diff --git a/libs/remix-simulator/src/VmProxy.ts b/libs/remix-simulator/src/VmProxy.ts index f7090d8b1d..dcc834b617 100644 --- a/libs/remix-simulator/src/VmProxy.ts +++ b/libs/remix-simulator/src/VmProxy.ts @@ -3,7 +3,7 @@ const { hexListFromBNs, formatMemory } = util import { helpers } from '@remix-project/remix-lib' const { normalizeHexAddress } = helpers.ui import { ConsoleLogs } from '@remix-project/remix-lib' -import { toChecksumAddress, BN, bufferToHex, Address } from 'ethereumjs-util' +import { toChecksumAddress, BN, keccak, bufferToHex, Address, toBuffer } from 'ethereumjs-util' import Web3 from 'web3' import { ethers } from 'ethers' import { VMContext } from './vm-context' @@ -40,7 +40,6 @@ export class VmProxy { utils txsMapBlock blocks - latestBlockNumber constructor (vmContext: VMContext) { this.vmContext = vmContext @@ -62,6 +61,7 @@ export class VmProxy { this.eth.getTransactionReceipt = (txHash, cb) => this.getTransactionReceipt(txHash, cb) this.eth.getTransactionFromBlock = (blockNumber, txIndex, cb) => this.getTransactionFromBlock(blockNumber, txIndex, cb) this.eth.getBlockNumber = (cb) => this.getBlockNumber(cb) + this.eth.getStorageAt = (address: string, position: string, blockNumber: string, cb) => this.getStorageAt(address, position, blockNumber, cb) this.debug.traceTransaction = (txHash, options, cb) => this.traceTransaction(txHash, options, cb) this.debug.storageRangeAt = (blockNumber, txIndex, address, start, maxLength, cb) => this.storageRangeAt(blockNumber, txIndex, address, start, maxLength, cb) this.debug.preimage = (hashedKey, cb) => this.preimage(hashedKey, cb) @@ -83,7 +83,6 @@ export class VmProxy { this.utils = Web3.utils || [] this.txsMapBlock = {} this.blocks = {} - this.latestBlockNumber = 0 } setVM (vm) { @@ -132,6 +131,7 @@ export class VmProxy { this.txs[this.processingHash] = tx this.txsReceipt[this.processingHash] = tx this.storageCache[this.processingHash] = {} + this.storageCache['after_' + this.processingHash] = {} if (data.to) { try { const storage = await this.vm.stateManager.dumpStorage(data.to) @@ -175,6 +175,17 @@ export class VmProxy { const status = data.execResult.exceptionError ? 0 : 1 this.txsReceipt[this.processingHash].status = `0x${status}` + const to = this.txs[this.processingHash].to + if (to) { + try { + const account = Address.fromString(to) + const storage = await this.vm.stateManager.dumpStorage(account) + this.storageCache['after_' + this.processingHash][to] = storage + } catch (e) { + console.log(e) + } + } + if (data.createdAddress) { const address = data.createdAddress.toString() this.vmTraces[this.processingHash].return = toChecksumAddress(address) @@ -294,19 +305,31 @@ export class VmProxy { } } - storageRangeAt (blockNumber, txIndex, address, start, maxLength, cb) { + getStorageAt (address: string, position: string, blockNumber: string, cb) { // we don't use the range params here address = toChecksumAddress(address) + + blockNumber = blockNumber === 'latest' ? this.vmContext.latestBlockNumber : blockNumber - let txHash - if (txIndex === 'latest') { - txHash = this.lastProcessedStorageTxHash[address] - } else { - const block = this.vmContext.blocks[blockNumber] - txHash = '0x' + block.transactions[txIndex].hash().toString('hex') + const block = this.vmContext.blocks[blockNumber] + const txHash = '0x' + block.transactions[block.transactions.length - 1].hash().toString('hex') + + if (this.storageCache['after_' + txHash] && this.storageCache['after_' + txHash][address]) { + const slot = '0x' + keccak(toBuffer(ethers.utils.hexZeroPad(position, 32))).toString('hex') + const storage = this.storageCache['after_' + txHash][address] + return cb(null, storage[slot].value) } - - + // Before https://github.com/ethereum/remix-project/pull/1703, it used to throw error as + // 'unable to retrieve storage ' + txIndex + ' ' + address + cb(null, { storage: {} }) + } + + storageRangeAt (blockNumber, txIndex, address, start, maxLength, cb) { + // we don't use the range params here + address = toChecksumAddress(address) + + const block = this.vmContext.blocks[blockNumber] + const txHash = '0x' + block.transactions[txIndex].hash().toString('hex') if (this.storageCache[txHash] && this.storageCache[txHash][address]) { const storage = this.storageCache[txHash][address] diff --git a/libs/remix-simulator/src/methods/blocks.ts b/libs/remix-simulator/src/methods/blocks.ts index e2594b05ac..cc6f96f042 100644 --- a/libs/remix-simulator/src/methods/blocks.ts +++ b/libs/remix-simulator/src/methods/blocks.ts @@ -1,7 +1,7 @@ import Web3 from 'web3' - +import { VMContext } from '../vm-context' export class Blocks { - vmContext + vmContext: VMContext coinbase: string TX_INDEX = '0x0' // currently there's always only 1 tx per block, so the transaction index will always be 0x0 constructor (vmContext, _options) { @@ -73,7 +73,7 @@ export class Blocks { stateRoot: this.toHex(block.header.stateRoot), miner: this.coinbase, difficulty: this.toHex(block.header.difficulty), - totalDifficulty: this.toHex(block.header.totalDifficulty), + totalDifficulty: this.toHex((block.header as any).totalDifficulty), extraData: this.toHex(block.header.extraData), size: '0x027f07', // 163591 gasLimit: this.toHex(block.header.gasLimit), @@ -127,7 +127,7 @@ export class Blocks { stateRoot: this.toHex(block.header.stateRoot), miner: this.coinbase, difficulty: this.toHex(block.header.difficulty), - totalDifficulty: this.toHex(block.header.totalDifficulty), + totalDifficulty: this.toHex((block.header as any).totalDifficulty), extraData: this.toHex(block.header.extraData), size: '0x027f07', // 163591 gasLimit: this.toHex(block.header.gasLimit), @@ -173,15 +173,10 @@ export class Blocks { } eth_getStorageAt (payload, cb) { - const [address, position, blockNumber] = payload.params - - this.vmContext.web3().debug.storageRangeAt(blockNumber, 'latest', address.toLowerCase(), position, 1, (err, result) => { - if (err || (result.storage && Object.values(result.storage).length === 0)) { - return cb(err, '') - } - - const value = Object.values(result.storage)[0]['value'] - cb(err, value) - }) + return this.vmContext.web3().eth.getStorageAt( + payload.params[0], + payload.params[1], + payload.params[2], + cb) } } diff --git a/libs/remix-simulator/test/blocks.ts b/libs/remix-simulator/test/blocks.ts index 47e7f8ba9e..5ffb448070 100644 --- a/libs/remix-simulator/test/blocks.ts +++ b/libs/remix-simulator/test/blocks.ts @@ -212,13 +212,13 @@ describe('blocks', () => { let storage = await web3.eth.getStorageAt(contractInstance.options.address, 0) assert.deepEqual(storage, '0x64') - await contractInstance.methods.set(200).send({ from: accounts[0], gas: 400000 }) + await contractInstance.methods.set(200).send({ from: accounts[0].toLowerCase(), gas: 400000 }) storage = await web3.eth.getStorageAt(contractInstance.options.address, 0) - assert.deepEqual(storage, '0x64') + assert.deepEqual(storage, '0xc8') - await contractInstance.methods.set(200).send({ from: accounts[0], gas: 400000 }) + await contractInstance.methods.set(1).send({ from: accounts[0].toLowerCase(), gas: 400000 }) storage = await web3.eth.getStorageAt(contractInstance.options.address, 0) - assert.deepEqual(storage, '0xc8') + assert.deepEqual(storage, '0x01') }) }) describe('eth_call', () => {