Livre blanc Ethereum, expliqué. Partie 2

Ethereum a été construit autour d'un objectif central: la création d'un protocole permettant de créer diverses applications décentralisées avec de nombreux cas d'utilisation.

Ils fournissent un langage de programmation complet Turing où le temps de développement, la sécurité et l’interaction entre les applications (applications décentralisées) sont importantes. Une blockchain complète et programmable Turing permet de développer une grande variété de contrats intelligents, beaucoup plus sophistiqués que ceux proposés par Bitcoin.

Philosophie

Ethereum est conçu sur les cinq principes suivants.

Simplicité

Ethereum est construit comme un protocole simple et a la vision d’être ouvert à tous, même au

coût de stockage des données et manque de temps. Tout programmeur moyen devrait pouvoir choisir le

flux de travail et à mettre en œuvre des projets avec facilité. Cela aide à réaliser pleinement le projet sans précédent

potentiel de Blockchain et Cryptocurrency.

Universalité

La complétude Turing d’Ethereum aide à la création de tout contrat intelligent pouvant être

défini mathématiquement. Monnaie, dérivés financiers ou votre propre Skynet, tout peut être construit. Toutefois, si vous envisagez de créer Skynet, vous devrez peut-être disposer de plusieurs contrats imbriqués et les alimenter avec suffisamment de gaz pour que le contrat intelligent soit exécuté.

La modularité

Ethereum est conçu de manière à ce que toutes les parties du protocole puissent être séparées en unités individuelles. Même si quelqu'un modifie un protocole à un endroit donné, les autres parties de la pile d'applications ne seraient apparemment pas affectées et continueraient à fonctionner sans autre modification.

Des innovations telles qu'Ethash, les arbres de Patricia modifiés et RLP (dont il sera question dans les prochains articles) sont mises en œuvre sous forme de bibliothèques complètes et distinctes. Le développement d'Ethereum est fait de manière à profiter à l'ensemble du système de crypto-monnaie plutôt qu'à lui-même.

Agilité

Les constructions du protocole Ethereum ne sont pas figées dans la pierre, bien que les modifications des constructions de haut niveau ne soient effectuées que de manière judicieuse.

Non-discrimination et non-censure

En tant que véritable ouvert à tous les protocoles, Ethereum permet de développer tout type d’applications. Les mécanismes de réglementation utilisés dans Ethereum sont utilisés pour limiter et limiter les dommages causés à l'écosystème plutôt que pour restreindre une catégorie spécifique d'applications.

Par exemple, vous pouvez exécuter un script de boucle infinie à condition de payer les frais nécessaires et pertinents aux mineurs pour l’exécution de votre code.

Comptes Ethereum

Dans Ethereum, l'état est constitué d'objets appelés «comptes», chaque compte ayant une adresse publique de 20 octets. Les transitions d'état sont des transferts de valeur et d'informations entre deux comptes ou plus. Un compte Ethereum contient les quatre champs suivants.

  • Nonce; c'est un compteur qui assure que chaque transaction ne peut être traitée qu'une seule fois
  • Solde Ether actuel du compte
  • Le code de contrat du compte (le cas échéant, applicable aux contrats intelligents)
  • Stockage du compte (vide par défaut)

L'éther est le principal carburant utilisé dans Ethereum et est utilisé pour les frais de transaction également connus sous le nom de Gwei.

Il existe deux types de comptes à savoir:

  1. Comptes appartenant à l'extérieur; contrôlé par des clés privées: ne pas avoir de code inhérent. Les messages sont envoyés en créant et en signant une transaction.
  2. Comptes contractuels; contrôlé par code contrat: le code s'active en fonction du contenu du message reçu. Il est également possible d'activer d'autres processus, tels que la lecture et l'écriture dans la mémoire interne, l'envoi d'autres messages ou la création de contrats.

Le deuxième type de compte est utilisé par un exchage de crypto-monnaie: le Blockchain Board of Derivatives dans son système de portefeuille intelligent sans portefeuille.

Les contrats intelligents sont donc des agents autonomes qui résident dans l'environnement Ethereum et exécutent le code lorsqu'ils sont transmis par une transaction ou un message. Ces contrats ont un contrôle direct sur leur solde d’éther et sur leur propre magasin de clés.

Transactions

La transaction dans Ethereum est essentiellement un paquet de données signé et crypté qui stocke un message à envoyer à partir d'un compte appartenant à l'extérieur.

Les transactions typiques contiennent les éléments suivants:

  • Le destinataire du message (clé publique du destinataire)
  • Signature identifiant l'expéditeur (clé privée de l'expéditeur)
  • La quantité d'éther à transférer de l'expéditeur au destinataire
  • Un champ de données optionnel
  • Une valeur STARTGAS, représentant le nombre maximal d'étapes de calcul que l'exécution de la transaction est autorisée à effectuer.
  • Une valeur GASPRICE, représentant les frais payés par l'expéditeur par étape de calcul

