Plasma Cash Chain comme solution au trilemme d'évolutivité de la blockchain

Bonjour, chers lecteurs!

Cet article concerne la chaîne de paiement au plasma et met en lumière les sujets suivants:

  • le trilemme d'évolutivité et les méthodes de sa solution;
  • les structures de données de la chaîne enfant et leur affichage dans la chaîne racine;
  • mise en œuvre de l'apport à la chaîne racine;
  • mise en œuvre du retrait de la chaîne racinaire.

Opporty a utilisé le langage de programmation Javascript pour implémenter la chaîne enfant, ainsi que Solidity pour la chaîne racine. Des exemples de code sont fournis dans ces langues.



La blockchain et la décentralisation permettent d'optimiser et d'améliorer le travail de presque tous les domaines de la vie où Internet et les technologies de l'information sont utilisés. Ils augmentent la fiabilité, l'efficacité financière et facilitent également la numérisation des biens et des biens réels.

Les contrats intelligents apportent une logique métier aux réseaux décentralisés. Cela vous permet de créer de nouvelles applications DAPP.

L'exécution de contrats intelligents et le fonctionnement rapide d'applications avec une base de données distribuée ne peuvent être possibles que si la condition d'évolutivité est remplie.

Les blockchains décentralisées modernes présentent plusieurs inconvénients. Le principal est l'évolutivité. Ethereum traite environ 20 tx / s. Cela ne suffit pas dans les réalités financières modernes. Dans le même temps, Ethereum offre le plus haut degré de protection possible contre le piratage et les pannes de réseau. D'autres crypto-monnaies et systèmes construits sur la blockchain n'ont pas un degré de décentralisation aussi élevé, ce qui réduit la confiance dans le réseau.

Le trilemme d'évolutivité


Il existe un trilemme d'évolutivité de la blockchain qui comprend trois composants:

  • décentralisation;
  • la sécurité
  • évolutivité.

La décentralisation dans le trilemme


La décentralisation, comme son nom l'indique, reflète le degré de diversification de la propriété de l'activité dans la blockchain, ainsi que le degré de diversification de la création de blocs et de la génération de nouvelles écritures.

Pour plus de clarté, il est nécessaire de parler des organisations les plus centralisées. Habituellement, une simple base de données est utilisée à la place de la blockchain. Une telle organisation est dirigée par des administrateurs spéciaux. Toutes les transactions peuvent être annulées par intervention manuelle.

Dans les réseaux entièrement décentralisés, chaque utilisateur peut participer à la construction d'un réseau.

La conséquence la plus importante de la décentralisation est que la plus grande partie de la valeur va à la communauté impliquée dans la création de la blockchain. Il n'y a pas d'équipe intermédiaire de gestionnaires qui reçoivent tous les avantages au lieu de ceux qui génèrent la structure du réseau elle-même. En fait, la plupart des projets de cryptographie appartiennent entièrement à leurs contributeurs ou utilisateurs, et non aux fondateurs. C'est évidemment un modèle plus attractif pour ceux qui ne sont pas fondateurs.

La sécurité dans le trilemme


Il s'agit de la capacité de la blockchain à résister aux attaques de sources externes et à garder le système dans un état inchangé. La plupart des chaînes de blocs sont soumises à de nombreuses menaces de sécurité potentielles. Il est impératif de connaître les vecteurs d'attaque et les options de défense les plus courants.

Dans ce cas, décentralisation et sécurité vont de pair. Plus il y a de nœuds, moins le réseau dépend du côté centralisé et donc du risque d'avoir un point de défaillance central. Cependant, de nombreux autres vecteurs d'attaque constituent une menace pour les réseaux décentralisés, notamment:
> 50% d'attaque - un objet qui possède plus de 50% du nombre total de jetons non payés possède réellement le réseau;
> Sybil Attack - l'utilisateur peut générer de nombreux identifiants dans le système pour contrôler efficacement une part importante de la propriété et / ou de la prise de décision sur le réseau;
> DDoS - une attaque par déni de service distribué (DDoS) se produit lorsqu'il existe une intention de perturber le trafic sur le réseau, remplissant le réseau de transactions malveillantes;
> Attaque de collusion - un ou plusieurs objets (ou nœuds) décident de s'unir pour effectuer toute opération malveillante sur le réseau.

Évolutivité dans le trilemme


