Wie parse ich das Transaktionsempfangsprotokoll mit web3.js?

Der Ereignis-Parser in web3 bietet eine nette Parsing-Funktion für Ereignisse, und ich verwende ihn zum Protokollieren aller Ereignisse in einer Datei, aber es ist sehr schwierig, einzelne Ereignisse für eine bestimmte Transaktion für automatisierte Tests zu betrachten, da dies unnötig und schwierig ist zur Verwaltung des Nebenläufigkeitsaspekts, wenn keiner vorhanden sein muss.

Wenn ich mit web3 ein Transaktionsergebnis erhalte, habe ich den Transaktionsbeleg in der Hand und das ist der perfekte Zeitpunkt, um das Ergebnis synchron zu prüfen und Pass/Fail-Testkriterien anzuwenden.

Ich möchte den Protokollabschnitt der Quittung analysieren, kann aber in web3 keine Funktion dafür finden. Existiert es?

Da die neueren Antworten nicht ausreichend positiv bewertet wurden, sollte hier klargestellt werden, dass die Web3-Versionen 1.0 und höher eine API bereitstellen, um dies für Sie zu tun, Sie müssen sie nicht mehr selbst zusammenhacken.

Antworten (6)

Tun Sie dies: Sie müssen Code aus web3 ziehen, und es funktioniert am besten, wenn Ihr Frontend mit etwas wie webpack oder browserify gebündelt ist:

var SolidityCoder = require("web3/lib/solidity/coder.js");
var log = receipt.logs[0];
var data = SolidityCoder.decodeParams(["string", "uint"], log.data.replace("0x", ""));

In diesem Fall dekodieren wir Protokolldaten, die zwei Variablen enthalten, eine vom Typ String und eine vom Typ uint.

BEARBEITEN:

Wenn Sie die ABI zur Verfügung haben, können Sie erkennen, welches Ereignis sich auf diese ABI bezieht:

var SolidityCoder = require("web3/lib/solidity/coder.js");

// You might want to put the following in a loop to handle all logs in this receipt.
var log = receipt.logs[0];
var event = null;

for (var i = 0; i < abi.length; i++) {
  var item = abi[i];
  if (item.type != "event") continue;
  var signature = item.name + "(" + item.inputs.map(function(input) {return input.type;}).join(",") + ")";
  var hash = web3.sha3(signature);
  if (hash == log.topics[0]) {
    event = item;
    break;
  }
}

