Comment construire un DApp sur des nébuleuses (partie 2)

Nous avons publié plusieurs bibliothèques pour faciliter la rédaction de contrats intelligents. Cela signifie que vous n'avez pas besoin de créer explicitement ces contrats intelligents à partir de zéro, car nous avons déjà effectué le travail initial à votre place.

Dans la deuxième partie de ‘Comment construire DApp sur Nebulas’, nous allons en apprendre davantage sur ces bibliothèques, sur ce qu’elles font et sur la façon de les utiliser.

BigNumber

Le module BigNumber utilise bignumber.js, une bibliothèque JavaScript pour les arithmétiques décimales et non décimales à précision arbitraire. Le contrat peut utiliser BigNumber directement pour gérer la valeur de la transaction et d’autres transferts de valeur.

valeur var = nouveau BigNumber (0);
valeur.plus (1);
...

Espace de rangement

Le module de stockage permet le stockage de données sur des nébuleuses. Plus précisément, il permet le stockage permanent des variables d’état sur Nebulas lorsqu’un paiement est effectué, c’est-à-dire un GAZ, semblable à un système de stockage clé-valeur traditionnel. L'objet LocalContractStorage est l'objet de stockage intégré à Nebulas que vous pouvez utiliser et accepter les nombres, les chaînes et les objets JavaScript au format de chaîne. Seul le contrat qui stocke ces données peut y accéder et les manipuler.

Les bases

LocalContractStorage prend en charge trois opérations, à savoir, set, get et del, qui vous permettent de stocker, de lire et de supprimer des données:

"use strict";
var BankVaultContract = function () {
    // rien
};
BankVaultContract.prototype = {
    init: function () {
        // rien
    },
    set: function (nom, valeur) {// nom = "robin", valeur = 10000
        LocalContractStorage.set ("nom", nom);
        // 'put' est une opération équivalente à 'set'
        LocalContractStorage.put ("valeur", valeur);
    },
    get: function () {
        var name = LocalContractStorage.get ("nom");
        console.log (nom); // affiche 'robin'
        var value = LocalContractStorage.get ("valeur");
        console.log (valeur); // affiche '10000'
    },
    del: function () {
        var result = LocalContractStorage.del ("nom");
        console.log (résultat); // affiche 'robin'
        // 'delete' est une opération équivalente à 'del'
        resultat = LocalContractStorage.delete ("valeur");
        console.log (résultat); // affiche '10000'
    
        // après suppression, les données ne peuvent plus être lues
    }
};
module.exports = BankVaultContract;

Avancée

En plus des utilisations de base ci-dessus, LocalContractStorage prend également en charge la définition des propriétés de stockage et le stockage de mappes sur des objets, ainsi que des méthodes de sérialisation.

  • Propriétés de stockage

Une propriété de contrat peut être liée à une propriété de stockage, où la lecture et l'écriture du contrat sont effectuées sur LocalContractStorage. Il existe deux méthodes pour définir une telle liaison:

// lie une propriété d'objet nommée `nomChamp` à` obj` avec un descripteur.
// le descripteur par défaut est JSON.parse () / JSON.stringify (). Que le descripteur soit 'nul' ou 'non défini', celui par défaut sera utilisé.
// retourne ceci.
defineProperty (obj, fieldName, [descriptor]);

// lie plusieurs propriétés à `obj` dans un lot.
// retourne ceci.
defineProperties (obj, {
    fieldName1: descriptor1,
    fieldName2: descriptor2
});

Habituellement, nous mappons les propriétés du contrat pour stocker les bits dans l'initialisation de la manière suivante:

"use strict";
var BankVaultContract = function () {
    // en raison de 'null', le descripteur par défaut sera utilisé.
    LocalContractStorage.defineProperty (this, "name1", null);
    
    // une implémentation `descripteur` personnalisée.
    // retourne l'objet BigNumber lors de l'analyse.
    LocalContractStorage.defineProperty (this, "value1", {
        stringify: fonction (obj) {
            retourne obj.toString ();
        },
        parse: function (str) {
            renvoyer new BigNumber (str);
        }
    });
    
    // liaison par lots avec implémentation de sérialisation par défaut.
    LocalContractStorage.defineProperties (this, {
        name2: null,
        valeur2: null
    });
};
module.exports = BankVaultContract;