Le degré d'évolutivité est important car il détermine le débit ultime, en d'autres termes, la limite supérieure de la taille du réseau. La question la plus importante à poser lors de l'évaluation d'un réseau est: «Combien d'utilisateurs ce système peut-il supporter?» Bitcoin compte actuellement entre 2,9 et 5,8 millions de détenteurs de portefeuille. EOS compte plusieurs milliers de membres.

L'évolutivité et la décentralisation peuvent coexister, mais la sécurité est réduite. Les développeurs choisissent les plateformes qui répondent le mieux à leurs besoins. Les utilisateurs font de même. Les opinions des deux côtés diffèrent parfois. Certains utilisateurs sont prêts à sacrifier la sécurité pour l'évolutivité, d'autres sont prêts à sacrifier l'évolutivité pour la sécurité, mais l'équilibrage est beaucoup plus difficile.

«Holy Graal» dans la technologie de la blockchain


Par définition, une blockchain n'a que deux des trois propriétés suivantes:

  • Décentralisation (chaque participant n'a accès qu'aux ressources d'O ©, c'est-à-dire à un ordinateur portable ordinaire ou à un petit VPS);
  • Évolutivité (capacité à traiter les transactions O (n)> O ©);
  • Sécurité (protection contre les intrus utilisant des ressources O (n)).


Vert: Un état équilibré de trois conditions.
Rouge: forte sécurité mais décentralisation et évolutivité limitées.
Bleu: l'efficacité est élevée, mais la sécurité et la décentralisation sont limitées.
Noir: la décentralisation est élevée, mais il n'y a aucun aspect d'évolutivité et de sécurité.
Gris: décentralisation complète, avec des qualités de sécurité et d'évolutivité minimales ou manquantes.
Violet: un équilibre égal entre sécurité et évolutivité, le rejet de la décentralisation.

Le «Saint-Graal» dans la technologie de la blockchain signifie combiner les trois aspects.
Dans la plupart des projets actuels utilisant des crypto-monnaies, deux propriétés de base sont atteintes: la décentralisation et la sécurité. L'évolutivité en souffre.

Des solutions prometteuses au trilemme


Preuve de participation (PoS)


Proof of Stake (PoS) offre des améliorations d'évolutivité potentielles. POS remplace l'extraction de crypto-monnaie basée sur le système Proof of Work (PoW). Le choix du validateur est très rapide - de manière déterministe. En même temps, il n'y a pas de coût énergétique et il est respectueux de l'environnement.

Sidechains


Dans le réseau virtuel Ethereum, il est possible de créer un réseau secondaire dans lequel le projet peut traiter ses transactions individuelles, puis enregistrer uniquement les résultats initiaux et finaux dans le réseau Ethereum. Cela réduit la charge sur l'EVM, mais donne plus de confiance dans la gestion de la chaîne latérale. Ainsi, la confiance en un tiers réduit la décentralisation.

Partage


Le sharding divise les transactions en plus petites données. Au lieu que chaque nœud individuel du réseau traite des transactions entières, les nœuds sont divisés en groupes et ces groupes de nœuds traitent certains éléments de données. Plus tard, lors du traitement, ces données sont réassimilées pour un stockage permanent sur la blockchain.

Augmentez la taille du bloc


Litecoin et Bitcoin Cash (BCH) sont des «fourchettes» pour la blockchain Bitcoin. Forker copie essentiellement une blockchain. Après le branchement, vous pouvez apporter des modifications. LTC et BCH ont augmenté la taille de chaque bloc, ce qui a permis de stocker plus de transactions par bloc, augmentant ainsi la vitesse de traitement des transactions.

Réseau Lightning


La toute première solution de chaîne latérale était la foudre. L'idée principale du Lightning Network est que toutes les transactions ne doivent pas être enregistrées dans la blockchain, car cela surcharge le réseau. Si les utilisateurs se transfèrent des fonds plusieurs fois, l'enregistrement de chaque transfert est facultatif. Il suffit d'ouvrir une sorte de canal de paiement et d'écrire les données de son ouverture sur la blockchain. Ce canal restera ouvert au besoin. Lorsqu'il sera nécessaire de le fermer, le résultat de toutes les transactions effectuées dans ce canal est simplement écrit dans la blockchain. En suivant cette idée, vous pouvez créer tout un réseau de canaux de paiement. Ensuite, les transactions sur la blockchain seront utilisées beaucoup moins fréquemment.

