You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
5.2 KiB
166 lines
5.2 KiB
6 years ago
|
const async = require('async')
|
||
|
const crypto = require('crypto')
|
||
6 years ago
|
|
||
|
class LogsManager {
|
||
|
|
||
6 years ago
|
constructor () {
|
||
6 years ago
|
this.notificationCallbacks = []
|
||
|
this.subscriptions = {}
|
||
6 years ago
|
this.filters = {}
|
||
|
this.filterTracking = {}
|
||
6 years ago
|
this.oldLogs = []
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
checkBlock (blockNumber, block, web3) {
|
||
6 years ago
|
async.eachOf(block.transactions, (tx, i, next) => {
|
||
6 years ago
|
let txHash = '0x' + tx.hash().toString('hex')
|
||
6 years ago
|
|
||
6 years ago
|
web3.eth.getTransactionReceipt(txHash, (_error, receipt) => {
|
||
6 years ago
|
for (let log of receipt.logs) {
|
||
6 years ago
|
this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i })
|
||
6 years ago
|
let subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log })
|
||
|
|
||
6 years ago
|
for (let subscriptionId of subscriptions) {
|
||
|
let result = {
|
||
6 years ago
|
'logIndex': '0x1', // 1
|
||
|
'blockNumber': blockNumber,
|
||
|
'blockHash': ('0x' + block.hash().toString('hex')),
|
||
|
'transactionHash': ('0x' + tx.hash().toString('hex')),
|
||
|
'transactionIndex': '0x' + i.toString(16),
|
||
6 years ago
|
// TODO: if it's a contract deploy, it should be that address instead
|
||
6 years ago
|
'address': log.address,
|
||
|
'data': log.data,
|
||
|
'topics': log.topics
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
if (result.address === '0x') {
|
||
6 years ago
|
delete result.address
|
||
|
}
|
||
|
|
||
6 years ago
|
let response = { 'jsonrpc': '2.0', 'method': 'eth_subscription', params: { 'result': result, 'subscription': subscriptionId } }
|
||
|
this.transmit(response)
|
||
6 years ago
|
}
|
||
6 years ago
|
}
|
||
6 years ago
|
})
|
||
6 years ago
|
}, (_err) => {
|
||
|
})
|
||
6 years ago
|
}
|
||
6 years ago
|
|
||
6 years ago
|
eventMatchesFilter (changeEvent, queryType, queryFilter) {
|
||
6 years ago
|
if (queryFilter.topics.filter((logTopic) => changeEvent.log.topics.indexOf(logTopic) >= 0).length === 0) return false
|
||
|
|
||
|
if (queryType === 'logs') {
|
||
6 years ago
|
if ((queryFilter.address === ('0x' + changeEvent.tx.to.toString('hex'))) && (queryFilter.address === ('0x' + changeEvent.tx.from.toString('hex')))) {
|
||
6 years ago
|
if (!queryFilter.toBlock) {
|
||
6 years ago
|
return true
|
||
6 years ago
|
} else if (parseInt(queryFilter.toBlock) > parseInt(changeEvent.blockNumber)) {
|
||
6 years ago
|
return true
|
||
6 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
return false
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
getSubscriptionsFor (changeEvent) {
|
||
6 years ago
|
let matchedSubscriptions = []
|
||
|
for (let subscriptionId of Object.keys(this.subscriptions)) {
|
||
|
const subscriptionParams = this.subscriptions[subscriptionId]
|
||
|
const [queryType, queryFilter] = subscriptionParams
|
||
6 years ago
|
|
||
6 years ago
|
if (this.eventMatchesFilter(changeEvent, queryType, queryFilter || {topics: []})) {
|
||
6 years ago
|
matchedSubscriptions.push(subscriptionId)
|
||
6 years ago
|
}
|
||
|
}
|
||
6 years ago
|
return matchedSubscriptions
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
getLogsForSubscription (subscriptionId) {
|
||
6 years ago
|
const subscriptionParams = this.subscriptions[subscriptionId]
|
||
6 years ago
|
const [_queryType, queryFilter] = subscriptionParams // eslint-disable-line
|
||
6 years ago
|
|
||
6 years ago
|
return this.getLogsFor(queryFilter)
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
transmit (result) {
|
||
6 years ago
|
this.notificationCallbacks.forEach((callback) => {
|
||
6 years ago
|
if (result.params.result.raw) {
|
||
|
result.params.result.data = result.params.result.raw.data
|
||
|
result.params.result.topics = result.params.result.raw.topics
|
||
|
}
|
||
6 years ago
|
callback(result)
|
||
6 years ago
|
})
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
addListener (_type, cb) {
|
||
6 years ago
|
this.notificationCallbacks.push(cb)
|
||
|
}
|
||
|
|
||
6 years ago
|
subscribe (params) {
|
||
|
let subscriptionId = '0x' + crypto.randomBytes(16).toString('hex')
|
||
6 years ago
|
this.subscriptions[subscriptionId] = params
|
||
|
return subscriptionId
|
||
|
}
|
||
|
|
||
6 years ago
|
unsubscribe (subscriptionId) {
|
||
6 years ago
|
delete this.subscriptions[subscriptionId]
|
||
|
}
|
||
|
|
||
6 years ago
|
newFilter (filterType, params) {
|
||
5 years ago
|
const filterId = '0x' + crypto.randomBytes(16).toString('hex')
|
||
6 years ago
|
if (filterType === 'block' || filterType === 'pendingTransactions') {
|
||
|
this.filters[filterId] = { filterType }
|
||
|
}
|
||
|
if (filterType === 'filter') {
|
||
|
this.filters[filterId] = { filterType, params }
|
||
|
}
|
||
|
this.filterTracking[filterId] = {}
|
||
|
return filterId
|
||
|
}
|
||
|
|
||
|
uninstallFilter (filterId) {
|
||
|
delete this.filters[filterId]
|
||
|
}
|
||
|
|
||
6 years ago
|
getLogsForFilter (filterId, logsOnly) {
|
||
6 years ago
|
const {filterType, params} = this.filter[filterId]
|
||
|
const tracking = this.filterTracking[filterId]
|
||
|
|
||
|
if (logsOnly || filterType === 'filter') {
|
||
|
return this.getLogsFor(params || {topics: []})
|
||
|
}
|
||
|
if (filterType === 'block') {
|
||
6 years ago
|
let blocks = this.oldLogs.filter(x => x.type === 'block').filter(x => tracking.block === undefined || x.blockNumber >= tracking.block)
|
||
6 years ago
|
tracking.block = blocks[blocks.length - 1]
|
||
|
return blocks.map(block => ('0x' + block.hash().toString('hex')))
|
||
|
}
|
||
|
if (filterType === 'pendingTransactions') {
|
||
|
return []
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
getLogsFor (params) {
|
||
6 years ago
|
let results = []
|
||
|
for (let log of this.oldLogs) {
|
||
|
if (this.eventMatchesFilter(log, 'logs', params)) {
|
||
|
results.push({
|
||
6 years ago
|
'logIndex': '0x1', // 1
|
||
|
'blockNumber': log.blockNumber,
|
||
|
'blockHash': ('0x' + log.block.hash().toString('hex')),
|
||
|
'transactionHash': ('0x' + log.tx.hash().toString('hex')),
|
||
|
'transactionIndex': '0x' + log.txNumber.toString(16),
|
||
6 years ago
|
// TODO: if it's a contract deploy, it should be that address instead
|
||
6 years ago
|
'address': log.log.address,
|
||
|
'data': log.log.data,
|
||
|
'topics': log.log.topics
|
||
6 years ago
|
})
|
||
|
}
|
||
|
}
|
||
6 years ago
|
|
||
|
return results
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
6 years ago
|
module.exports = LogsManager
|