Unverified Commit 16cea52a authored by Iuri Matias's avatar Iuri Matias Committed by GitHub

Merge pull request #1272 from ethereum/improve_remix_sim4

Implement filters; add more tests; eth_getStorageAt
parents 299b25b8 1a890d28
......@@ -115,6 +115,7 @@ function ExecutionContext () {
this.blockGasLimit = this.blockGasLimitDefault
this.customNetWorks = {}
this.blocks = {}
this.latestBlockNumber = 0
this.txs = {}
this.init = function (config) {
......@@ -309,6 +310,7 @@ function ExecutionContext () {
self.blocks['0x' + block.hash().toString('hex')] = block
self.blocks[blockNumber] = block
self.latestBlockNumber = blockNumber
this.logsManager.checkBlock(blockNumber, block, this.web3())
}
......
......@@ -6,6 +6,8 @@ class LogsManager {
constructor () {
this.notificationCallbacks = []
this.subscriptions = {}
this.filters = {}
this.filterTracking = {}
this.oldLogs = []
}
......@@ -66,13 +68,20 @@ class LogsManager {
const subscriptionParams = this.subscriptions[subscriptionId]
const [queryType, queryFilter] = subscriptionParams
if (this.eventMatchesFilter(changeEvent, queryType, queryFilter)) {
if (this.eventMatchesFilter(changeEvent, queryType, queryFilter || {topics: []})) {
matchedSubscriptions.push(subscriptionId)
}
}
return matchedSubscriptions
}
getLogsForSubscription (subscriptionId) {
const subscriptionParams = this.subscriptions[subscriptionId]
const [_queryType, queryFilter] = subscriptionParams // eslint-disable-line
return this.getLogsFor(queryFilter)
}
transmit (result) {
this.notificationCallbacks.forEach((callback) => {
if (result.params.result.raw) {
......@@ -97,6 +106,39 @@ class LogsManager {
delete this.subscriptions[subscriptionId]
}
newFilter (filterType, params) {
const filterId = '0x' + crypto.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]
}
getLogsForFilter (filterId, logsOnly) {
const {filterType, params} = this.filter[filterId]
const tracking = this.filterTracking[filterId]
if (logsOnly || filterType === 'filter') {
return this.getLogsFor(params || {topics: []})
}
if (filterType === 'block') {
let 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 []
}
}
getLogsFor (params) {
let results = []
for (let log of this.oldLogs) {
......
......@@ -43,7 +43,7 @@ module.exports = {
* @param {Function} finalCallback - last callback.
*/
callFunction: function (from, to, data, value, gasLimit, funAbi, txRunner, callbacks, finalCallback) {
var tx = { from: from, to: to, data: data, useCall: false, value: value, gasLimit: gasLimit }
var tx = { from: from, to: to, data: data, useCall: funAbi.constant, value: value, gasLimit: gasLimit }
txRunner.rawRun(tx, callbacks.confirmationCb, callbacks.gasEstimationForceSend, callbacks.promptCb, (error, txResult) => {
// see universaldapp.js line 660 => 700 to check possible values of txResult (error case)
finalCallback(error, txResult)
......
......@@ -29,6 +29,7 @@ function web3VmProvider () {
this.providers = { 'HttpProvider': function (url) {} }
this.currentProvider = {'host': 'vm provider'}
this.storageCache = {}
this.lastProcessedStorageTxHash = {}
this.sha3Preimages = {}
// util
this.sha3 = function () { return self.web3.sha3.apply(self.web3, arguments) }
......@@ -92,6 +93,7 @@ web3VmProvider.prototype.txWillProcess = function (self, data) {
const account = ethutil.toBuffer(tx.to)
self.vm.stateManager.dumpStorage(account, function (storage) {
self.storageCache[self.processingHash][tx.to] = storage
self.lastProcessedStorageTxHash[tx.to] = self.processingHash
})
}
this.processingIndex = 0
......@@ -171,12 +173,14 @@ web3VmProvider.prototype.pushTrace = function (self, data) {
if (step.op === 'CREATE') {
this.processingAddress = traceHelper.contractCreationToken(this.processingIndex)
this.storageCache[this.processingHash][this.processingAddress] = {}
this.lastProcessedStorageTxHash[this.processingAddress] = this.processingHash
} else {
this.processingAddress = uiutil.normalizeHexAddress(step.stack[step.stack.length - 2])
if (!self.storageCache[self.processingHash][this.processingAddress]) {
const account = ethutil.toBuffer(this.processingAddress)
self.vm.stateManager.dumpStorage(account, function (storage) {
self.storageCache[self.processingHash][self.processingAddress] = storage
self.lastProcessedStorageTxHash[self.processingAddress] = self.processingHash
})
}
}
......@@ -217,6 +221,11 @@ web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) {
web3VmProvider.prototype.storageRangeAt = function (blockNumber, txIndex, address, start, maxLength, cb) { // txIndex is the hash in the case of the VM
// we don't use the range params here
if (txIndex === 'latest') {
txIndex = this.lastProcessedStorageTxHash[address]
}
if (this.storageCache[txIndex] && this.storageCache[txIndex][address]) {
var storage = this.storageCache[txIndex][address]
return cb(null, {
......
......@@ -16,7 +16,7 @@ Implemented:
* [~] eth_accounts
* [X] eth_blockNumber
* [X] eth_getBalance
* [_] eth_getStorageAt
* [~] eth_getStorageAt
* [X] eth_getTransactionCount
* [X] eth_getBlockTransactionCountByHash
* [X] eth_getBlockTransactionCountByNumber
......@@ -40,12 +40,12 @@ Implemented:
* [X] eth_compileSolidity (DEPRECATED)
* [X] eth_compileLLL (DEPRECATED)
* [X] eth_compileSerpent (DEPRECATED)
* [_] eth_newFilter
* [_] eth_newBlockFilter
* [_] eth_newPendingTransactionFilter
* [_] eth_uninstallFilter
* [_] eth_getFilterChanges
* [_] eth_getFilterLogs
* [X] eth_newFilter
* [X] eth_newBlockFilter
* [X] eth_newPendingTransactionFilter
* [X] eth_uninstallFilter
* [~] eth_getFilterChanges
* [~] eth_getFilterLogs
* [X] eth_getLogs
* [_] eth_getWork
* [_] eth_submitWork
......@@ -55,18 +55,6 @@ Implemented:
* [_] db_getString
* [_] db_putHex
* [_] db_getHex
* [X] shh_version
* [_] shh_post
* [_] shh_newIdentity
* [_] shh_hasIdentity
* [_] shh_newGroup
* [_] shh_addToGroup
* [_] shh_newFilter
* [_] shh_uninstallFilter
* [_] shh_getFilterChanges
* [_] shh_getMessages
* [_] bzz_hive (stub)
* [_] bzz_info (stub)
* [_] debug_traceTransaction
* [X] eth_subscribe
* [X] eth_unsubscribe
......@@ -79,5 +67,3 @@ Implemented:
* [_] personal_unlockAccount
* [_] personal_sendTransaction
* [_] rpc_modules
* [_] web3_clientVersion
* [_] web3_sha3
......@@ -24,12 +24,14 @@ program
.option('-b, --ip [host]', 'specify host')
.option('-c, --coinbase [coinbase]', 'specify host')
.option('--rpc', 'run rpc server only')
.option('--details', 'display payloads for every requests and their responses')
.parse(process.argv)
const Server = require('../src/server')
const server = new Server({
coinbase: program.coinbase || "0x0000000000000000000000000000000000000000",
rpc: program.rpc
rpc: program.rpc,
logDetails: program.details
})
server.start(program.host || '127.0.0.1', program.port || 8545)
......@@ -29,7 +29,7 @@
"remix-lib": "0.4.14",
"standard": "^10.0.3",
"time-stamp": "^2.0.0",
"web3": "^1.0.0-beta.37"
"web3": "1.0.0-beta.37"
},
"devDependencies": {
"@babel/core": "^7.4.5",
......
......@@ -20,7 +20,7 @@ Accounts.prototype.init = async function () {
this.accountsKeys[ethJSUtil.toChecksumAddress(account.address)] = account.privateKey
this.accounts[ethJSUtil.toChecksumAddress(account.address)] = { privateKey: Buffer.from(account.privateKey.replace('0x', ''), 'hex'), nonce: 0 }
executionContext.vm().stateManager.getAccount(Buffer.from(account.address.toLowerCase().replace('0x', ''), 'hex'), (err, account) => {
executionContext.vm().stateManager.getAccount(Buffer.from(account.address.replace('0x', ''), 'hex'), (err, account) => {
if (err) {
throw new Error(err)
}
......@@ -61,13 +61,16 @@ Accounts.prototype.eth_getBalance = function (payload, cb) {
}
Accounts.prototype.eth_sign = function (payload, cb) {
let address = payload.params[0]
let message = payload.params[1]
const address = payload.params[0]
const message = payload.params[1]
let privateKey = this.accountsKeys[address]
let account = Web3.eth.accounts.privateKeyToAccount(privateKey)
const privateKey = this.accountsKeys[ethJSUtil.toChecksumAddress(address)]
if (!privateKey) {
return cb(new Error('unknown account'))
}
const account = this.web3.eth.accounts.privateKeyToAccount(privateKey)
let data = account.sign(message)
const data = account.sign(message)
cb(null, data.signature)
}
......
......@@ -17,12 +17,18 @@ Blocks.prototype.methods = function () {
eth_getBlockTransactionCountByHash: this.eth_getBlockTransactionCountByHash.bind(this),
eth_getBlockTransactionCountByNumber: this.eth_getBlockTransactionCountByNumber.bind(this),
eth_getUncleCountByBlockHash: this.eth_getUncleCountByBlockHash.bind(this),
eth_getUncleCountByBlockNumber: this.eth_getUncleCountByBlockNumber.bind(this)
eth_getUncleCountByBlockNumber: this.eth_getUncleCountByBlockNumber.bind(this),
eth_getStorageAt: this.eth_getStorageAt.bind(this)
}
}
Blocks.prototype.eth_getBlockByNumber = function (payload, cb) {
var block = executionContext.blocks[payload.params[0]]
let blockIndex = payload.params[0]
if (blockIndex === 'latest') {
blockIndex = executionContext.latestBlockNumber
}
const block = executionContext.blocks[blockIndex]
if (!block) {
return cb(new Error('block not found'))
......@@ -117,4 +123,17 @@ Blocks.prototype.eth_getUncleCountByBlockNumber = function (payload, cb) {
cb(null, 0)
}
Blocks.prototype.eth_getStorageAt = function (payload, cb) {
const [address, position, blockNumber] = payload.params
executionContext.web3().debug.storageRangeAt(blockNumber, 'latest', address.toLowerCase(), position, 1, (err, result) => {
if (err || (result.storage && Object.values(result.storage).length === 0)) {
return cb(err, '')
}
let value = Object.values(result.storage)[0].value
cb(err, value)
})
}
module.exports = Blocks
......@@ -13,7 +13,6 @@ Filters.prototype.methods = function () {
}
}
// 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)
......@@ -29,4 +28,36 @@ Filters.prototype.eth_unsubscribe = function (payload, cb) {
cb(null, true)
}
Filters.prototype.eth_newFilter = function (payload, cb) {
const filterId = executionContext.logsManager.newFilter('filter', payload.params[0])
cb(null, filterId)
}
Filters.prototype.eth_newBlockFilter = function (payload, cb) {
const filterId = executionContext.logsManager.newFilter('block')
cb(null, filterId)
}
Filters.prototype.eth_newPendingTransactionFilter = function (payload, cb) {
const filterId = executionContext.logsManager.newFilter('pendingTransactions')
cb(null, filterId)
}
Filters.prototype.eth_uninstallfilter = function (payload, cb) {
const result = executionContext.logsManager.uninstallFilter(payload.params[0])
cb(null, result)
}
Filters.prototype.eth_getFilterChanges = function (payload, cb) {
const filterId = payload.params[0]
let results = executionContext.logsManager.getLogsForFilter(filterId)
cb(null, results)
}
Filters.prototype.eth_getFilterLogs = function (payload, cb) {
const filterId = payload.params[0]
let results = executionContext.logsManager.getLogsForFilter(filterId, true)
cb(null, results)
}
module.exports = Filters
......@@ -53,6 +53,10 @@ Transactions.prototype.eth_getTransactionReceipt = function (payload, cb) {
'status': receipt.status
}
if (r.blockNumber === '0x') {
r.blockNumber = '0x0'
}
cb(null, r)
})
}
......@@ -78,6 +82,12 @@ Transactions.prototype.eth_call = function (payload, cb) {
if (payload.params && payload.params.length > 0 && payload.params[0].from) {
payload.params[0].from = ethJSUtil.toChecksumAddress(payload.params[0].from)
}
if (payload.params && payload.params.length > 0 && payload.params[0].to) {
payload.params[0].to = ethJSUtil.toChecksumAddress(payload.params[0].to)
}
payload.params[0].value = undefined
processTx(this.accounts, payload, true, cb)
}
......@@ -130,6 +140,10 @@ Transactions.prototype.eth_getTransactionByHash = function (payload, cb) {
r.value = '0x0'
}
if (r.blockNumber === '0x') {
r.blockNumber = '0x0'
}
cb(null, r)
})
}
......
......@@ -16,7 +16,7 @@ function runCall (payload, from, to, data, value, gasLimit, txRunner, callbacks,
return callback(null, toReturn)
}
TxExecution.callFunction(from, to, data, value, gasLimit, null, txRunner, callbacks, finalCallback, true)
TxExecution.callFunction(from, to, data, value, gasLimit, {constant: true}, txRunner, callbacks, finalCallback, true)
}
function runTx (payload, from, to, data, value, gasLimit, txRunner, callbacks, callback) {
......@@ -27,7 +27,7 @@ function runTx (payload, from, to, data, value, gasLimit, txRunner, callbacks, c
callback(null, result.transactionHash)
}
TxExecution.callFunction(from, to, data, value, gasLimit, null, txRunner, callbacks, finalCallback, false)
TxExecution.callFunction(from, to, data, value, gasLimit, {constant: false}, txRunner, callbacks, finalCallback, false)
}
function createContract (payload, from, data, value, gasLimit, txRunner, callbacks, callback) {
......
var Whisper = function () {
}
Whisper.prototype.methods = function () {
return {
shh_version: this.shh_version.bind(this)
}
}
Whisper.prototype.shh_version = function (payload, cb) {
cb(null, 5)
}
module.exports = Whisper
......@@ -10,11 +10,11 @@ const Filters = require('./methods/filters.js')
const Misc = require('./methods/misc.js')
const Net = require('./methods/net.js')
const Transactions = require('./methods/transactions.js')
const Whisper = require('./methods/whisper.js')
const generateBlock = require('./genesis.js')
var Provider = function (options) {
this.options = options || {}
this.Accounts = new Accounts()
this.Transactions = new Transactions()
......@@ -24,10 +24,10 @@ var Provider = function (options) {
this.methods = merge(this.methods, (new Misc()).methods())
this.methods = merge(this.methods, (new Filters()).methods())
this.methods = merge(this.methods, (new Net()).methods())
this.methods = merge(this.methods, (this.Transactions.methods()))
this.methods = merge(this.methods, (new Whisper()).methods())
this.methods = merge(this.methods, this.Transactions.methods())
generateBlock()
this.init()
}
Provider.prototype.init = async function () {
......@@ -39,8 +39,15 @@ Provider.prototype.sendAsync = function (payload, callback) {
log.info('payload method is ', payload.method)
let method = this.methods[payload.method]
if (this.options.logDetails) {
log.info(payload)
}
if (method) {
return method.call(method, payload, (err, result) => {
if (this.options.logDetails) {
log.info(err)
log.info(result)
}
if (err) {
return callback(err)
}
......
......@@ -54,7 +54,12 @@ class Server {
})
}
app.listen(port, host, () => log('Remix Simulator listening on port ' + host + ':' + port))
app.listen(port, host, () => {
log('Remix Simulator listening on ws://' + host + ':' + port)
if (!this.rpcOnly) {
log('http json-rpc is deprecated and disabled by default. To enable it use --rpc')
}
})
}
}
......
......@@ -10,8 +10,32 @@ describe('Accounts', function () {
web3.setProvider(provider)
})
it('should get a list of accounts', async function () {
let accounts = await web3.eth.getAccounts()
assert.notEqual(accounts.length, 0)
describe('eth_getAccounts', () => {
it('should get a list of accounts', async function () {
let accounts = await web3.eth.getAccounts()
assert.notEqual(accounts.length, 0)
})
})
describe('eth_getBalance', () => {
it('should get a account balance', async function () {
let accounts = await web3.eth.getAccounts()
let balance0 = await web3.eth.getBalance(accounts[0])
let balance1 = await web3.eth.getBalance(accounts[1])
let balance2 = await web3.eth.getBalance(accounts[2])
assert.deepEqual(balance0, '100000000000000000000')
assert.deepEqual(balance1, '100000000000000000000')
assert.deepEqual(balance2, '100000000000000000000')
})
})
describe('eth_sign', () => {
it('should sign payloads', async function () {
let accounts = await web3.eth.getAccounts()
let signature = await web3.eth.sign('Hello world', accounts[0])
assert.deepEqual(signature.length, 132)
})
})
})
This diff is collapsed.
......@@ -10,47 +10,103 @@ describe('Misc', function () {
web3.setProvider(provider)
})
it('should get correct remix simulator version', async function (done) {
web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, version) => {
if (err) {
throw new Error(err)
}
let remixVersion = require('../package.json').version
assert.equal(version, 'Remix Simulator/' + remixVersion)
done()
describe('web3_clientVersion', () => {
it('should get correct remix simulator version', async function (done) {
web3._requestManager.send({ method: 'web3_clientVersion', params: [] }, (err, version) => {
if (err) {
throw new Error(err)
}
let remixVersion = require('../package.json').version
assert.equal(version, 'Remix Simulator/' + remixVersion)
done()
})
})
})
it('should get protocol version', async function () {
web3._requestManager.send({method: 'eth_protocolVersion', params: []}, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, '0x3f')
describe('eth_protocolVersion', () => {
it('should get protocol version', async function () {
web3._requestManager.send({ method: 'eth_protocolVersion', params: [] }, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, '0x3f')
})
})
})
it('should get if is syncing', async function () {
let isSyncing = await web3.eth.isSyncing()
assert.equal(isSyncing, false)
describe('eth_syncing', () => {
it('should get if is syncing', async function () {
let isSyncing = await web3.eth.isSyncing()
assert.equal(isSyncing, false)
})
})
describe('eth_mining', () => {
it('should get if is mining', async function () {
let isMining = await web3.eth.isMining()
assert.equal(isMining, false)
})
})
it('should get if is mining', async function () {
let isMining = await web3.eth.isMining()
assert.equal(isMining, false)
describe('eth_hashrate', () => {
it('should get hashrate', async function () {
let hashrate = await web3.eth.getHashrate()
assert.equal(hashrate, 0)
})
})
describe('web3_sha3', () => {
it('should get result of a sha3', async function () {
web3._requestManager.send({ method: 'web3_sha3', params: ['0x68656c6c6f20776f726c64'] }, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, '0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad')
})
})
})
it('should get hashrate', async function () {
let hashrate = await web3.eth.getHashrate()
assert.equal(hashrate, 0)
describe('eth_getCompilers', () => {
it('should get list of compilers', async function () {
web3._requestManager.send({ method: 'eth_getCompilers', params: [] }, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, 0)
})
})
})
describe('eth_compileSolidity', () => {
it('get unsupported result when requesting solidity compiler', async function () {
web3._requestManager.send({ method: 'eth_compileSolidity', params: [] }, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, 'unsupported')
})
})
})
describe('eth_compileLLL', () => {
it('get unsupported result when requesting LLL compiler', async function () {
web3._requestManager.send({ method: 'eth_compileLLL', params: [] }, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, 'unsupported')
})
})
})
it('should get result of a sha3', async function () {
web3._requestManager.send({method: 'web3_sha3', params: ['0x68656c6c6f20776f726c64']}, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, '0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad')
describe('eth_compileSerpent', () => {
it('get unsupported result when requesting serpent compiler', async function () {
web3._requestManager.send({ method: 'eth_compileSerpent', params: [] }, (err, result) => {
if (err) {
throw new Error(err)
}
assert.equal(result, 'unsupported')
})
})
})
})
/* global describe, before, it */
var Web3 = require('web3')
var RemixSim = require('../index.js')
let web3 = new Web3()
var assert = require('assert')
describe('Whisper', function () {
before(function () {
let provider = new RemixSim.Provider()
web3.setProvider(provider)
})
it('should get correct remix simulator version', async function () {
let version = await web3.shh.getVersion()
assert.equal(version, 5)
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment