Rejoignez-Nous sur

Tout ce que vous avez toujours voulu savoir sur les événements et les journaux sur Ethereum | par William Schwab | Blog de Linum Labs | Sept. 2020

News

Tout ce que vous avez toujours voulu savoir sur les événements et les journaux sur Ethereum | par William Schwab | Blog de Linum Labs | Sept. 2020

Dans le cadre d'un projet récent, Linum Labs a été chargé de créer une API qui pourrait être utilisée pour récupérer les données pertinentes d'une suite de contrats déployés. Alors que le grattage des données d'événements est une opération assez courante dans les applications blockchain, nous avons constaté un manque de guides pratiques ou même d'explications détaillées sur la façon d'utiliser les outils existants. Vous cherchez à extraire des données de la blockchain et vous ne savez pas comment obtenir les informations que vous souhaitez des événements? Nous espérons que ce guide vous aidera à faciliter votre processus de développement.

Les événements sont courants dans les contrats intelligents Ethereum. Voici où Ouvrez Zeppelin déclare certains dans leur Interface ERC20:

Chaque bloc a un journal, accessible via les outils que vous utilisez pour interagir avec la blockchain. Chaque bloc génère un journal contenant les informations suivantes:

L'exemple est tiré de https://codeburst.io/deep-dive-into-ethereum-logs-a8d2047c7371 , et apparaît avec la permission de l'auteur (Banteg)

Les événements vous permettent d'ajouter des données de journalisation pertinentes aux journaux d'un bloc.

Cela nécessite une explication, cependant. Et si je vous disais que le journal de l'image ci-dessus contient un événement ERC20 Transfer? Vous ne pouvez certainement rien voir de tel là-bas, n'est-ce pas? Eh bien, en l'occurrence, il y en a, et nous allons vous expliquer comment voir cela. Je voudrais créer cela à partir de zéro, donc si vous recherchez simplement une implémentation de code, passez au bas. Le tl; dr est que vous pouvez rechercher des données à partir d'événements avec quelques fonctions intégrées dans Ethers.js. (Nous avons deux implémentations ci-dessous, une pour Ethers v5 et une autre pour v4.)

Il peut être utile de faire une petite tangente ici à propos des ABI. Quiconque s'est occupé de la mise en œuvre d'outils qui interagissent avec les contrats en a probablement entendu parler, mais en parler un peu ici devrait faciliter un peu l'explication de la partie suivante.

  • name est le nom de l'argument. TransferLes arguments de sont from, to, et value.
  • Je ne sais pas trop quoi internalType Est-ce que. Veuillez m'éclairer dans les commentaires.
  • indexed est important, mais nous allons essayer de l'expliquer.
