Ajouter une transaction à la blockchain est parfois un casse tête. La taille des blocs étant limitée, les mineurs sélectionnent en priorité les transactions les plus profitables pour eux.
Si vous êtes un développeur ou un utilisateur du réseau, vous avez probablement déjà été confronté au problème des transactions “stucks” (coincées). C’est un état qu’on pourrait qualifier d’attente interminable de traitement.
Comment se retrouve-t-on dans cette situation, pourquoi par “effet domino”, cela bloque-t-il toutes nouvelles transactions avec ce compte ? Quelles solutions peuvent apporter les relayeurs de transaction ?
Pourquoi est-ce parfois compliqué d’inclure des transactions dans la Blockchain?
Pour rappel, les transactions sur Ethereum sont ordonnancées par un nombre associé à la transaction et appelé « nonce ». Chaque compte sur la chaîne dispose d’un « nonce » qui est incrémenté à chaque transaction. Ainsi, la première transaction d’un compte aura le nonce 1, tandis que la troisième aura le nonce 3. Les transactions doivent s’exécuter dans l’ordre des nonces : la transaction 3 d’un compte ne pourra être intégrée dans un bloc et exécutée avant la 2.
Si plusieurs comptes sont en compétition pour passer leur transaction dans les meilleurs délais, le gas price va subitement grimper. Imaginons dans ce contexte qu’un compte ait soumis une transaction avec un gas price trop bas, elle sera alors “coincée” par l’afflux de transactions plus rentables pour les mineurs. Le compteur de transaction (nonce) du compte n’étant plus incrémenté, ce sont toutes les transactions du compte émisent depuis l’incident qui se retrouvent alors bloquées.
Pour sortir de cette situation dans un délai raisonnable, il faut annuler ou remplacer la transaction “coincée” par une nouvelle avec un nonce identique et un gasprice plus élevé. Il faut répéter l’opération en augmentant le gas price jusqu’à l’inclusion de la transaction dans un bloc.
Enfin, sauf à forcer un usage séquentiel du compte (ce qui est impossible si les transactions sont émises depuis le wallet d’un utilisateur par exemple) il reste à gérer l’accumulation des transactions “en attente” du compte avec un gas price potentiellement décorrélé du nouveau prix du marché.
Rendu célèbre par Cryptokitty et les ICOs, c’est aujourd’hui aux protocoles de finance décentralisée de faire face à ce challenge. Heureusement ces problèmes restent occasionnels sur Ethereum. Néanmoins lorsqu’ils se produisent, c’est un un bug critique pour l’application. Côté utilisateur, la frustration ressemble à celle qu’on peut ressentir lorsque le paiement ne fonctionne pas sur un site e-commerce. Côté application, en plus du support que cela génère, cela se traduit généralement pas une perte de revenu.
Utilisateurs et développeurs ont hérité d’un problème inextricable sur Ethereum 1.x. Cette situation a probablement contribué à ternir l’image du protocole. Elle a aussi montré que la communauté est capable de se mobiliser pour proposer des améliorations.
L’une d’entre elles est basée sur l’utilisation des meta-transactions.
Une solution basée sur les meta-transactions
Le concept de meta-transaction permet à des utilisateurs d’interagir avec la blockchain avec seulement une paire de clés publique/privée. Ce mécanisme est souvent utilisé pour rendre possible l’envoi de “gasless” transactions, c’est-à-dire émises depuis un compte (EOA) sans Ether.
Côté utilisateur, la construction de la meta-transaction est similaire à une transaction standard (from, to, value… et signature) sauf qu’au lieu de l’envoyer directement à la Blockchain, il envoie sa meta-transaction à un tiers qui prendra en charge le gas.
Ce tiers construit une nouvelle transaction qui contient la meta-transaction et l’envoie vers un smart contract proxy (ou seulement une fonction proxy dans un contrat). Le contrat vérifie la validité de la meta-transaction (grâce à sa signature) avant de l’exécuter.
Ce mécanisme est de plus en plus utilisé par les applications pour améliorer l’onboarding de leurs utilisateurs. Elles peuvent ainsi sponsoriser l’usage de leur service en payant le gas tout en préservant les bénéfices d’un système décentralisé pour l’utilisateur. (non-corruptibility, non-repudiation, etc).
Si l’application peut assurer elle-même le relai des transactions de ses utilisateurs, à quel moment a-t-on besoin d’un relayer?
Le dilemme entre “faire soi-même” ou “acheter une solution” est bien connu des développeurs. La réponse dépend toujours du contexte. Pizza Hut continue de livrer ses pizzas quand la majorité des restaurateurs utilisent Uber Eat ou Deliveroo. Comme pour les restaurants, les infrastructures de relais étant complexes à développer et coûteuses à maintenir, de plus en plus d’applications intègrent des APIs pour relayer leurs transactions.
Envoyez vos meta-transactions, le relayer s’occupe de tout !
En plus d’améliorer l’inclusion des transactions dans la blockchain, les relayeurs peuvent proposer des services pour faciliter la mise en place de “gasless” transactions.
Comment un relayeur améliore-t-il l’inclusion des transactions dans la Blockchain ?
Pour un compte donné, les transactions doivent être ordonnées et validées de manière séquentielle. Dans le cas où l’on souhaite envoyer 3 transactions par exemple, la transaction 3 restera en attente tant que la 1 et la 2 n’auront pas été traitées. Le nombre de transactions en attente pour un compte est limité par le noeud (sur geth la limite par défaut est de 64 par exemple). Au delà de cette limite, le noeud peut arbitrairement supprimer des transactions de sa file d’attente.
Pour contourner ces limitations, un relayer peut dispatcher l’envoi de ses meta-transactions à partir de plusieurs comptes. Par exemple avec trois comptes le nombre de transactions pouvant être en attente sur un noeud passe de 64 à 192 dans le cas de Geth. De plus, quand une transaction est bloquée sur un des comptes, le relayer peut déporter l’envoi sur les deux comptes restant et ainsi continuer à distribuer ses transactions.
Un autre point à considérer est le système de nonce (permettant de se protéger contre le replay attack) utilisé par le smart contract relayeur. La solution choisie aura un impact sur la façon dont les transactions seront traitées.Par exemple, si l’on souhaite faire de l’ancrage de certificat, on veut pouvoir envoyer un grand nombre de transactions simultanément et l’ordre n’a pas d’importance.
Une application peut avoir besoin d’envoyer certaines transactions de manière séquentielle et d’autres de manière simultané. En cas de volume de transactions important, les technique pour estimer le prix du gas et et les solutions de protection contre les replay attack “on chain” peuvent avoir des impact important sur le coût des transactions. Les relayeurs permettent aux développeurs de s’affranchir de ces questions en leur mettant à disposition des services simples prêt à l’usage.
Comment un relayeur facilite-t-il la mise en place de “gasless” transactions?
La nécessité d’avoir de l’Ether sur son compte pour modifier l’état d’un smart contract rend l’onboarding utilisateur laborieux sur Ethereum. Aucune application grand public n’aura un taux de conversion élevée tant qu’elle imposera à ses utilisateurs d’acheter de l’Ether avant son utilisation.
Certaines applications proposent tout simplement de payer le gas pour leurs utilisateurs. Cette approche est souvent négligée par les développeurs car elle s’écarte de la philosophie du protocole qui vise à garantir une indépendance dans l’usage du réseau. Dans ce modèle plus traditionnel, l’application considère le gas comme un coût d’infrastructure, au même titre qu’une consommation CPU sur AWS par exemple. La génération de revenus étant généralement corrélée à l’usage des smart contract, c’est un modèle économiquement viable dans la plupart des cas.
L’application et l’utilisateur peuvent également s’accorder on chain pour un remboursement automatique des frais de gas. Avec l’émergence des services de DeFi, de plus en plus d’utilisateurs possèdent des Token sans posséder d’Ether. Certains systèmes permettent alors à leurs utilisateurs de payer leurs transactions avec un token ERC20.
L’application peut également distribuer à ses utilisateurs ses propres token au moment de l’inscription. Ce mécanisme est comparable à une distribution de coupons gratuits utilisables seulement sur les contrats de l’application.
Un relayeur aidera à mettre en place la bonne stratégie de remboursement de gas sans que cela ne nécessite de lourds investissements en recherche et développement.
Comment s’utilise un relayeur ?
Idéalement, tous ces services doivent fonctionner de manière transparente pour les développeurs, c’est-à-dire sans modifier ses smart contract ou le code de leurs applications.
Les services de relais sont généralement exposés via une API web classique. Ils peuvent également être disponibles en tant que proxy devant un “web3 provider” entre l’application et le noeud pour faciliter leur usage avec des librairies comme web3js.
Enfin, le design de la solution doit permettre à ses utilisateurs de vérifier que le relayer ne peut ni rejouer, ni modifier les données des meta-transactions.
Le fonctionnement d’un relayer est finalement assez similaire à celui d’une liste d’attente d’un noeud, mais il ajoute plusieurs fonctionnalités indispensables pour les applications en production (live sur le mainnet).
Existe-t-il un standard pour les relayeurs?
Décentralisation, simplicité, vie privée, sécurité, … choisir comment relayer une transaction sur Ethereum implique de prendre en compte beaucoup de critères et à nouveau, selon le contexte, les applications font des choix différents.
GSN (Gas Station Network) est une des initiatives les plus visibles dans ce domaine. Cette solution a permis la construction d’un réseau de relayeurs décentralisés. L’utilisation d’un hub de relayeurs permet de mettre en compétition des acteurs prêts à traiter des transactions contre une commission. GSN nécessite d’importants efforts d’intégration. C’est une solution adaptée surtout lorsque l’utilisation d’un réseau P2P de relais est importante. Pour comprendre pourquoi aucun consensus autour d’un standard n’existe, comparons deux wallets: Metamask et Argent.xyz.
Le premier gère l’identité de ses utilisateurs avec un EOA, le second utilise des smart contract. Implémenter naïvement un “proxy relayeur” sur des transactions émises depuis MetaMask se révèle plus complexe qu’il n’y paraît. L’utilisation de msg.sender dans les contrats de l’application serait proscrite car elle contiendrait l’adresse du relayer et non l’adresse publique de l’utilisateur.
Argent.xyz utilise quand à lui un account contract qu’il faut déployer pour chaque utilisateur. C’est un coût supplémentaire pour Argent.xyz mais la vérification et le relai des transactions se font directement dans ce contrat, aucune modification sur les contrats de destination n’est alors requise.
Les contrats des applications peuvent aussi directement vérifier et exécuter la signature des meta-transactions en implémentant deux fonctions. Une pour se protéger contre les attaques par rejeu et l’autre pour vérifier et exécuter la transaction. Une solution qui présente de nombreux avantages mais qui reste inutilisable sur les contrats déjà déployés.
Pour aller plus loin sur les différentes philosophies de relai sur Ethereum, @wighawag à récemment proposé l’idée d’un “Minimal And Extensible Meta Transaction Forwarder” #2585. Cet EIP montre bien à quel point le sujet est vaste et activement débattu dans la communauté.
Conclusion
Les applications avec d’importants volumes de transactions paient systématiquement des commissions de réseau beaucoup trop chères. Ce gaspillage ne leur évite pas de devoir intervenir lorsqu’une transaction est bloquée. Pour les applications plus petites ou en cours de création, créer et maintenir une infrastructure de relai nécessite des investissements importants. Les prestataire de services de paiement comme Paypal ou Stripe ont permis aux développeurs d’accepter des paiements électroniques simplement sur Internet. Ethereum permet de supprimer ou limiter le pouvoir des intermédiaires. Ce protocole doit pourtant se doter de passerelles pour simplifier son utilisation. Les relayeurs répondent à ce challenge en mettant à disposition des développeurs des infrastructures fiables d’acheminement de transactions tout en étant limité “by design” à leur rôle de relaie grâce à l’utilisation exclusive de transactions pré-autorisées par les utilisateurs.
Chez Rockside.io, nous nous sommes fixé pour objectif il y a 8 mois de construire le meilleur relayeur sur Ethereum, nous traitons déjà des centaines de transactions quotidiennement pour des startups et des grands comptes. Cela traduit un besoin réel chez les développeurs. L’utilisation en progression de ce type de service montre également que le rapport des entreprises à la blockchain évolue. Nous passons d’une volonté de comprendre à une volonté d’utiliser la technologie.