Décomposons ces points individuels. Les trois premiers sont des champs standard présents dans chaque crypto-monnaie. Le champ de données n'a pas de fonction par défaut mais peut être utilisé par un contrat pour accéder aux données. Par exemple, si un contrat fonctionne comme un service d’enregistrement de domaine, il peut alors souhaiter interpréter les données qui lui sont transmises comme contenant deux «champs», le premier champ étant un domaine à enregistrer et le second champ étant l’adresse IP à traiter. enregistrer le domaine à. Le contrat lirait ces valeurs à partir des données du message et les stockerait de manière appropriée.

Les champs STARTGAS et GASPRICE sont essentiels pour le modèle d’anti-déni de service d’Ethereum. Afin d'éviter toute boucle infinie ou tout autre gaspillage de calcul, chaque transaction doit définir un nombre maximal d'étapes de calcul pouvant être utilisées. L'unité fondamentale de calcul est le «gaz». Généralement, une étape de calcul coûte 1 gaz, mais certaines opérations coûtent des quantités de gaz plus élevées car elles sont plus coûteuses en calcul ou augmentent la quantité de données à stocker dans le cadre de l'état.

Il y a une taxe de 5 essence pour chaque octet dans les données de transaction. Le système de frais amène un attaquant à payer proportionnellement pour chaque ressource qu'il consomme, y compris le calcul, la bande passante et le stockage. Par conséquent, toute transaction entraînant une consommation élevée du réseau entraîne naturellement une augmentation de la taxe sur l'essence.

En termes simples, le gaz payé est directement proportionnel au nombre et à la complexité des calculs effectués sur la blockchain.

messages

Les contrats peuvent envoyer des messages à d'autres contrats.

Les messages typiques contiennent:

  • L'expéditeur du message
  • Le destinataire du message
  • La quantité d'éther à transférer avec le message
  • Un champ de données optionnel
  • Une valeur STARTGAS

Un message est similaire à une transaction, sauf que les messages sont créés par un contrat et non par des comptes appartenant à l'extérieur. Un message est produit lorsqu'un code d'exécution de contrat exécute l'opcode CALL, produisant et exécutant un message.

Le message est reçu par le compte du destinataire qui exécute ensuite son code. De cette manière, les contrats peuvent être mis en vigueur dans des relations avec d’autres contrats d’une manière similaire aux comptes détenus en externe.

L'allocation de gaz attribuée par contrat s'applique à la fois au gaz consommé par transaction et à toutes les sous-exécutions.

Laissez-nous comprendre la même chose avec un exemple.

@A est un compte appartenant à l'extérieur

@B est un contrat

@A envoie à @B une transaction avec 1000 gaz.

@B consomme 600 gaz et envoie un message à @C.

L'exécution interne de @C consomme 300 gaz.

1000–600–300 = 100

Cela implique que le contrat @B ne peut dépenser que 100 autres gaz en calcul / message / transaction avant de manquer de gaz.

Fonction de transition d'état Ethereum

Comme mentionné dans la partie 1 de la série, vous pouvez vous rappeler la fonction de transition d'état

APPLIQUER (S, TX) -> S ’

Les étapes suivantes sont extraites du livre blanc et sont assez explicites:

  1. La transaction doit avoir le bon nombre de valeurs, la signature doit être valide et le nonce doit correspondre au nonce du compte de l'expéditeur. Si ce n'est pas conforme, jetez une erreur.
  2. Les frais de transaction sont calculés sous la forme STARTGAS * GASPRICE, l'adresse d'envoi pouvant être déterminée à partir de la signature. Soustrayez les taxes du solde de l’expéditeur et augmentez son coût. S'il n'y a pas assez d'équilibre à dépenser, jetez une erreur.
  3. Initialisez GAS = STARTGAS et une certaine quantité de gaz par octet est prélevée pour payer les octets de la transaction.
  4. Transférez la valeur de transaction du compte de l’expéditeur vers le compte de destination. Si le compte destinataire n'existe pas encore, créez-le. Si le compte destinataire est un contrat, exécutez le code du contrat soit à l’achèvement, soit jusqu’à épuisement du gaz.
  5. Si le transfert de valeur a échoué parce que l’expéditeur n’avait pas assez d’argent ou si l’exécution du code était à court de gaz, annulez tous les changements d’État, à l’exception du paiement des frais, et ajoutez-les au compte du mineur. Le paiement des frais ne peut pas être annulé car le mineur dépense de l'énergie pour faciliter la transaction.
  6. Sinon, rembourser les frais pour tout le gaz restant à l'expéditeur et envoyer les frais payés pour le gaz consommé au mineur.