Transfer(address,address,uint256)
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
0x0000000000000000000000000035fc5208ef989c28d47e552e92b0c507d2b318000000000000000000000000646985c36ad7bf4f3a91283f3ea6eda2af79fac6000000000000000000000000000000000000000000000000000000000001a4b0
const logs = provider.getLogs({
address: “0x06012c8cf97bead5deoe237070f9587f8e7a266d”,
topics: (“0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef”)
});
const decoder = new ethers.utils.AbiCoder();const unindexedEvents = events.inputs.filter(event => event.indexed === false);const decodedLogs = logs.map(log => decoder.decode(unindexedEvents, log.data)
const decodedFromAndTo = logs.map(log => {
const from = decoder.decode(“address”, log.topics(1));
const to = decoder.decode(“address”, log.topics(2));
return (from, to)
})

Nous avons maintenant la possibilité de hacher une signature d'événement et de voir si elle figure dans les sujets et de décoder les sujets et les données. Mais comment êtes-vous censé obtenir les objets du journal? La question la plus importante que vous découvrirez est de savoir comment obtenir les objets de journal dont vous avez besoin? Les blockchains sont grandes. Le réseau principal d'Ethereum compte plus de 10 millions de blocs. Vous ne voulez pas passer accidentellement un appel qui essaie d'extraire les journaux de la chaîne entière.

Tous les exemples supposent une adresse à un contrat ERC20 transmise sous forme de chaîne et recherchent le Transfer un événement. Vous aurez également besoin de l'ABI du contrat. Vous aurez également besoin d'un fournisseur, qui est le terme Web3 général pour l'objet par lequel vous vous connectez à la blockchain. Si vous ne savez pas ce que c'est, j'admire honnêtement votre détermination à en arriver là, et vous devriez être en mesure de découvrir comment en instancier un dans la documentation sur le framework que vous utilisez. Ils sont à peu près la colonne vertébrale de tous les scripts Web3, alors assurez-vous de les comprendre. Cela étant dit, voici quelques mots sur le sujet: si vous voulez pouvoir interagir avec la blockchain, ou même simplement en lire, vous avez besoin d'une sorte de connexion à la blockchain.

À la dure

Il existe un moyen très simple de le faire avec Ethers v5, et un moyen assez simple avec la v4, mais si nous sommes arrivés jusque-là, quel est le plaisir de le faire de manière simple? Aussi, cher lecteur, je ne sais pas si vous en avez besoin pour un projet qui serait difficile à mettre à jour vers la v5, ou si vous utilisez un framework complètement différent qui n'a pas d'intégrés comme Ethers v5 (ou v4 ) Est-ce que. En tant que tel, d'abord, nous allons le faire à la dure. Il sert également un but illustratif, donnant une implémentation de code à tout ce que nous avons discuté ci-dessus.

const eventFilter = (contractAddress, erc20abi, _provider) => {
const provider = _provider
// this will return an array with an object for each event
const events = erc20abi.abi.filter(obj => obj.type ? obj.type === "event" : false);
// getting the Transfer event, then pulling it out of the array
const event = events.filter(event => event.name === "Transfer")(0);
// getting the types for the event signature
const types = event.inputs.map(input => input.type)
// knowing which types are indexed will be useful later
let indexedInputs = ();
let unindexedInputs = ();
event.inputs.forEach(input => {
input.indexed ?
indexedInputs.push(input) :
unindexedInputs.push(input)
});
// event signature
const eventSig = `${event.name}(${types.toString()})`;
// getting the topic
const eventTopic = ethers.utils.keccak256(eventSig);
// you could also filter by blocks, see above "Getting the Logs You Need" const logs = provider.getLogs({
address: contractAddress,
topics: (eventTopic)
});
// need to decode the topics and events
const decoder = new ethers.utils.AbiCoder();
const decodedLogs = logs.map(log => {
// remember how we separated indexed and unindexed events?
// it was because we need to sort them differently here
const decodedTopics = indexedInputs.map(input => {
// we use the position of the type in the array as an index for the
// topic, we need to add 1 since the first topic is the event sig
const value = decoder.decode(
input.type,
log.topics(indexedInputs.indexOf(input) + 1)
);
return `${input.name}: ${value}`;
})
const decodedDataRaw = decoder.decode(unindexedInputs, log.data);
const decodedData = unindexedInputs.forEach((input, i) => {
return `${input.name}: ${decodedDataRaw(i)}`
});
}); // let's put everything in one array const decodedEvents = decodedLogs.map(log => (...log.decodedTopics, ...log.decodedData)); // let's pull out the to and from addresses and amounts const toAddresses = decodedEvents.map(event => event("values")("to"));
const fromAddresses = decodedEvents.map(event => event("values")("from"));
const amounts = decodedEvents.map(event => event("values")("value"));
return (decodedEvents, fromAddresses, toAddresses, amounts)}

Ethers v4

Ici, tout ce dont vous aurez besoin est l’adresse du contrat et l’ABI. Une chose sympa appelée Interface fera tout le reste pour vous.

const eventFilterv4 = (contractAddress, erc20abi, _provider) => {
// creating the interface of the ABI
const iface = new ethers.utils.Interface(erc20abi.abi);
// get all events from interface
const events = iface.events;
// filter for Transfer
const transfer = events("Transfer");
// get event topic
const eventTopic = transfer.topic;
const logs = _provider.getLogs({
address: contractAddress,
topics: (eventTopic)
});
// this will return an array with the decoded events
const decodedEvents = logs.map(log => iface.parseLog(log));
// let's pull out the to and from addresses and amounts
const toAddresses = decodedEvents.map(event => event("values")("to"));
const fromAddresses = decodedEvents.map(event => event("values")("from"));
const amounts = decodedEvents.map(event => event("values")("value"));
return (fromAddresses, toAddresses, amounts)}