Après cela, vous pouvez lire et écrire les propriétés de liaison comme si vous accédez directement au stockage:

BankVaultContract.prototype = {
    init: fonction (nom, valeur) {// nom = "robin", valeur = 1
        this.name1 = name;
        this.value1 = valeur;
    },
    testStorage: fonction (nom, valeur) {// nom = "ROBIN", valeur = 2
        this.name2 = nom;
        this.value2 = valeur;
        
        bool r = this.value1.lessThan (new BigNumber (0));
        console.log (this.name1 + ":" + r); // robin: false
        console.log (this.name2 + ":" + this.value2); // ROBIN: 2
    }
};
  • Stockage des données cartographiques

Le stockage Nebula implémente une structure de carte avec des opérateurs del / delete, get, set / put pour certains scénarios dans lesquels vous devez stocker des données clé-valeur. Pour ce faire, vous pouvez définir la propriété du contrat en tant que carte. Encore une fois, il existe deux méthodes pour le faire:

// liaison unique, la mise en œuvre du descripteur par défaut est identique à defineProperty.
// retourne ceci.
defineMapProperty (obj, mapName, [descriptor]);

// liaison par lots.
// retourne ceci.
defineMapProperties (obj, {
    mapName1: descriptor1,
    mapName2: descriptor2
});

Permet de voir un exemple d'utilisation des cartes:

'use strict';

var BankVaultContract = function () {
    LocalContractStorage.defineMapProperty (this, "userMap");
    
    LocalContractStorage.defineMapProperty (this, "userBalanceMap", {
        stringify: fonction (obj) {
            retourne obj.toString ();
        },
        parse: function (str) {
            renvoyer new BigNumber (str);
        }
    });
    
    LocalContractStorage.defineMapProperties (this, {
        key1Map: null,
        key2Map: null
    });
};

BankVaultContract.prototype = {
    init: function () {
    },
    testStorage: function () {
        this.userMap.set ("robin", "1");
        this.userBalanceMap.set ("robin", nouveau BigNumber (1));
    },
    testRead: function () {
        // Lire et stocker des données
        var balance = this.userBalanceMap.get ("robin");
        this.key1Map.set ("robin", balance.toString ());
        this.key2Map.set ("robin", balance.toString ());
    }
};

module.exports = BankVaultContract;

Blockchain

Le module Blockchain est utilisé pour obtenir la transaction et le blocage dans le contrat en cours d'exécution. De plus, le NAS peut être transféré du contrat et la vérification de l'adresse est fournie.

La blockchain a deux propriétés:

  1. bloquer le bloc actuel pour l'exécution du contrat avec les attributs:

- timestamp block timestamp

- hash block hash

- hauteur du bloc

2. transaction en cours transaction pour l'exécution du contrat avec attributs:

- hash transaction hash

- de transaction à partir de l'adresse

- à la transaction pour adresser

- valeur de transaction, un objet BigNumber à utiliser par contrat

- nonce transaction nonce

- horodatage de la transaction

- transaction gasPrice gasPrice, un objet BigNumber à usage contractuel

- transaction gasLimit gasLimit, un objet BigNumber à usage contractuel

Et Blockchain fournit deux méthodes:

  1. transfer (adresse, valeur) transfère NAS du contrat à l'adresse.
  • adresse param: adresse des nébuleuses pour recevoir le NAS
  • param value: valeur transférée, un objet BigNumber

return: 0-transfer success, 1-transfer a échoué.

2. verifyAddress (address) vérifie si l'adresse du paramètre est une adresse Nebula valide.

return: 1-address est valide, 0-address est invalide.

Voici un exemple simple de ce module mis en œuvre:

'use strict';

var BankVaultContract = function () {};