Supposons que le code du contrat soit le suivant:

if! self.storage [calldataload (0)]:
self.storage [calldataload (0)] = calldataload (32)

Le contrat est en réalité écrit en code EVM de bas niveau, mais l'exemple ci-dessus est écrit en Serpent.

Considérons maintenant un exemple:

La mémoire du contrat est initialement vide et une transaction est envoyée avec une valeur de 10 ether, 2000 gas, un prix de 0,001 ether et 64 octets de données, les octets 0 à 31 représentant le nombre 2 et les octets 32 à 63 portant la chaîne CHARLIE.

Le processus de la fonction de transition d'état dans ce scénario est le suivant. Ces étapes sont similaires à celles mentionnées dans l'exemple générique ci-dessus.

  1. Vérifiez que la transaction est valide et bien formée.
  2. Vérifiez que l'expéditeur de la transaction a au moins 2 000 * 0,001 = 2 ether. Si tel est le cas, soustrayez 2 éther du compte de l’expéditeur. (Puisque nous devons utiliser STARTGAS * GASPRICE comme formule)
  3. Initialiser gaz = 2000; en supposant que la transaction a une longueur de 170 octets et que le montant en octets est de 5, soustrayez 850 (170 * 5), de sorte qu'il reste 1150 (2000–850) de gaz.
  4. Soustrayez 10 autres éther du compte de l’expéditeur et ajoutez-le au compte du contrat.
  5. Exécutez le code. Dans ce cas, c’est simple: il vérifie si le stockage du contrat à l’index 2 est utilisé, s’aperçoit que ce n’est pas le cas et définit donc le stockage à l’index 2 sur la valeur CHARLIE. Supposons que cela prenne 187 gaz, la quantité restante de gaz est donc 1150–187 = 963
  6. Ajoutez 963 * 0.001 = 0.963 dans le compte de l’expéditeur et renvoyez l’état résultant.

Ceci conclut les étapes qui sont entreprises dans tout le processus.

En l'absence de contrat à la réception de la transaction, le total des frais de transaction serait simplement égal au GASPRICE fourni multiplié par la longueur de la transaction en octets, et les données envoyées parallèlement à la transaction ne seraient pas pertinentes.

Dans ce cas, tout le gaz serait utilisé par un mineur pour ne fournir aucun résultat, aucun contrat n’existant.

Les messages et les transactions fonctionnent de la même manière quand il s’agit de revenir: si une exécution de message est à court de carburant, son exécution et toutes les autres exécutions déclenchées par cette exécution reviennent, mais les exécutions parent n’ont pas besoin de revenir.

Cela implique qu’il est «sûr» pour un contrat d’appeler un autre contrat comme si A appelait B avec G gaz, alors l’exécution de A était garantie de perdre au plus G gaz. Cependant, les exécutions parentes hors contrat ne sont pas restaurées

En outre, il existe un code d'opération, CREATE, qui crée un contrat. Ses mécanismes d’exécution sont généralement similaires à CALL, à la différence près que la sortie de l’exécution détermine le code d’un contrat nouvellement créé.

Nous étudierons l'opcode plus en détail dans nos prochains articles techniques approfondis sur le blog.

Exécution de code

Le code dans les contrats Ethereum est écrit dans un langage de bas niveau de type bytecode basé sur une pile, appelé «code de la machine virtuelle Ethereum» ou «code EVM». Le code EVM est essentiellement une série d'octets et chaque octet est une opération.

«L’exécution du code est une boucle infinie qui consiste à exécuter de manière répétée l’opération sur le compteur de programme en cours (qui commence à zéro), puis à incrémenter le compteur de programme de un, jusqu’à ce que la fin du code soit atteinte ou qu’une erreur soit commise, STOP ou RETURN. l'instruction est détectée. "

Les opérations ont accès à trois types d’espace dans lesquels stocker des données:

  1. Stack, un conteneur dernier entré, premier sorti dans lequel les valeurs peuvent être poussées et affichées comme une pile typique.
  2. Memory, un tableau d'octets infiniment extensible.
  3. Stockage, un magasin clé / valeur. Contrairement à la pile et à la mémoire, qui sont réinitialisées à la fin du calcul, le stockage persiste à long terme.

Le code a également la capacité d'accéder à la valeur, à l'expéditeur, aux données du message entrant et à l'en-tête de bloc. Le code peut également renvoyer un tableau d'octets de données en sortie.

Le modèle d'exécution du code EVM est assez simple. Nous l'explorerons plus avant dans les étapes ci-dessous.