Un canal de paiement n'est qu'une combinaison de plusieurs transactions. Un canal peut être fermé par n'importe lequel de ses membres. Cette action sera comme ouvrir un coffre-fort, ce qui vous permet de prendre les fonds appartenant aux participants et de noter les données de leur transfert vers la blockchain.
Cette technologie devient vraiment puissante lorsque plusieurs de ces canaux sont combinés en un réseau appelé The Lightning Network. Ce réseau est spécialement conçu pour Bitcoin.

Réseau Raiden


Pour Ethereum, l'homologue le plus connu de Lightning est le réseau Raiden.
C'est une solution pour évoluer en dehors de la blockchain principale. Il est compatible avec le transfert de jetons ERC-20 dans les canaux de paiement bidirectionnels.

Son architecture de base est complexe, mais l'interaction avec Raiden nécessite que les développeurs n'interagissent qu'avec l'API pour créer des applications évolutives sur Raiden.

Raiden est conçu pour fournir des paiements instantanés et de faibles commissions, augmenter la confidentialité des transactions et les micropaiements. La plupart des canaux de paiement existent en dehors du réseau et ne forment qu'occasionnellement des transactions au sein de la chaîne racine, ce qui réduit considérablement le débit de la chaîne enfant.

Solution optimale


Les idéologues de la foudre ont créé un nouveau concept de chaîne d'enfant qui résout les problèmes de vitesse de la chaîne de blocs.

Opporty met pratiquement en œuvre le concept de Plasma et Plasma Cash.

Le plasma est un ensemble de contrats intelligents qui s'exécutent au sommet de la chaîne racine Ethereum et se composent d'un réseau de chaînes enfants connectées à la chaîne racine dans une structure arborescente hiérarchique.

En d'autres termes, la sécurité de la chaîne racine Ethereum est utilisée pour optimiser l'évolutivité.

Plasma Cash: Option Opporty


Opporty utilise l'implémentation de Plasma Cash dans la première version.

Ce modèle est l'implémentation plasma la plus efficace en termes d'évolutivité.
Plasma Cash est un système basé sur l'utilisation d'identifiants uniques pour chaque jeton de la chaîne Plasma. Autrement dit, le NFT est appliqué et les jetons du réseau reçoivent des numéros de série uniques.

Caractéristiques de Plasma Cash:

  • Validation fragmentée côté client - les clients ont juste besoin de surveiller leur chaîne Plasma pour obtenir leurs jetons. Cela signifie que le débit des transactions peut augmenter sans augmenter la charge des utilisateurs individuels.
  • Simplification des sorties de masse - les sorties de masse deviennent moins une menace pour le réseau, car le voleur doit soumettre une transaction de sortie pour chaque jeton qu'il veut voler.
  • Aucune confirmation bidirectionnelle - les transactions ne nécessitent plus l'envoi et la confirmation en deux étapes. Au lieu de cela, une transaction peut être dépensée dès qu'elle est incluse dans la chaîne principale.

Inconvénient:

Grandes coupures de jetons - étant donné que chaque jeton doit se voir attribuer un numéro de série, il est impossible de produire des jetons arbitrairement petits. Cela est dû au fait qu'à un moment donné, la valeur de l'achat du jeton sera supérieure à la valeur du jeton lui-même.

Structure des transactions dans Opporty Plasma Cash


Opporty a utilisé Javascript pour implémenter la chaîne d'enfant. Chaque transaction dans Opporty Plasma Cash est une structure similaire:

const transactionFields = [ {name: 'prevHash'}, {name: 'prevBlock', int: true, default: 0}, {name: 'tokenId', isDecimal: true}, {name: 'newOwner'}, {name: 'type'}, {name: 'signature'}, ] 

Les principaux éléments ici sont un lien vers le bloc précédent prevBlock (il est nécessaire de se déplacer dans la chaîne de blocs), l'identificateur de jeton tokenId (il doit être unique), ainsi que newOwner, le dernier propriétaire du jeton.

De plus, afin d'assembler le bloc et d'obtenir le hachage de la chaîne racine, un type spécial de l'arbre Patricia Merkle Trie est utilisé. Le même arbre est utilisé dans Ethereum. Il a un aspect compressé. Dans le même temps, vous pouvez toujours recevoir des preuves d'inclusion ou de non-inclusion d'une transaction dans un bloc.
La signature est une signature sur les courbes elliptiques.

Une transaction dépensant un jeton avec un tokenId donné n'est valide que si elle est incluse dans l'arborescence Merkle dans la position tokenId, c'est-à-dire que pour chaque jeton dans l'arborescence Merkle, il n'y a qu'un seul «endroit» dépensant ce jeton où les transactions sont autorisées. Ce format permet aux utilisateurs de vérifier l'historique complet de la chaîne Plasma, ainsi que de prouver et de réfuter la propriété de jetons spécifiques.

