remix-project mirror
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.
remix-project/libs/remix-lib/src/execution/logsManager.ts

185 lines
6.0 KiB

import { eachOf } from 'async'
import { randomBytes } from 'crypto'
export class LogsManager {
notificationCallbacks
subscriptions
filters
filterTracking
oldLogs
constructor () {
this.notificationCallbacks = []
this.subscriptions = {}
this.filters = {}
this.filterTracking = {}
this.oldLogs = []
}
checkBlock (blockNumber, block, web3) {
eachOf(block.transactions, (tx, i, next) => {
4 years ago
const txHash = '0x' + tx.hash().toString('hex')
web3.eth.getTransactionReceipt(txHash, (_error, receipt) => {
4 years ago
for (const log of receipt.logs) {
this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i })
4 years ago
const subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log })
for (const subscriptionId of subscriptions) {
const result = {
logIndex: '0x1', // 1
blockNumber: blockNumber,
blockHash: ('0x' + block.hash().toString('hex')),
transactionHash: ('0x' + tx.hash().toString('hex')),
transactionIndex: '0x' + i.toString(16),
// TODO: if it's a contract deploy, it should be that address instead
4 years ago
address: log.address,
data: log.data,
topics: log.topics
}
if (result.address === '0x') {
delete result.address
}
4 years ago
const response = { jsonrpc: '2.0', method: 'eth_subscription', params: { result: result, subscription: subscriptionId } }
this.transmit(response)
}
}
})
}, (_err) => {
})
}
eventMatchesFilter (changeEvent, queryType, queryFilter) {
if (queryFilter.topics.filter((logTopic) => changeEvent.log.topics.indexOf(logTopic) >= 0).length === 0) return false
if (queryType === 'logs') {
const fromBlock = queryFilter.fromBlock || '0x0'
const toBlock = queryFilter.toBlock || this.oldLogs.length ? this.oldLogs[this.oldLogs.length - 1].blockNumber : '0x0'
if ((queryFilter.address === (changeEvent.tx.to || '').toString()) || queryFilter.address === (changeEvent.tx.getSenderAddress().toString())) {
if ((parseInt(toBlock) >= parseInt(changeEvent.blockNumber)) && (parseInt(fromBlock) <= parseInt(changeEvent.blockNumber))) {
return true
}
}
}
return false
}
getSubscriptionsFor (changeEvent) {
4 years ago
const matchedSubscriptions = []
for (const subscriptionId of Object.keys(this.subscriptions)) {
const subscriptionParams = this.subscriptions[subscriptionId]
const [queryType, queryFilter] = subscriptionParams
4 years ago
if (this.eventMatchesFilter(changeEvent, queryType, queryFilter || { topics: [] })) {
matchedSubscriptions.push(subscriptionId)
}
}
return matchedSubscriptions
}
6 years ago
getLogsForSubscription (subscriptionId) {
const subscriptionParams = this.subscriptions[subscriptionId]
6 years ago
const [_queryType, queryFilter] = subscriptionParams // eslint-disable-line
6 years ago
return this.getLogsFor(queryFilter)
}
transmit (result) {
this.notificationCallbacks.forEach((callback) => {
if (result.params.result.raw) {
result.params.result.data = result.params.result.raw.data
result.params.result.topics = result.params.result.raw.topics
}
callback(result)
})
}
addListener (_type, cb) {
this.notificationCallbacks.push(cb)
}
subscribe (params) {
4 years ago
const subscriptionId = '0x' + randomBytes(16).toString('hex')
this.subscriptions[subscriptionId] = params
return subscriptionId
}
unsubscribe (subscriptionId) {
delete this.subscriptions[subscriptionId]
}
newFilter (filterType, params) {
const filterId = '0x' + randomBytes(16).toString('hex')
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) {
4 years ago
const { filterType, params } = this.filters[filterId]
const tracking = this.filterTracking[filterId]
if (logsOnly || filterType === 'filter') {
4 years ago
return this.getLogsFor(params || { topics: [] })
}
if (filterType === 'block') {
4 years ago
const blocks = this.oldLogs.filter(x => x.type === 'block').filter(x => tracking.block === undefined || x.blockNumber >= tracking.block)
tracking.block = blocks[blocks.length - 1]
return blocks.map(block => ('0x' + block.hash().toString('hex')))
}
if (filterType === 'pendingTransactions') {
return []
}
}
getLogsByTxHash (hash) {
return this.oldLogs.filter((log) => '0x' + log.tx.hash().toString('hex') === hash)
3 years ago
.map((log) => {
return {
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),
// TODO: if it's a contract deploy, it should be that address instead
address: log.log.address,
data: log.log.data,
topics: log.log.topics
}
})
}
getLogsFor (params) {
4 years ago
const results = []
for (const log of this.oldLogs) {
if (this.eventMatchesFilter(log, 'logs', params)) {
results.push({
4 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),
// TODO: if it's a contract deploy, it should be that address instead
4 years ago
address: log.log.address,
data: log.log.data,
topics: log.log.topics
})
}
}
return results
}
}