if (event != null) {
  var inputs = event.inputs.map(function(input) {return input.type;});
  var data = SolidityCoder.decodeParams(inputs, log.data.replace("0x", ""));
  // Do something with the data. Depends on the log and what you're using the data for.
}
Sollte dies nicht die vom Compiler generierte ABI verwenden, um sie zu dekodieren? So funktioniert das mit Events...
Die Protokolldaten sind ABI-kodiert. Die angegebenen Typen ("string, dann "uint") teilen dem Decoder mit, wie er es dekodieren soll. Sie benötigen nicht die vollständige Vertrags-ABI - nur die Typen, die sich auf das spezifische Protokoll beziehen. Lassen Sie mich meine Antwort bearbeiten, um dies besser zu beschreiben funktioniert.
Antwort bearbeitet. Sollte Ihnen eine bessere Vorstellung davon geben, wie Sie mit den Protokolldaten umgehen.
Das Problem ist, dass ich die Typen für ein Ereignis nicht angeben muss, ein JSON-Objekt wird automatisch erstellt. Das Erstellen manuell erstellter JSON-Typen aus der Untersuchung von Solidity-Code ist mühsam und fehleranfällig. Vielleicht sollte ich die Frage in "automatisch analysieren" ändern, da das von Ihnen vorgeschlagene Verfahren manuell ist.
Ich bin mir nicht sicher, was Sie in diesem Zusammenhang zwischen "automatisch" und "manuell" meinen. Wenn Sie Protokolldaten (eine hexadezimale Zeichenfolge) in Javascript-Objekte umwandeln möchten, gehen Sie wie folgt vor. Web3 stellt hierfür keine Funktion für Sie bereit. Wenn Sie diese Funktion möchten, empfehle ich Ihnen, diesen Code an Web3 zu senden und zu versuchen, ihn aufzunehmen. Prost!
Ich bin damit einverstanden, den Code zu erstellen, aber ich hätte gerne einige Hinweise, wo ich anfangen soll. Wie findet der Ereignishandlercode den Ereignisnamen heraus, sucht ihn in der ABI und erstellt das JSON-Objekt für das Ereignis? Ich komme erst Ende März dazu, ich habe andere Termine.
Hmm, es gibt ein Caching-Problem mit Stackexchange, ich habe Ihren Code aus irgendeinem Grund nicht hinzugefügt gesehen. Ich sehe jetzt, dass es vollständig datengesteuert ist, nicht manuell. Alles, was ich brauche, ist das ABI und das Ereignisprotokoll und alles ist gut. Ich werde das Kopfgeld vergeben. Wollen Sie das jetzt in Web3 einchecken oder soll ich das tun? Ende März werde ich meinen Erweiterungen von web3 ein erstklassiges Transaktionsobjekt hinzufügen, die Frage ist, ob die Community es will oder nicht ...
Fühlen Sie sich frei einzureichen. Sie sind sich bezüglich Ihres Transaktionsobjekts nicht sicher. Aber ich habe diese Vertragsabstraktion in den letzten Monaten verwendet (PS: Ich habe sie geschrieben) und sie funktioniert gut für mich. Würde mich über eure Gedanken freuen. github.com/ConsenSys/ether-pudding
Ich habe Sie auf Gitter gepingt
Ich versuche dasselbe, kann aber die coder.js nicht finden, kann mir jemand den Speicherort auf web3/lib unter Windows OS sagen
@Tim Coulter @Paul S Würden Sie bitte erwähnen, wie SolidityCoder.decodeParams(["string", "uint"], log.data.replace("0x", ""));Parameter geändert werden, wenn unser Funktionseingabetyp ein Array wie dieses ist: function newObject(bytes32 _id, uint256 number_of_sub_states, bytes32[10] sub_states_types, bytes32[10] sub_states_values, address _owner)? Vielen Dank.
@Tim Coulter @Paul S Wenn ich benutze var SolidityCoder = require("web3/lib/solidity/coder.js");, erhalte ich diese Fehlermeldung: Error: Cannot find module 'web3/lib/solidity/coder.js'Weißt du, was der Grund ist?, Danke.
Wahrscheinlich hat die neuere Version von web3 Interna neu geordnet

Sie können die web3.eth.abi.decodeLogFunktion jetzt verwenden (web3 1.0).

Beispiel aus der Dokumentation:

web3.eth.abi.decodeLog([{
    type: 'string',
    name: 'myString'
},{
    type: 'uint256',
    name: 'myNumber',
    indexed: true
},{
    type: 'uint8',
    name: 'mySmallNumber',
    indexed: true
}],
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000748656c6c6f252100000000000000000000000000000000000000000000000000',
['0x000000000000000000000000000000000000000000000000000000000000f310', '0x0000000000000000000000000000000000000000000000000000000000000010']);
> Result {
    '0': 'Hello%!',
    '1': '62224',
    '2': '16',
    myString: 'Hello%!',
    myNumber: '62224',
    mySmallNumber: '16'
}
kopieren fügen hmmm
@MH Sie müssen hier bei SE neu sein? Die Idee ist, eine Antwort bereitzustellen, nicht nur einen Link. Kopieren und Einfügen ist eine perfekte Möglichkeit, dies zu tun.

Timo:

Vielen Dank für den Hinweis. Sie haben mich gezwungen, endlich einige der Interna von web3.js zu verstehen.

Ich habe einen saubereren Weg gefunden, dies zu tun, der alle Eckfälle des eigentlich ziemlich komplizierten Protokollnachrichtenformats abdeckt (z. B. Indizierung). Ich habe gerade SolidityEvent von web3 verwendet, um die bereits getestete Arbeit für mich zu erledigen.

Unten ist der Code. Ich habe diesen Code auf GitHub , einschließlich Testcode .

// XXX move this to a hook function
var SolidityEvent = require("web3/lib/web3/event.js");
Pudding.logParser = function (logs, abi) {

    // pattern similar to lib/web3/contract.js:  addEventsToContract()
    var decoders = abi.filter(function (json) {
        return json.type === 'event';
    }).map(function(json) {
        // note first and third params required only by enocde and execute;
        // so don't call those!
        return new SolidityEvent(null, json, null);
    });

    return logs.map(function (log) {
        return decoders.find(function(decoder) {
            return (decoder.signature() == log.topics[0].replace("0x",""));
        }).decode(log);
    })
}
Beachten Sie, dass Sie bei mehreren Verträgen die ABIs für alle Verträge benötigen. Ich werde dieses Beispiel nicht aktuell halten. Wenn Sie auf dem Laufenden bleiben möchten, folgen Sie dem Github-Link. Ein paar Bugs habe ich schon behoben. Das Kaskadieren von Array-Funktionen ist sehr schlecht, da ein leeres Array dazu führt, dass Javascript einen Fehler ausgibt ...
Dies ist eine sehr gute Antwort, wenn jemand mit Web v0.20.x arbeitet.
Ja, der Kommentar ist oben ausgeblendet, aber in den neuesten Versionen von web3.js wird der Transaktionsbeleg für Sie analysiert.

Verwenden Sie für web3.js 1.0 Folgendes:

contractInstance.inputs = [{"indexed": false, "name": "_id", "type": "uint256"}]; //event abi
contractInstance._decodeEventABI({data: '0x0'}); //event raw data

Ausgang

{
  returnValues: 
   Result {
     '0': '1',
     _id: '1',
  },
  raw: {
    data: '0x0'
  }
}

Sobald Sie den Transaktionsbeleg ( tr) haben, kennen Sie die Blocknummer der Transaktion ( tr.blockNumber). Sie können also Folgendes tun:

myContract.MyEvent (
  {},
  {fromBlock: tr.blockNumber, toBlock: tr.blockNumber}).
    get ().
      filter (function (e) {
        return e.transactionHash == tr.transactionHash
      });

Dadurch wird ein Array aller Ereignisse des Typs zurückgegeben MyEvent, die durch den Vertrag myContractin der Transaktion generiert wurden, auf die durch die Transaktionsquittung verwiesen wird tr.

Mit web3.js 0.20.6.

$ node
> var AllEvents = require('web3/lib/web3/allevents')
undefined
> var decodeEventsForContract = (C, tr) => {
    const ae = new AllEvents(C._web3, C.abi, C.address);

    // ae.decode mutates the args, so we deep copy
    return JSON.parse(JSON.stringify(tr)) 
      .logs
      .filter(l => l.address === C.address)
      .map(l => ae.decode(l));
  }
undefined
> decodeEventsForContract(MyTokenContract, txreceipt);
[ { logIndex: 0,
    transactionIndex: 0,
    transactionHash: '0xbc68d5ddc391fab84cd633a77dbc815cbc42546a13de9d123f7a5b820faa3cb4',
    blockHash: '0xb604998aa0b6bece492530c9cbab494349a31b18a34067f225e1b59613952051',
    blockNumber: 21,
    address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
    type: 'mined',
    event: 'Transfer',
    args: 
     { from: '0x0000000000000000000000000000000000000000',
       to: '0x627306090abab3a6e1400e9345bc60c78a8bef57',
       value: [BigNumber] } },
  { logIndex: 1,
    transactionIndex: 0,
    transactionHash: '0xbc68d5ddc391fab84cd633a77dbc815cbc42546a13de9d123f7a5b820faa3cb4',
    blockHash: '0xb604998aa0b6bece492530c9cbab494349a31b18a34067f225e1b59613952051',
    blockNumber: 21,
    address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
    type: 'mined',
    event: 'Mint',
    args: 
     { to: '0x627306090abab3a6e1400e9345bc60c78a8bef57',
       value: [BigNumber],
       minter: '0x627306090abab3a6e1400e9345bc60c78a8bef57' } } ]