Afin de dépenser un jeton, vous devez valider la chaîne, vérifier qu'il n'y a pas de blocs manquants et ensuite re-signer la transaction avec tout l'historique.

Le bloc est le suivant:

 const blockFields = [ {name: 'prevHash'}, {name: 'blockNum', isDecimal: true}, {name: 'transactions'}, {name: 'merkleRoot'}, {name: 'time'} ] 

À un niveau de base, une blockchain est simplement une chaîne de blocs avec un lien vers le bloc précédent. Une telle structure permet d'obtenir la propriété d'immuabilité, c'est-à-dire de ne pas réécrire l'histoire. merkleRoot permet d'écrire des points de contrôle dans la chaîne racine.

Dans la chaîne racine, au niveau du contrat intelligent, cela ressemble à ceci (langage Solidity):

 /* * Block structure (represents one block in a chain) */ struct Block { uint block_num; bytes32 merkle_root; uint time; /* * Transaction structure (decoded from RLP form) */ struct Transaction { bytes32 prevhash; uint prev_block; uint token_id; address new_owner; } 

L'encodage est effectué à l'aide des fonctions d'encodage / décodage - sérialisation / désérialisation RLP.

Façons d'entrer Plasma Cash


N'importe qui peut déposer des fonds dans Plasma Cash simplement en transférant de l'éther dans un contrat intelligent. Par conséquent, un jeton OPP sera reçu à une position tokenId spécifique.

Voici l'implémentation dans Solidity:

 function deposit() public payable { uint token_id = uint(keccak256(msg.sender, msg.value, deposit_blk)); // token.index = deposit_blk; tokens[token_id] = msg.value; deposit_blk += 1; emit DepositAdded(msg.sender, msg.value, token_id, current_blk); } 

Autrement dit, tokenId est généré sous la forme d'un nombre aléatoire (hachage). Ensuite, un événement est généré qui est analysé dans la chaîne enfant.

Façons de se retirer sur Plasma Cash


Chaque personne peut retirer son jeton en fournissant les deux dernières transactions dans l'historique de propriété du jeton.

Mise en œuvre de la sortie de la chaîne racine:

 function startExit(uint block_num, bytes tx1, bytes tx0, bytes proof1, bytes proof0) public returns (uint exit_id) { require(checkPatriciaProof(keccak256(tx1), childChain[block_num].merkle_root, proof1)); bytes32 prev_hash; uint prev_blk; uint token_id; address new_owner; (prev_hash, prev_blk, token_id, new_owner,) = getTransactionFromRLP(tx1); require(msg.sender == new_owner); require(tokens[token_id] > 0); bytes32 hashPrevTx = keccak256(tx0); require(checkPatriciaProof(hashPrevTx, childChain[prev_blk].merkle_root, proof0)); require(prev_hash == hashPrevTx); Exit storage record = exitRecords[token_id]; require(record.block_num == 0); record.block_num = block_num; record.new_owner = msg.sender; record.prev_block = prev_blk; if (childChain[block_num].time > block.timestamp - week) record.priority = childChain[block_num].time; else record.priority = block.timestamp - week; exits.add(record.priority); exit_ids[record.priority].push(token_id); emit ExitAdded(msg.sender, record.priority, token_id); return token_id; } 

Tout d'abord, deux transactions sont vérifiées. Si l'utilisateur actuel est le propriétaire de la transaction, nous ajoutons simplement sa sortie à la structure et laissons deux semaines pour l'opportunité de contester la sortie.

La conclusion peut être contestée de trois manières:

  • Confirmation des dépenses sur les transactions:

 function challengeSpent(uint exit_id, uint blk_num, bytes tx1, bytes proof) public { require(checkPatriciaProof(keccak256(tx1), childChain[blk_num].merkle_root, proof)); Exit memory record = exitRecords[exit_id]; require(record.block_num > 0); uint prev_block; uint token_id; (, prev_block , token_id, ) = getTransactionFromRLP(tx1); require(tokens[token_id] > 0); require(prev_block == record.block_num && record.block_num < blk_num); require(token_id == exit_id); exit_ids[record.priority].remove(exit_id); delete exitRecords[exit_id]; emit ExitChallengedEvent(exit_id); } 

S'il y a une transaction qui dépense déjà le jeton affiché, alors un tel retrait sera annulé!

  • Preuve des dépenses de la transaction précédente:

 /* * Challenge exit by providing * a proof of a transaction spending P(C) that appears before C */ function challengeDoubleSpend(uint exit_id, uint blk_num, bytes tx1, bytes proof) public { require(checkPatriciaProof(keccak256(tx1), childChain[blk_num].merkle_root, proof)); Exit memory record = exitRecords[exit_id]; require(record.block_num > 0); // bytes32 prev_hash; uint prev_block; uint token_id; (, prev_block , token_id, ) = getTransactionFromRLP(tx1); require(tokens[token_id] > 0); // check if token double spent require(prev_block == record.prev_block && blk_num < record.block_num); // require(token_id == exit_id); exit_ids[record.priority].remove(exit_id); delete exitRecords[exit_id]; emit ExitChallengedEvent(exit_id); } 

Il s'agit du même contrôle que si le jeton avait été dépensé avant le retrait. Tout d'abord, recherchez une transaction dans le hachage racine. Ensuite, nous supprimons la sortie si elle a déjà été dépensée.

  • fournir une transaction dans l'historique des transactions du jeton qui le précède.

Cela peut être une mauvaise histoire, vous devez donc la confirmer avec une transaction enfant:

 // */ function challengeInvalidHistory(uint exit_id, uint blk_num, bytes tx0, bytes proof) public { // check if proof is valid require(checkPatriciaProof(keccak256(tx0), childChain[blk_num].merkle_root, proof)); Exit memory record = exitRecords[exit_id]; require(record.block_num > 0); bytes32 prev_hash; uint token_id; (prev_hash, , token_id, ) = getTransactionFromRLP(tx0); //require(exit_id == token_id); require(tokens[token_id] > 0); // transaction should be before exit tx in history require(blk_num < record.block_num - 1); challenged[exit_id] = blk_num; emit ChallengedInvalidHistory(exit_id, token_id); } 

L'appel du premier et du deuxième script bloque immédiatement la sortie.

L'appel au troisième scénario peut être répondu en fournissant un descendant direct. Elle doit être égale ou antérieure à la transaction parent.

 /* * Respond to invalid history challenge by providing * the direct child of C*, which must be either equal to or before P( C ) */ function respondChallenge(uint exit_id, uint blk_num, bytes childtx, bytes proof) public { require(challenged[exit_id] > 0); Exit memory record = exitRecords[exit_id]; require(record.block_num > 0); require(checkPatriciaProof(keccak256(childtx), childChain[blk_num].merkle_root, proof)); // get transaction from rlpencoded form bytes32 prev_hash; uint prev_block; uint token_id; (prev_hash, prev_block, token_id, ) = getTransactionFromRLP(childtx); // if direct child if (prev_block == challenged[exit_id] ) { if (blk_num <= record.prev_block && token_id == exit_id ) { delete challenged[exit_id]; emit ExitRespondedEvent(exit_id); } else { exit_ids[record.priority].remove(exit_id); delete exitRecords[exit_id]; emit ExitChallengedEvent(exit_id); } } } 

Autrement dit, si la transaction enfant correcte est reçue, la sortie est contestée et reste dans la file d'attente!
Après avoir construit une partie du protocole Opporty Plasma Cash, la conclusion suivante a été tirée:
Ce protocole assure la sécurité via la chaîne racine Ethereum.

En compliquant les procédures d'entrée et de sortie de la chaîne racine et la compression d'état (blocs de transaction), toutes les méthodes de sortie et d'entrée dans la chaîne racine ont été prises en compte, et les structures de données de base: les transactions et les blocs ont été étudiés.

En utilisant la chaîne latérale basée sur le réseau Ethereum, vous pouvez accélérer considérablement les transactions. Opporty a reçu jusqu'à 300 000 transactions par seconde sur un seul opérateur. C'est bien plus que ce que les systèmes de paiement actuels peuvent offrir.

Malgré certains problèmes de disponibilité des données, l'opérateur offre un haut niveau de stabilité de la blockchain et permet d'effectuer des transactions commerciales internationales efficaces.

Plasma Cash apporte une énorme augmentation de l'évolutivité. Par conséquent, Opporty utilise le plasma dans le cadre de son protocole PoE.

Liens utiles


  1. Plasma papier blanc
  2. Git hub
  3. Cas d'utilisation et description de l'architecture
  4. Papier réseau Lightning

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


All Articles