Ethers v5

Ethers v5 facilite les choses. Vous avez toujours besoin de l'ABI et de l'adresse, mais après cela, tout est facile à utiliser:

const eventFilterv5 = (contractAddress, erc20abi, _provider) => {
const iface = new ethers.utils.Interface(erc20abi.abi);
const logs = _provider.getLogs({
address: contractAddress
});
const decodedEvents = logs.map(log => {
iface.decodeEventLog("Transfer", log.data)
});
const toAddresses = decodedEvents.map(event => event("values")("to"));
const fromAddresses = decodedEvents.map(event => event("values")("from"));
const amounts = decodedEvents.map(event => event("values")("value"));
return (fromAddresses, toAddresses, amounts)}

À l'origine, je pensais, oui! Nous l'avons fait! Ça y est, il est temps de faire les valises et de rentrer à la maison. Nous avons rapidement découvert une autre différence clé entre le traitement des données classiques et le traitement des données blockchain. La plupart des API ont une sorte de limiteur intégré afin que vous ne soyez pas soudainement et étonnamment frappé par une quantité massive de réponses. La blockchain n'a pas mis en place une telle mesure. D'après mon expérience, mon serveur enverrait automatiquement toute demande qui tenterait d'obtenir plus de 10K réponses, je ne me souviens pas si cela était intégré à Ethers, ou une partie de l'architecture sous-jacente Node.js (je soupçonne cette dernière), mais cela n'est guère pratique si vous essayez de créer un tableau de bord qui affiche des données pertinentes et que vous remplissez soudainement une table avec des centaines de lignes là où vous ne vous y attendiez pas. On m’a fait remarquer que c’était encore pire si vous commencez à récupérer tellement de données que les E / S de votre ordinateur sont débordées. Ne serait-ce pas bien s'il y avait un moyen de contrôler la quantité de données que vous récupérez d'une demande?

const eventFilterv5WithPagination = (contractAddress, erc20abi, _provider, numberOfResponses) => {
// creating the interface of the ABI
const iface = new ethers.utils.Interface(erc20abi.abi);
// initialize array for the logs
let logs = ();
// get latest block number
const latest = await provider.getBlockNumber();
// initialize a counter for which block we're scraping starting at the most recent block
let blockNumberIndex = latest;
// while loop runs until there are as many responses as desired
while (logs.length < numberOfResponses) {
const tempLogs = await provider.getLogs({
address: contractAddress,
// both fromBlock and toBlock are the index, meaning only one block's logs are pulled
fromBlock: blockNumberIndex,
toBlock: blockNumberIndex
})
// an added console.log to help see what's going on
console.log("BLOCK: ", blockNumberIndex, " NUMBER OF LOGS: ", tempLogs.length);
blockNumberIndex -= 1;
logs = logs && logs.length > 0 ? (...logs, ...tempLogs) : (...tempLogs)
};
// this will return an array with the decoded events
const decodedEvents = logs.map(log => {
iface.decodeEventLog("Transfer", log.data)
});
// let's pull out the to and from addresses and amounts
const toAddresses = decodedEvents.map(event => event("values")("to"));
const fromAddresses = decodedEvents.map(event => event("values")("from"));
const amounts = decodedEvents.map(event => event("values")("value"));
return (fromAddresses, toAddresses, amounts)}

C'était pas mal! Nous avons parcouru les journaux et les événements, compris comment les journaux stockent les événements et avons même abouti à trois implémentations de code différentes sur la façon d'extraire les événements des journaux, ainsi que sur la façon de filtrer le nombre de réponses que vous obtenez.



Traduction de l’article de William Schwab : Article Original

BlockBlog

Le Meilleur de l'Actualité Blockchain Francophone & Internationale | News, Guides, Avis & Tutoriels pour s'informer et démarrer facilement avec Bitcoin, les Crypto-Monnaies et le Blockchain. En Savoir Plus sur L'Équipe BlockBlog

Commenter cet Article

Commenter cet Article

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Plus dans News

Les Plus Populaires

Acheter des Bitcoin

Acheter des Alt-Coins

Sécuriser vos Cryptos

Vêtements et Produits Dérivés

Top