Merge pull request #1267 from ethereum/improve_remix_sim3
working websocket support; implement eth_subscribe; eth_unsubscribe; eth_getLogspull/7/head
commit
a57aa65ab5
@ -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