BankVaultContract.prototype = {
    init: function () {
        console.log ('init: Blockchain.block.height =' + Blockchain.block.height);
        console.log ('init: Blockchain.transaction.from =' + Blockchain.transaction.from);
    },
    
    transfert: fonction (adresse, valeur) {
        var result = Blockchain.transfer (adresse, valeur);
        console.log ("résultat du transfert:", résultat);
    },
    
    verifyAddress: fonction (adresse) {
    var result = Blockchain.verifyAddress (adresse);
        console.log ("verifyAddress result:", result);
    }
};

module.exports = BankVaultContract;

un événement

Le module Event permet d’enregistrer les événements d’exécution dans le contrat. Les événements enregistrés sont stockés dans l'événement trie de la chaîne, qui peut être récupéré par rpc.getEventsByHash avec le hachage de la transaction d'exécution. Tous les sujets d'événement de contrat ont un chain.contract. préfixe avec des sujets définis par l'utilisateur. L'utilisation est:

Event.Trigger (topic, obj);
  • sujet: sujet défini par l'utilisateur
  • obj: objet JSON

Voici l'échantillon:

'use strict';

var BankVaultContract = function () {};

BankVaultContract.prototype = {
    init: function () {},
testEvent: function () {
        // le sujet stocké est en réalité "chain.contract.topic"
        Event.Trigger ("topic", {
Les données: {
valeur: "Test d'événement."
}
        });
    }
};

module.exports = BankVaultContract;

Console

Le module de console fournit une console de débogage simple, similaire au mécanisme de console JavaScript fourni par les navigateurs Web. La console imprimera tous les arguments reçus sur le consignateur Nebulas à un niveau spécifique associé au nom de la méthode invoquée.

  • console.log ([… args ]) - - niveau d'information
  • console.debug ([… args ]) - - niveau de débogage
  • console.warn ([… args ]) - - avertir le niveau
  • console.error ([… args ]) - - niveau d'erreur
  • console.info ([… args ]) - - alias pour console.log ()

Nous avons maintenant terminé de parler des principaux modules de fonctionnalités. Ensuite, nous examinerons les fonctions de contrat d’appel.

Comment appeler un contrat?

L'approche recommandée consiste à rejoindre le réseau principal ou le réseau de test de Nebulas en lançant un nœud local. Voici un guide de démarrage rapide sur la façon de le faire.

Une fois le nœud démarré, vous devez d'abord déverrouiller votre propre compte avec unlockAccount () avant d'appeler une fonction du contrat:

// Demande
curl -i -H 'Content-Type: application / json' -X POST http: // localhost: 8685 / v1 / admin / compte / déverrouillé -d '{"adresse": "n1czGUvbQQton6KUWga4wKDLLKYDEn39mEk", "passphrase", "passphrase" "," duration ":" 1000000000 "} '

// Résultat
{
    "résultat":{
        "result": true
    }
}

Vous pouvez ensuite utiliser la méthode sendTransaction () pour appeler le contrat intelligent.

Par exemple, appelez testEvent () dans le modèle de contrat précédent:

// Demande
curl -i -H 'Accepter: application / json' -X POST http: // localhost: 8685 / v1 / admin / transaction -H 'Type de contenu: application / json' -d '{"de": "n1NZttPdrJCwHgFN3V6YnSDaD5g8UbVppoC" , "à": "n1qsgj2C5zmYzS9TSkPTnp15bhCCocRPwno", "valeur": "100", "nonce": 8, "gasPrice": "1000000", "gasLimit": "2000000", "contrat": {"fonction": "" fonction ":" fonction ":" "," args ":" [] "}} '

// Résultat
{
"résultat": {"txhash": "b55358c2e12c1d48d4e6beaee7002a59138294fb2896ea8059ff5277553af59f", "adresse_contrat": ""}
}

Pour plus d'informations sur le manuel RPC, voir l'API utilisateur et l'API admin.

Que ce passe t-il après?

Dans le prochain article, nous allons partager une nouvelle fonctionnalité de smart contract, à savoir la fonction "Accepter".