Merge pull request #1267 from ethereum/improve_remix_sim3
working websocket support; implement eth_subscribe; eth_unsubscribe; eth_getLogspull/5370/head
commit
2840825079
@ -0,0 +1,123 @@ |
|||||||
|
const async = require('async') |
||||||
|
const crypto = require('crypto') |
||||||
|
|
||||||
|
class LogsManager { |
||||||
|
|
||||||
|
constructor () { |
||||||
|
this.notificationCallbacks = [] |
||||||
|
this.subscriptions = {} |
||||||
|
this.oldLogs = [] |
||||||
|
} |
||||||
|
|
||||||
|
checkBlock (blockNumber, block, web3) { |
||||||
|
async.eachOf(block.transactions, (tx, i, next) => { |
||||||
|
let txHash = '0x' + tx.hash().toString('hex') |
||||||
|
|
||||||
|
web3.eth.getTransactionReceipt(txHash, (_error, receipt) => { |
||||||
|
for (let log of receipt.logs) { |
||||||
|
this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i }) |
||||||
|
let subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log }) |
||||||
|
|
||||||
|
for (let subscriptionId of subscriptions) { |
||||||
|
let 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
|
||||||
|
'address': log.address, |
||||||
|
'data': log.data, |
||||||
|
'topics': log.topics |
||||||
|
} |
||||||
|
|
||||||
|
if (result.address === '0x') { |
||||||
|
delete result.address |
||||||
|
} |
||||||
|
|
||||||
|
let 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') { |
||||||
|
if ((queryFilter.address === ('0x' + changeEvent.tx.to.toString('hex'))) && (queryFilter.address === ('0x' + changeEvent.tx.from.toString('hex')))) { |
||||||
|
if (!queryFilter.toBlock) { |
||||||
|
return true |
||||||
|
} else if (parseInt(queryFilter.toBlock) > parseInt(changeEvent.blockNumber)) { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
getSubscriptionsFor (changeEvent) { |
||||||
|
let matchedSubscriptions = [] |
||||||
|
for (let subscriptionId of Object.keys(this.subscriptions)) { |
||||||
|
const subscriptionParams = this.subscriptions[subscriptionId] |
||||||
|
const [queryType, queryFilter] = subscriptionParams |
||||||
|
|
||||||
|
if (this.eventMatchesFilter(changeEvent, queryType, queryFilter)) { |
||||||
|
matchedSubscriptions.push(subscriptionId) |
||||||
|
} |
||||||
|
} |
||||||
|
return matchedSubscriptions |
||||||
|
} |
||||||
|
|
||||||
|
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) { |
||||||
|
let subscriptionId = '0x' + crypto.randomBytes(16).toString('hex') |
||||||
|
this.subscriptions[subscriptionId] = params |
||||||
|
return subscriptionId |
||||||
|
} |
||||||
|
|
||||||
|
unsubscribe (subscriptionId) { |
||||||
|
delete this.subscriptions[subscriptionId] |
||||||
|
} |
||||||
|
|
||||||
|
getLogsFor (params) { |
||||||
|
let results = [] |
||||||
|
for (let log of this.oldLogs) { |
||||||
|
if (this.eventMatchesFilter(log, 'logs', params)) { |
||||||
|
results.push({ |
||||||
|
'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 |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return results |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = LogsManager |
@ -0,0 +1,32 @@ |
|||||||
|
var RemixLib = require('remix-lib') |
||||||
|
var executionContext = RemixLib.execution.executionContext |
||||||
|
|
||||||
|
var Filters = function (_options) { |
||||||
|
// const options = _options || {}
|
||||||
|
} |
||||||
|
|
||||||
|
Filters.prototype.methods = function () { |
||||||
|
return { |
||||||
|
eth_getLogs: this.eth_getLogs.bind(this), |
||||||
|
eth_subscribe: this.eth_subscribe.bind(this), |
||||||
|
eth_unsubscribe: this.eth_unsubscribe.bind(this) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
||||||
|
Filters.prototype.eth_getLogs = function (payload, cb) { |
||||||
|
let results = executionContext.logsManager.getLogsFor(payload.params[0]) |
||||||
|
cb(null, results) |
||||||
|
} |
||||||
|
|
||||||
|
Filters.prototype.eth_subscribe = function (payload, cb) { |
||||||
|
let subscriptionId = executionContext.logsManager.subscribe(payload.params) |
||||||
|
cb(null, subscriptionId) |
||||||
|
} |
||||||
|
|
||||||
|
Filters.prototype.eth_unsubscribe = function (payload, cb) { |
||||||
|
executionContext.logsManager.unsubscribe(payload.params[0]) |
||||||
|
cb(null, true) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = Filters |
Loading…
Reference in new issue