add event decoder

pull/1/head
yann300 7 years ago
parent 233c4171ef
commit 3cce2a17b1
  1. 28
      src/app.js
  2. 81
      src/app/listener/eventsDecoder.js
  3. 27
      src/app/txListener.js

@ -31,6 +31,7 @@ var RighthandPanel = require('./app/righthand-panel')
var examples = require('./app/example-contracts') var examples = require('./app/example-contracts')
var modalDialogCustom = require('./app/modal-dialog-custom') var modalDialogCustom = require('./app/modal-dialog-custom')
var Txlistener = require('./app/txListener') var Txlistener = require('./app/txListener')
var EventsDecoder = require('./app/listener/eventsDecoder')
var css = csjs` var css = csjs`
html { box-sizing: border-box; } html { box-sizing: border-box; }
@ -748,18 +749,20 @@ function run () {
node.insertBefore(staticanalysis.render(), node.childNodes[0]) node.insertBefore(staticanalysis.render(), node.childNodes[0])
// ----------------- Tx listener ----------------- // ----------------- Tx listener -----------------
// Commented for now. will be used later.
var compiledContracts = function () {
if (compiler.lastCompilationResult && compiler.lastCompilationResult.data) {
return compiler.lastCompilationResult.data.contracts
}
return null
}
var txlistener = new Txlistener({ var txlistener = new Txlistener({
api: { api: {
web3: function () { return executionContext.web3() }, web3: function () { return executionContext.web3() },
isVM: function () { return executionContext.isVM() }, isVM: function () { return executionContext.isVM() },
vm: function () { return executionContext.vm() }, vm: function () { return executionContext.vm() },
contracts: function () { contracts: compiledContracts,
if (compiler.lastCompilationResult && compiler.lastCompilationResult.data) {
return compiler.lastCompilationResult.data.contracts
}
return null
},
context: function () { context: function () {
return executionContext.getProvider() return executionContext.getProvider()
} }
@ -770,6 +773,14 @@ function run () {
} }
}) })
var eventsDecoder = new EventsDecoder({ txListener: txlistener })
txlistener.event.register('txResolved', (tx, resolvedData) => {
if (resolvedData) {
eventsDecoder.parseLogs(tx, resolvedData, compiledContracts())
}
})
txlistener.startListening() txlistener.startListening()
txlistener.event.register('newTransaction', (tx) => { txlistener.event.register('newTransaction', (tx) => {
@ -781,7 +792,8 @@ function run () {
console.log({ console.log({
tx: tx, tx: tx,
resolvedContract: txlistener.resolvedContract(address), resolvedContract: txlistener.resolvedContract(address),
resolvedTransaction: resolvedTransaction resolvedTransaction: resolvedTransaction,
resolvedEvents: eventsDecoder.eventsOf(tx.hash)
}) })
}) })

@ -0,0 +1,81 @@
'use strict'
var $ = require('jquery')
var ethJSABI = require('ethereumjs-abi')
/**
* Register to txListener and extract events
*
*/
class EventsDecoder {
constructor (opt = {}) {
this.txListener = opt.txListener
this.resolvedEvents = {}
}
/**
* use Transaction Receipt to decode logs. assume that the transaction as already been resolved by txListener.
* logs are decoded only if the contract if known by remix.
*
* @param {Object} tx - transaction object
* @param {Function} cb - callback
*/
parseLogs (tx, resolvedData, compiledContracts) {
this.txListener.resolveTransactionReceipt(tx, (error, receipt) => {
if (error) console.log(error)
this._decodeLogs(tx, receipt, resolvedData.contractName, compiledContracts)
})
}
eventsOf (hash) {
return this.resolvedEvents[hash]
}
_decodeLogs (tx, receipt, contract, contracts) {
if (!contract || !receipt.logs) {
return
}
this._decodeEvents(tx, receipt.logs, contract, contracts)
}
_eventABI (contractName, compiledContracts) {
var contractabi = JSON.parse(compiledContracts[contractName].interface)
var eventABI = {}
$.each(contractabi, function (i, funABI) {
if (funABI.type !== 'event') {
return
}
var hash = ethJSABI.eventID(funABI.name, funABI.inputs.map(function (item) { return item.type }))
eventABI[hash.toString('hex')] = { event: funABI.name, inputs: funABI.inputs }
})
return eventABI
}
_decodeEvents (tx, logs, contractName, compiledContracts) {
var eventABI = this._eventABI(contractName, compiledContracts)
// FIXME: support indexed events
for (var i in logs) {
// [address, topics, mem]
var log = logs[i]
var event
var decoded
try {
var abi = eventABI[log.topics[0].replace('0x', '')]
event = abi.event
var types = abi.inputs.map(function (item) {
return item.type
})
decoded = ethJSABI.rawDecode(types, new Buffer(log.data.replace('0x', ''), 'hex'))
decoded = ethJSABI.stringify(types, decoded)
} catch (e) {
decoded = log.data
}
if (!this.resolvedEvents[tx.hash]) {
this.resolvedEvents[tx.hash] = []
}
this.resolvedEvents[tx.hash].push({ event: event, args: decoded })
}
}
}
module.exports = EventsDecoder

@ -22,6 +22,7 @@ class TxListener {
this._web3VMProvider.setVM(opt.api.vm()) this._web3VMProvider.setVM(opt.api.vm())
this._resolvedTransactions = {} this._resolvedTransactions = {}
this._resolvedContracts = {} this._resolvedContracts = {}
this._transactionReceipts = {}
this.init() this.init()
opt.event.executionContext.register('contextChanged', (context) => { opt.event.executionContext.register('contextChanged', (context) => {
if (this.loopId) { if (this.loopId) {
@ -124,8 +125,10 @@ class TxListener {
_resolve (block, callback) { _resolve (block, callback) {
async.each(block.transactions, (tx, cb) => { async.each(block.transactions, (tx, cb) => {
this._resolveTx(tx, () => { this._resolveTx(tx, (error, resolvedData) => {
if (error) cb(error)
this.event.trigger('newTransaction', [tx]) this.event.trigger('newTransaction', [tx])
if (resolvedData) this.event.trigger('txResolved', [tx, resolvedData])
cb() cb()
}) })
}, () => { }, () => {
@ -144,14 +147,15 @@ class TxListener {
var code = tx.input var code = tx.input
contractName = this._tryResolveContract(code, contracts, 'bytecode') contractName = this._tryResolveContract(code, contracts, 'bytecode')
if (contractName) { if (contractName) {
this._resolveCreationAddress(tx, (error, address) => { this.resolveTransactionReceipt(tx, (error, receipt) => {
if (error) return cb(error) if (error) return cb(error)
var address = receipt.contractAddress
this._resolvedContracts[address] = contractName this._resolvedContracts[address] = contractName
this._resolveFunction(contractName, contracts, tx, true) var fun = this._resolveFunction(contractName, contracts, tx, true)
if (this._resolvedTransactions[tx.hash]) { if (this._resolvedTransactions[tx.hash]) {
this._resolvedTransactions[tx.hash].contractAddress = address this._resolvedTransactions[tx.hash].contractAddress = address
} }
return cb() return cb(null, {to: null, contractName: contractName, function: fun, creationAddress: address})
}) })
return return
} }
@ -166,7 +170,8 @@ class TxListener {
var contractName = this._tryResolveContract(code, contracts, 'runtimeBytecode') var contractName = this._tryResolveContract(code, contracts, 'runtimeBytecode')
if (contractName) { if (contractName) {
this._resolvedContracts[tx.to] = contractName this._resolvedContracts[tx.to] = contractName
this._resolveFunction(contractName, contracts, tx, false) var fun = this._resolveFunction(contractName, contracts, tx, false)
return cb(null, {to: tx.to, contractName: contractName, function: fun})
} }
} }
return cb() return cb()
@ -174,16 +179,21 @@ class TxListener {
return return
} }
if (contractName) { if (contractName) {
this._resolveFunction(contractName, contracts, tx, false) var fun = this._resolveFunction(contractName, contracts, tx, false)
return cb(null, {to: tx.to, contractName: contractName, function: fun})
} }
return cb() return cb()
} }
} }
_resolveCreationAddress (tx, cb) { resolveTransactionReceipt (tx, cb) {
if (this._transactionReceipts[tx.hash]) {
return cb(null, this._transactionReceipts[tx.hash])
}
this.currentWeb3().eth.getTransactionReceipt(tx.hash, (error, receipt) => { this.currentWeb3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
if (!error) { if (!error) {
cb(null, receipt.contractAddress) this._transactionReceipts[tx.hash] = receipt
cb(null, receipt)
} else { } else {
cb(error) cb(error)
} }
@ -222,6 +232,7 @@ class TxListener {
params: params params: params
} }
} }
return this._resolvedTransactions[tx.hash]
} }
_tryResolveContract (codeToResolve, compiledContracts, type) { _tryResolveContract (codeToResolve, compiledContracts, type) {

Loading…
Cancel
Save