Pendant que la machine virtuelle Ethereum est en cours d'exécution, son état de calcul complet peut être défini par le tuple. Un tuple est composé de block_state, transaction, message, code, mémoire, pile, pc et gas.

Ici, block_state est l'état global contenant tous les comptes et inclut les soldes et le stockage.

Au début de chaque tour d'exécution, l'instruction en cours est trouvée en prenant le pc-ème octet de code (ou 0 si pc> = len (code)), ce qui signifie que pc est considéré comme égal à zéro lorsqu'il est supérieur ou égal à à la longueur du code.

Chaque instruction a sa propre définition sur la façon dont elle affecterait le tuple.

ADD supprime deux éléments de la pile, pousse leur somme, réduit le gaz de 1 et incrémente l'ordinateur de 1 (travail typique d'une pile)

SSTORE extrait les deux principaux éléments de la pile et insère le deuxième élément dans la mémoire du contrat à l’index spécifié par le premier.

Il existe de nombreuses manières d’optimiser l’exécution de EVM via une compilation juste à temps. Une implémentation de base d’Ethereum peut être réalisée en quelques centaines de lignes de code.

Blockchain et l'exploitation minière

Ethereum blockchain est plus ou moins similaire à la Bitcoin blockchain avec quelques différences subtiles.

La principale différence entre Ethereum et Bitcoin en ce qui concerne l'architecture blockchain est que, contrairement à Bitcoin (qui ne contient qu'une copie de la liste de transactions), les blocs Ethereum contiennent une copie de la liste de transactions, l'état le plus récent, le numéro de bloc et le difficulté.

L'algorithme de validation de bloc de base dans Ethereum peut être expliqué dans les étapes suivantes:

  1. Vérifiez si le bloc précédent référencé existe et est valide.
  2. Vérifiez que l'horodatage du bloc est supérieur à celui du bloc précédent référencé et inférieur à 15 minutes dans le futur.
  3. Vérifiez que le numéro de bloc, la difficulté, la racine de la transaction, la racine de l'oncle et la limite de gaz (divers concepts de bas niveau spécifiques à Ethereum qui seront abordés plus tard) sont valides.
  4. Vérifiez que la preuve de travail sur le bloc est valide.
  5. Soit S [0] l’état à la fin du bloc précédent. (rappelez-vous que ceci est discuté et expliqué dans le post précédent du blog)
  6. Soit TX la liste des transactions du bloc, avec n transactions. Pour tout i dans 0… n-1, définissez S [i + 1] = APPLIQUER (S [i], TX [i]). Si une application renvoie une erreur ou si la quantité totale de gaz consommée dans le bloc jusqu'à ce point dépasse le GASLIMIT, renvoyez une erreur.
  7. Soit S [FIN] S [n], mais en ajoutant la récompense de bloc payée au mineur (S_FINAL = S [n] + récompense de bloc). La récompense est attribuée une fois qu'un mineur termine l'extraction d'un bloc avec succès.
  8. Vérifiez si la racine de l'arbre à distorsion de l'état S_FINAL est égale à la racine de l'état final fournie dans l'en-tête de bloc. Si c'est le cas, le bloc est valide. sinon, ce n'est pas valide. (L'arbre Merkle et la validation avec l'en-tête de bloc sont expliqués avec des images pertinentes dans le précédent article de blog)

L'approche consistant à stocker l'état entier dans chaque bloc peut sembler inefficace au début, mais elle est comparable à celle de Bitcoin.

L'état est stocké dans l'arborescence et après chaque bloc, seule une infime partie de l'arborescence doit être modifiée. Cela implique qu'entre deux blocs adjacents, la grande majorité de l'arbre doit être identique. Les données peuvent être stockées une fois et référencées deux fois à l'aide de pointeurs (hachages de sous-arbres).

Un type spécial d'arborescence appelé «arbre Patricia» est utilisé à cet effet, notamment une modification du concept d'arborescence Merkle qui permet d'insérer et de supprimer les nœuds de manière efficace.

De plus, étant donné que toutes les informations d'état font partie du dernier bloc, il n'est pas nécessaire de stocker l'historique complet de la chaîne de blocs.

Une question fréquemment posée est «où» le code de contrat est exécuté, en termes de matériel physique.

Le processus d'exécution du code de contrat est défini dans la fonction de transition d'état elle-même, qui fait partie de l'algorithme de validation de bloc. Si une transaction est ajoutée au bloc B, l'exécution du code généré par cette transaction sera exécutée par tous les nœuds chargés de télécharger et de valider le bloc B, maintenant ou à l'avenir.

Ceci marque la fin de la partie 2 du livre blanc Ethereum. Dans la prochaine partie, nous discuterons des applications en temps réel du protocole Ethereum et de l'écosystème.