Merge pull request #451 from ethereum/refactor_remix_debug5_ab

misc refactors remix-debug / remix-lib
yann300-patch-10
yann300 4 years ago committed by GitHub
commit 0e91a817e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      apps/remix-ide/src/app/udapp/make-udapp.js
  2. 23
      apps/remix-ide/src/lib/transactionReceiptResolver.js
  3. 5
      libs/remix-debug/src/Ethdebugger.js
  4. 71
      libs/remix-debug/src/code/breakpointManager.js
  5. 11
      libs/remix-debug/src/code/codeManager.js
  6. 24
      libs/remix-debug/src/code/codeResolver.js
  7. 18
      libs/remix-debug/src/debugger/debugger.js
  8. 4
      libs/remix-debug/src/solidity-decoder/decodeInfo.js
  9. 7
      libs/remix-debug/src/solidity-decoder/index.js
  10. 4
      libs/remix-debug/src/solidity-decoder/localDecoder.js
  11. 10
      libs/remix-debug/src/solidity-decoder/solidityProxy.js
  12. 10
      libs/remix-debug/src/solidity-decoder/stateDecoder.js
  13. 3
      libs/remix-debug/src/solidity-decoder/types/Address.js
  14. 12
      libs/remix-debug/src/solidity-decoder/types/ArrayType.js
  15. 33
      libs/remix-debug/src/solidity-decoder/types/DynamicByteArray.js
  16. 11
      libs/remix-debug/src/solidity-decoder/types/Mapping.js
  17. 15
      libs/remix-debug/src/solidity-decoder/types/RefType.js
  18. 6
      libs/remix-debug/src/solidity-decoder/types/StringType.js
  19. 10
      libs/remix-debug/src/solidity-decoder/types/Struct.js
  20. 20
      libs/remix-debug/src/solidity-decoder/types/ValueType.js
  21. 26
      libs/remix-debug/src/solidity-decoder/types/util.js
  22. 5
      libs/remix-debug/src/source/sourceLocationTracker.js
  23. 11
      libs/remix-debug/src/source/sourceMappingDecoder.js
  24. 5
      libs/remix-debug/src/storage/mappingPreimages.js
  25. 8
      libs/remix-debug/test/debugger.js
  26. 9
      libs/remix-debug/test/decoder/localsTests/helper.js
  27. 17
      libs/remix-debug/test/decoder/localsTests/int.js
  28. 16
      libs/remix-debug/test/decoder/localsTests/misc.js
  29. 16
      libs/remix-debug/test/decoder/localsTests/misc2.js
  30. 16
      libs/remix-debug/test/decoder/localsTests/structArray.js
  31. 5
      libs/remix-lib/src/eventManager.js
  32. 6
      libs/remix-lib/src/execution/eventsDecoder.js
  33. 20
      libs/remix-lib/src/execution/txListener.js
  34. 22
      libs/remix-lib/src/execution/txRunner.js
  35. 7
      libs/remix-lib/src/storage.js
  36. 49
      libs/remix-lib/src/universalDapp.js
  37. 5
      libs/remix-lib/src/web3Provider/web3Providers.js
  38. 12
      libs/remix-lib/src/web3Provider/web3VmProvider.js

@ -2,7 +2,6 @@ var registry = require('../../global/registry')
var remixLib = require('@remix-project/remix-lib')
var yo = require('yo-yo')
var EventsDecoder = remixLib.execution.EventsDecoder
var TransactionReceiptResolver = require('../../lib/transactionReceiptResolver')
const transactionDetailsLinks = {
'Main': 'https://www.etherscan.io/tx/',
@ -27,7 +26,19 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
})
// ----------------- Tx listener -----------------
const transactionReceiptResolver = new TransactionReceiptResolver(blockchain)
let _transactionReceipts = {}
const transactionReceiptResolver = (tx, cb) => {
if (_transactionReceipts[tx.hash]) {
return cb(null, _transactionReceipts[tx.hash])
}
blockchain.web3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
if (error) {
return cb(error)
}
_transactionReceipts[tx.hash] = receipt
cb(null, receipt)
})
}
const txlistener = blockchain.getTxListener({
api: {
@ -35,9 +46,7 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
if (compilersArtefacts['__last']) return compilersArtefacts.getAllContractDatas()
return null
},
resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb)
}
resolveReceipt: transactionReceiptResolver
}
})
@ -45,11 +54,7 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
blockchain.startListening(txlistener)
const eventsDecoder = new EventsDecoder({
api: {
resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb)
}
}
resolveReceipt: transactionReceiptResolver
})
txlistener.startListening()
registry.put({api: eventsDecoder, name: 'eventsDecoder'})

@ -1,23 +0,0 @@
'use strict'
module.exports = class TransactionReceiptResolver {
constructor (blockchain) {
this._transactionReceipts = {}
this.blockchain = blockchain
}
resolve (tx, cb) {
if (this._transactionReceipts[tx.hash]) {
return cb(null, this._transactionReceipts[tx.hash])
}
this.blockchain.web3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
if (!error) {
this._transactionReceipts[tx.hash] = receipt
cb(null, receipt)
} else {
cb(error)
}
})
}
}

@ -33,7 +33,7 @@ function Ethdebugger (opts) {
this.traceManager = new TraceManager({web3: this.web3})
this.codeManager = new CodeManager(this.traceManager)
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager)
this.solidityProxy = new SolidityProxy({getCurrentCalledAddressAt: this.traceManager.getCurrentCalledAddressAt.bind(this.traceManager), getCode: this.codeManager.getCode.bind(this.codeManager)})
this.storageResolver = null
this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true })
@ -42,10 +42,11 @@ function Ethdebugger (opts) {
Ethdebugger.prototype.setManagers = function () {
this.traceManager = new TraceManager({web3: this.web3})
this.codeManager = new CodeManager(this.traceManager)
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager)
this.solidityProxy = new SolidityProxy({getCurrentCalledAddressAt: this.traceManager.getCurrentCalledAddressAt.bind(this.traceManager), getCode: this.codeManager.getCode.bind(this.codeManager)})
this.storageResolver = null
this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true })
this.event.trigger('managersChanged')
}
Ethdebugger.prototype.resolveStep = function (index) {

@ -15,13 +15,20 @@ class BreakpointManager {
* @param {Object} _debugger - type of EthDebugger
* @return {Function} _locationToRowConverter - function implemented by editor which return a column/line position for a char source location
*/
constructor (_debugger, _locationToRowConverter, _jumpToCallback) {
constructor ({traceManager, callTree, solidityProxy, locationToRowConverter}) {
this.event = new EventManager()
this.debugger = _debugger
this.traceManager = traceManager
this.callTree = callTree
this.solidityProxy = solidityProxy
this.breakpoints = {}
this.locationToRowConverter = _locationToRowConverter
this.locationToRowConverter = locationToRowConverter
this.previousLine
this.jumpToCallback = _jumpToCallback || (() => {}) // eslint-disable-line
}
setManagers({traceManager, callTree, solidityProxy}) {
this.traceManager = traceManager
this.callTree = callTree
this.solidityProxy = solidityProxy
}
/**
@ -30,7 +37,10 @@ class BreakpointManager {
*
*/
async jumpNextBreakpoint (fromStep, defaultToLimit) {
this.jump(fromStep || 0, 1, defaultToLimit)
if (!this.locationToRowConverter) {
return console.log('row converter not provided')
}
this.jump(fromStep || 0, 1, defaultToLimit, this.traceManager.trace)
}
/**
@ -39,64 +49,61 @@ class BreakpointManager {
*
*/
async jumpPreviousBreakpoint (fromStep, defaultToLimit) {
this.jump(fromStep || 0, -1, defaultToLimit)
}
/**
* start looking for the previous or next breakpoint
* @param {Int} direction - 1 or -1 direction of the search
* @param {Bool} defaultToLimit - if true jump to the limit (end if direction is 1, beginning if direction is -1) of the trace if no more breakpoint found
*
*/
async jump (fromStep, direction, defaultToLimit) {
if (!this.locationToRowConverter) {
console.log('row converter not provided')
return
return console.log('row converter not provided')
}
this.jump(fromStep || 0, -1, defaultToLimit, this.traceManager.trace)
}
function depthChange (step, trace) {
depthChange (step, trace) {
return trace[step].depth !== trace[step - 1].depth
}
function hitLine (currentStep, sourceLocation, previousSourceLocation, self) {
hitLine(currentStep, sourceLocation, previousSourceLocation, trace) {
// isJumpDestInstruction -> returning from a internal function call
// depthChange -> returning from an external call
// sourceLocation.start <= previousSourceLocation.start && ... -> previous src is contained in the current one
if ((helper.isJumpDestInstruction(self.debugger.traceManager.trace[currentStep]) && previousSourceLocation.jump === 'o') ||
depthChange(currentStep, self.debugger.traceManager.trace) ||
if ((helper.isJumpDestInstruction(trace[currentStep]) && previousSourceLocation.jump === 'o') ||
this.depthChange(currentStep, trace) ||
(sourceLocation.start <= previousSourceLocation.start &&
sourceLocation.start + sourceLocation.length >= previousSourceLocation.start + previousSourceLocation.length)) {
return false
}
self.jumpToCallback(currentStep)
self.event.trigger('breakpointHit', [sourceLocation, currentStep])
this.event.trigger('breakpointStep', [currentStep])
this.event.trigger('breakpointHit', [sourceLocation, currentStep])
return true
}
/**
* start looking for the previous or next breakpoint
* @param {Int} direction - 1 or -1 direction of the search
* @param {Bool} defaultToLimit - if true jump to the limit (end if direction is 1, beginning if direction is -1) of the trace if no more breakpoint found
*
*/
async jump (fromStep, direction, defaultToLimit, trace) {
let sourceLocation
let previousSourceLocation
let currentStep = fromStep + direction
let lineHadBreakpoint = false
while (currentStep > 0 && currentStep < this.debugger.traceManager.trace.length) {
while (currentStep > 0 && currentStep < trace.length) {
try {
previousSourceLocation = sourceLocation
sourceLocation = await this.debugger.callTree.extractValidSourceLocation(currentStep)
sourceLocation = await this.callTree.extractValidSourceLocation(currentStep)
} catch (e) {
console.log('cannot jump to breakpoint ' + e)
return
return console.log('cannot jump to breakpoint ' + e)
}
let lineColumn = await this.locationToRowConverter(sourceLocation)
if (this.previousLine !== lineColumn.start.line) {
if (direction === -1 && lineHadBreakpoint) { // TODO : improve this when we will build the correct structure before hand
lineHadBreakpoint = false
if (hitLine(currentStep + 1, previousSourceLocation, sourceLocation, this)) {
if (this.hitLine(currentStep + 1, previousSourceLocation, sourceLocation, trace)) {
return
}
}
this.previousLine = lineColumn.start.line
if (this.hasBreakpointAtLine(sourceLocation.file, lineColumn.start.line)) {
lineHadBreakpoint = true
if (direction === 1 && hitLine(currentStep, sourceLocation, previousSourceLocation, this)) {
if (direction === 1 && this.hitLine(currentStep, sourceLocation, previousSourceLocation, trace)) {
return
}
}
@ -108,9 +115,9 @@ class BreakpointManager {
return
}
if (direction === -1) {
this.jumpToCallback(0)
this.event.trigger('breakpointStep', [0])
} else if (direction === 1) {
this.jumpToCallback(this.debugger.traceManager.trace.length - 1)
this.event.trigger('breakpointStep', [trace.length - 1])
}
}
@ -122,7 +129,7 @@ class BreakpointManager {
* @return {Bool} return true if the given @arg fileIndex @arg line refers to a breakpoint
*/
hasBreakpointAtLine (fileIndex, line) {
const filename = this.debugger.solidityProxy.fileNameFromIndex(fileIndex)
const filename = this.solidityProxy.fileNameFromIndex(fileIndex)
if (!(filename && this.breakpoints[filename])) {
return false
}

@ -16,7 +16,16 @@ function CodeManager (_traceManager) {
this.event = new EventManager()
this.isLoading = false
this.traceManager = _traceManager
this.codeResolver = new CodeResolver({web3: this.traceManager.web3})
this.codeResolver = new CodeResolver({getCode: async (address) => {
return new Promise((resolve, reject) => {
this.traceManager.web3.eth.getCode(address, (error, code) => {
if (error) {
return reject(error)
}
return resolve(code)
})
})
}})
}
/**

@ -1,8 +1,8 @@
'use strict'
const codeUtils = require('./codeUtils')
function CodeResolver (options) {
this.web3 = options.web3
function CodeResolver ({getCode}) {
this.getCode = getCode
this.bytecodeByAddress = {} // bytes code by contract addesses
this.instructionsByAddress = {} // assembly items instructions list by contract addesses
@ -16,20 +16,13 @@ CodeResolver.prototype.clear = function () {
}
CodeResolver.prototype.resolveCode = async function (address) {
return new Promise((resolve, reject) => {
const cache = this.getExecutingCodeFromCache(address)
if (cache) {
return resolve(cache)
return cache
}
this.web3.eth.getCode(address, (error, code) => {
if (error) {
// return console.log(error)
return reject(error)
}
return resolve(this.cacheExecutingCode(address, code))
})
})
const code = await this.getCode(address)
return this.cacheExecutingCode(address, code)
}
CodeResolver.prototype.cacheExecutingCode = function (address, hexCode) {
@ -41,11 +34,8 @@ CodeResolver.prototype.cacheExecutingCode = function (address, hexCode) {
}
CodeResolver.prototype.formatCode = function (hexCode) {
const code = codeUtils.nameOpCodes(Buffer.from(hexCode.substring(2), 'hex'))
return {
code: code[0],
instructionsIndexByBytesOffset: code[1]
}
const [code, instructionsIndexByBytesOffset] = codeUtils.nameOpCodes(Buffer.from(hexCode.substring(2), 'hex'))
return {code, instructionsIndexByBytesOffset}
}
CodeResolver.prototype.getExecutingCodeFromCache = function (address) {

@ -21,12 +21,20 @@ function Debugger (options) {
compilationResult: this.compilationResult
})
this.breakPointManager = new BreakpointManager(this.debugger, async (sourceLocation) => {
const {traceManager, callTree, solidityProxy} = this.debugger
this.breakPointManager = new BreakpointManager({traceManager, callTree, solidityProxy, locationToRowConverter: async (sourceLocation) => {
const compilationResult = await this.compilationResult()
if (!compilationResult) return { start: null, end: null }
return this.offsetToLineColumnConverter.offsetToLineColumn(sourceLocation, sourceLocation.file, compilationResult.source.sources, compilationResult.data.sources)
}, (step) => {
this.event.trigger('breakpointStep', [step])
}})
this.breakPointManager.event.register('managersChanged', () => {
const {traceManager, callTree, solidityProxy} = this.debugger
this.breakPointManager.setManagers({traceManager, callTree, solidityProxy})
})
this.breakPointManager.event.register('breakpointStep', (step) => {
this.step_manager.jumpTo(step)
})
this.debugger.setBreakpointManager(this.breakPointManager)
@ -38,10 +46,6 @@ function Debugger (options) {
this.debugger.event.register('traceUnloaded', this, () => {
this.event.trigger('debuggerStatus', [false])
})
this.event.register('breakpointStep', (step) => {
this.step_manager.jumpTo(step)
})
}
Debugger.prototype.registerAndHighlightCodeItem = async function (index) {

@ -369,8 +369,8 @@ function computeOffsets (types, stateDefinitions, contractName, location) {
}
module.exports = {
parseType: parseType,
computeOffsets: computeOffsets,
parseType,
computeOffsets,
Uint: uint,
Address: address,
Bool: bool,

@ -3,9 +3,4 @@ const stateDecoder = require('./stateDecoder')
const localDecoder = require('./localDecoder')
const InternalCallTree = require('./internalCallTree')
module.exports = {
SolidityProxy: SolidityProxy,
stateDecoder: stateDecoder,
localDecoder: localDecoder,
InternalCallTree: InternalCallTree
}
module.exports = {SolidityProxy, stateDecoder, localDecoder, InternalCallTree}

@ -35,6 +35,4 @@ function formatMemory (memory) {
return memory
}
module.exports = {
solidityLocals: solidityLocals
}
module.exports = {solidityLocals}

@ -6,11 +6,11 @@ const astHelper = require('./astHelper')
const util = remixLib.util
class SolidityProxy {
constructor (traceManager, codeManager) {
constructor ({getCurrentCalledAddressAt, getCode}) {
this.cache = new Cache()
this.reset({})
this.traceManager = traceManager
this.codeManager = codeManager
this.getCurrentCalledAddressAt = getCurrentCalledAddressAt
this.getCode = getCode
}
/**
@ -40,11 +40,11 @@ class SolidityProxy {
* @param {Function} cb - callback returns (error, contractName)
*/
async contractNameAt (vmTraceIndex) {
const address = this.traceManager.getCurrentCalledAddressAt(vmTraceIndex)
const address = this.getCurrentCalledAddressAt(vmTraceIndex)
if (this.cache.contractNameByAddress[address]) {
return this.cache.contractNameByAddress[address]
}
const code = await this.codeManager.getCode(address)
const code = await this.getCode(address)
const contractName = contractNameFromCode(this.contracts, code.bytecode, address)
this.cache.contractNameByAddress[address] = contractName
return contractName

@ -1,5 +1,5 @@
const astHelper = require('./astHelper')
const decodeInfo = require('./decodeInfo')
const {computeOffsets} = require('./decodeInfo')
/**
* decode the contract state storage
@ -40,7 +40,7 @@ function extractStateVariables (contractName, sourcesList) {
return []
}
const types = states[contractName].stateVariables
const offsets = decodeInfo.computeOffsets(types, states, contractName, 'storage')
const offsets = computeOffsets(types, states, contractName, 'storage')
if (!offsets) {
return [] // TODO should maybe return an error
}
@ -64,8 +64,4 @@ async function solidityState (storageResolver, astList, contractName) {
}
}
module.exports = {
solidityState: solidityState,
extractStateVariables: extractStateVariables,
decodeState: decodeState
}
module.exports = {solidityState, extractStateVariables, decodeState}

@ -10,9 +10,8 @@ class Address extends ValueType {
decodeValue (value) {
if (!value) {
return '0x0000000000000000000000000000000000000000'
} else {
return '0x' + util.extractHexByteSlice(value, this.storageBytes, 0).toUpperCase()
}
return '0x' + util.extractHexByteSlice(value, this.storageBytes, 0).toUpperCase()
}
}

@ -69,11 +69,7 @@ class ArrayType extends RefType {
currentLocation.offset = 0
}
}
return {
value: ret,
length: '0x' + size.toString(16),
type: this.typeName
}
return {value: ret, length: '0x' + size.toString(16), type: this.typeName}
}
decodeFromMemoryInternal (offset, memory) {
@ -89,11 +85,7 @@ class ArrayType extends RefType {
ret.push(this.underlyingType.decodeFromMemory(contentOffset, memory))
offset += 32
}
return {
value: ret,
length: '0x' + length.toString(16),
type: this.typeName
}
return {value: ret, length: '0x' + length.toString(16), type: this.typeName}
}
}

@ -16,10 +16,7 @@ class DynamicByteArray extends RefType {
value = await util.extractHexValue(location, storageResolver, this.storageBytes)
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
return {value: '<decoding failed - ' + e.message + '>', type: this.typeName}
}
const bn = new BN(value, 16)
if (bn.testn(0)) {
@ -31,10 +28,7 @@ class DynamicByteArray extends RefType {
currentSlot = await util.readFromStorage(dataPos, storageResolver)
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
return {value: '<decoding failed - ' + e.message + '>', type: this.typeName}
}
while (length.gt(ret.length) && ret.length < 32000) {
currentSlot = currentSlot.replace('0x', '')
@ -44,24 +38,13 @@ class DynamicByteArray extends RefType {
currentSlot = await util.readFromStorage(dataPos, storageResolver)
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
return {value: '<decoding failed - ' + e.message + '>', type: this.typeName}
}
}
return {
value: '0x' + ret.replace(/(00)+$/, ''),
length: '0x' + length.toString(16),
type: this.typeName
}
return {value: '0x' + ret.replace(/(00)+$/, ''), length: '0x' + length.toString(16), type: this.typeName}
} else {
var size = parseInt(value.substr(value.length - 2, 2), 16) / 2
return {
value: '0x' + value.substr(0, size * 2),
length: '0x' + size.toString(16),
type: this.typeName
}
return {value: '0x' + value.substr(0, size * 2), length: '0x' + size.toString(16), type: this.typeName}
}
}
@ -69,11 +52,7 @@ class DynamicByteArray extends RefType {
offset = 2 * offset
let length = memory.substr(offset, 64)
length = 2 * parseInt(length, 16)
return {
length: '0x' + length.toString(16),
value: '0x' + memory.substr(offset + 64, length),
type: this.typeName
}
return {length: '0x' + length.toString(16), value: '0x' + memory.substr(offset + 64, length), type: this.typeName}
}
}

@ -28,20 +28,13 @@ class Mapping extends RefType {
const mappingPreimages = await storageResolver.mappingsLocation(corrections)
let ret = await this.decodeMappingsLocation(mappingPreimages, location, storageResolver) // fetch mapping storage changes
ret = Object.assign({}, this.initialDecodedState, ret) // merge changes
return {
value: ret,
type: this.typeName
}
return {value: ret, type: this.typeName}
}
decodeFromMemoryInternal (offset, memory) {
// mappings can only exist in storage and not in memory
// so this should never be called
return {
value: '<not implemented>',
length: '0x',
type: this.typeName
}
return {value: '<not implemented>', length: '0x', type: this.typeName}
}
async decodeMappingsLocation (preimages, location, storageResolver) {

@ -21,10 +21,7 @@ class RefType {
*/
async decodeFromStack (stackDepth, stack, memory, storageResolver) {
if (stack.length - 1 < stackDepth) {
return {
error: '<decoding failed - stack underflow ' + stackDepth + '>',
type: this.typeName
}
return {error: '<decoding failed - stack underflow ' + stackDepth + '>', type: this.typeName}
}
let offset = stack[stack.length - 1 - stackDepth]
if (this.isInStorage()) {
@ -33,19 +30,13 @@ class RefType {
return await this.decodeFromStorage({ offset: 0, slot: offset }, storageResolver)
} catch (e) {
console.log(e)
return {
error: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
return {error: '<decoding failed - ' + e.message + '>', type: this.typeName}
}
} else if (this.isInMemory()) {
offset = parseInt(offset, 16)
return this.decodeFromMemoryInternal(offset, memory)
} else {
return {
error: '<decoding failed - no decoder for ' + this.location + '>',
type: this.typeName
}
return {error: '<decoding failed - no decoder for ' + this.location + '>', type: this.typeName}
}
}

@ -39,11 +39,7 @@ function format (decoded) {
}
let value = decoded.value
value = value.replace('0x', '').replace(/(..)/g, '%$1')
const ret = {
length: decoded.length,
raw: decoded.value,
type: 'string'
}
const ret = {length: decoded.length, raw: decoded.value, type: 'string'}
try {
ret.value = decodeURIComponent(value)
} catch (e) {

@ -22,10 +22,7 @@ class Struct extends RefType {
ret[item.name] = '<decoding failed - ' + e.message + '>'
}
}
return {
value: ret,
type: this.typeName
}
return {value: ret, type: this.typeName}
}
decodeFromMemoryInternal (offset, memory) {
@ -36,10 +33,7 @@ class Struct extends RefType {
ret[item.name] = member
offset += 32
})
return {
value: ret,
type: this.typeName
}
return {value: ret, type: this.typeName}
}
}

@ -19,16 +19,10 @@ class ValueType {
async decodeFromStorage (location, storageResolver) {
try {
var value = await util.extractHexValue(location, storageResolver, this.storageBytes)
return {
value: this.decodeValue(value),
type: this.typeName
}
return {value: this.decodeValue(value), type: this.typeName}
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
return {value: '<decoding failed - ' + e.message + '>', type: this.typeName}
}
}
@ -47,10 +41,7 @@ class ValueType {
} else {
value = this.decodeValue(stack[stack.length - 1 - stackDepth].replace('0x', ''))
}
return {
value: value,
type: this.typeName
}
return {value, type: this.typeName}
}
/**
@ -62,10 +53,7 @@ class ValueType {
*/
decodeFromMemory (offset, memory) {
let value = memory.substr(2 * offset, 64)
return {
value: this.decodeValue(value),
type: this.typeName
}
return {value: this.decodeValue(value), type: this.typeName}
}
}

@ -2,20 +2,6 @@
const ethutil = require('ethereumjs-util')
const BN = require('ethereumjs-util').BN
module.exports = {
readFromStorage: readFromStorage,
decodeIntFromHex: decodeIntFromHex,
extractHexValue: extractHexValue,
extractHexByteSlice: extractHexByteSlice,
toBN: toBN,
add: add,
sub: sub,
extractLocation: extractLocation,
removeLocation: removeLocation,
normalizeHex: normalizeHex,
extractLocationFromAstVariable: extractLocationFromAstVariable
}
function decodeIntFromHex (value, byteLength, signed) {
let bigNumber = new BN(value, 16)
if (signed) {
@ -24,21 +10,17 @@ function decodeIntFromHex (value, byteLength, signed) {
return bigNumber.toString(10)
}
function readFromStorage (slot, storageResolver) {
function readFromStorage(slot, storageResolver) {
const hexSlot = '0x' + normalizeHex(ethutil.bufferToHex(slot))
return new Promise((resolve, reject) => {
storageResolver.storageSlot(hexSlot, (error, slot) => {
if (error) {
return reject(error)
} else {
if (!slot) {
slot = {
key: slot,
value: ''
}
if (!slot) {
slot = { key: slot, value: '' }
}
return resolve(normalizeHex(slot.value))
}
})
})
}
@ -120,3 +102,5 @@ function normalizeHex (hex) {
}
return hex
}
module.exports = {readFromStorage, decodeIntFromHex, extractHexValue, extractHexByteSlice, toBN, add, sub, extractLocation, removeLocation, normalizeHex, extractLocationFromAstVariable}

@ -88,10 +88,9 @@ function extractSourceMap (self, codeManager, address, contracts) {
const sourceMap = getSourceMap(address, result.bytecode, contracts)
if (sourceMap) {
if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap
resolve(sourceMap)
} else {
reject('no sourcemap associated with the code ' + address)
return resolve(sourceMap)
}
reject('no sourcemap associated with the code ' + address)
}).catch(reject)
})
}

@ -94,12 +94,8 @@ SourceMappingDecoder.prototype.convertOffsetToLineColumn = function (sourceLocat
start: convertFromCharPosition(sourceLocation.start, lineBreakPositions),
end: convertFromCharPosition(sourceLocation.start + sourceLocation.length, lineBreakPositions)
}
} else {
return {
start: null,
end: null
}
}
return {start: null, end: null}
}
/**
@ -119,10 +115,7 @@ function convertFromCharPosition (pos, lineBreakPositions) {
}
const beginColumn = line === 0 ? 0 : (lineBreakPositions[line - 1] + 1)
const column = pos - beginColumn
return {
line: line,
column: column
}
return {line, column}
}
function sourceLocationFromAstNode (astNode) {

@ -51,10 +51,9 @@ function getPreimage (web3, key) {
return new Promise((resolve, reject) => {
web3.debug.preimage(key.indexOf('0x') === 0 ? key : '0x' + key, (error, preimage) => {
if (error) {
resolve(null)
} else {
resolve(preimage)
return resolve(null)
}
resolve(preimage)
})
})
}

@ -273,8 +273,14 @@ function testDebugging (debugManager) {
tape('breakPointManager', (t) => {
t.plan(2)
var sourceMappingDecoder = new SourceMappingDecoder()
var breakPointManager = new BreakpointManager(debugManager, (rawLocation) => {
const {traceManager, callTree, solidityProxy} = debugManager
var breakPointManager = new BreakpointManager({traceManager, callTree, solidityProxy, locationToRowConverter: async (rawLocation) => {
return sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, sourceMappingDecoder.getLinebreakPositions(ballot))
}})
breakPointManager.event.register('managersChanged', () => {
const {traceManager, callTree, solidityProxy} = debugManager
breakPointManager.setManagers({traceManager, callTree, solidityProxy})
})
breakPointManager.add({fileName: 'test.sol', row: 38})

@ -25,13 +25,12 @@ function decodeLocal (st, index, traceManager, callTree, verifier) {
}],
index,
function (error, result) {
if (!error) {
localDecoder.solidityLocals(index, callTree, result[0].value, result[1].value, {}, {start: 5000}).then((locals) => {
if (error) {
return st.fail(error)
}
localDecoder.solidityLocals(index, callTree, result[0].value, result[1].value, {}, { start: 5000 }).then((locals) => {
verifier(locals)
})
} else {
st.fail(error)
}
})
} catch (e) {
st.fail(e.message)

@ -13,19 +13,19 @@ var EventManager = require('../../../src/eventManager')
var helper = require('./helper')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
vmCall.sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, txHash) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
vm.web3.eth.getTransaction(txHash, function (error, tx) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
tx.to = traceHelper.contractCreationToken('0')
var traceManager = new TraceManager({web3: vm.web3})
var traceManager = new TraceManager({ web3: vm.web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy(traceManager, codeManager)
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })
solidityProxy.reset(compilationResult)
var debuggerEvent = new EventManager()
var callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true })
@ -44,6 +44,7 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
st.equals(functions1.length, 1)
st.equals(functions2.length, 2)
st.equals(functions3.length, 0)
st.equals(Object.keys(functions1[0])[0], 'functionDefinition')
st.equals(Object.keys(functions1[0])[1], 'inputs')
st.equals(functions1[0].inputs[0], 'foo')
@ -123,9 +124,7 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
}).catch((error) => {
st.fail(error)
})
}
})
}
})
}

@ -10,19 +10,19 @@ var TraceManager = require('../../../src/trace/traceManager')
var CodeManager = require('../../../src/code/codeManager')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
vmCall.sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, txHash) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
vm.web3.eth.getTransaction(txHash, function (error, tx) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
tx.to = traceHelper.contractCreationToken('0')
var traceManager = new TraceManager({web3: vm.web3})
var traceManager = new TraceManager({ web3: vm.web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy(traceManager, codeManager)
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })
solidityProxy.reset(compilationResult)
var debuggerEvent = new EventManager()
var callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true })
@ -69,8 +69,6 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
}).catch((error) => {
st.fail(error)
})
}
})
}
})
}

@ -11,19 +11,19 @@ var TraceManager = require('../../../src/trace/traceManager')
var CodeManager = require('../../../src/code/codeManager')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
vmCall.sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, txHash) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
vm.web3.eth.getTransaction(txHash, function (error, tx) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
tx.to = traceHelper.contractCreationToken('0')
var traceManager = new TraceManager({web3: vm.web3})
var traceManager = new TraceManager({ web3: vm.web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy(traceManager, codeManager)
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })
solidityProxy.reset(compilationResult)
var debuggerEvent = new EventManager()
var callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true })
@ -56,8 +56,6 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
}).catch((error) => {
st.fail(error)
})
}
})
}
})
}

@ -10,19 +10,19 @@ var TraceManager = require('../../../src/trace/traceManager')
var CodeManager = require('../../../src/code/codeManager')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
vmCall.sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, txHash) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
vm.web3.eth.getTransaction(txHash, function (error, tx) {
if (error) {
st.fail(error)
} else {
return st.fail(error)
}
tx.to = traceHelper.contractCreationToken('0')
var traceManager = new TraceManager({web3: vm.web3})
var traceManager = new TraceManager({ web3: vm.web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy(traceManager, codeManager)
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })
solidityProxy.reset(compilationResult)
var debuggerEvent = new EventManager()
var callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true })
@ -113,8 +113,6 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
}).catch((error) => {
st.fail(error)
})
}
})
}
})
}

@ -44,10 +44,7 @@ eventManager.prototype.register = function (eventName, obj, func) {
func = obj
obj = this.anonymous
}
this.registered[eventName].push({
obj: obj,
func: func
})
this.registered[eventName].push({obj, func})
}
/*

@ -7,8 +7,8 @@ const txHelper = require('./txHelper')
*
*/
class EventsDecoder {
constructor (opt = {}) {
this._api = opt.api
constructor ({resolveReceipt}) {
this.resolveReceipt = resolveReceipt
}
/**
@ -20,7 +20,7 @@ class EventsDecoder {
*/
parseLogs (tx, contractName, compiledContracts, cb) {
if (tx.isCall) return cb(null, { decoded: [], raw: [] })
this._api.resolveReceipt(tx, (error, receipt) => {
this.resolveReceipt(tx, (error, receipt) => {
if (error) return cb(error)
this._decodeLogs(tx, receipt, contractName, compiledContracts, cb)
})

@ -9,6 +9,16 @@ const defaultExecutionContext = require('./execution-context')
const txFormat = require('./txFormat')
const txHelper = require('./txHelper')
function addExecutionCosts(txResult, tx) {
if (txResult && txResult.result) {
if (txResult.result.execResult) {
tx.returnValue = txResult.result.execResult.returnValue
if (txResult.result.execResult.gasUsed) tx.executionCost = txResult.result.execResult.gasUsed.toString(10)
}
if (txResult.result.gasUsed) tx.transactionCost = txResult.result.gasUsed.toString(10)
}
}
/**
* poll web3 each 2s if web3
* listen on transaction executed event if VM
@ -80,16 +90,6 @@ class TxListener {
})
})
})
function addExecutionCosts (txResult, tx) {
if (txResult && txResult.result) {
if (txResult.result.execResult) {
tx.returnValue = txResult.result.execResult.returnValue
if (txResult.result.execResult.gasUsed) tx.executionCost = txResult.result.execResult.gasUsed.toString(10)
}
if (txResult.result.gasUsed) tx.transactionCost = txResult.result.gasUsed.toString(10)
}
}
}
/**

@ -77,22 +77,21 @@ class TxRunner {
}
}
execute (args, confirmationCb, gasEstimationForceSend, promptCb, callback) {
execute(args, confirmationCb, gasEstimationForceSend, promptCb, callback) {
let data = args.data
if (data.slice(0, 2) !== '0x') {
data = '0x' + data
}
if (!this.executionContext.isVM()) {
this.runInNode(args.from, args.to, data, args.value, args.gasLimit, args.useCall, confirmationCb, gasEstimationForceSend, promptCb, callback)
} else {
return this.runInNode(args.from, args.to, data, args.value, args.gasLimit, args.useCall, confirmationCb, gasEstimationForceSend, promptCb, callback)
}
try {
this.runInVm(args.from, args.to, data, args.value, args.gasLimit, args.useCall, args.timestamp, callback)
} catch (e) {
callback(e, null)
}
}
}
runInVm (from, to, data, value, gasLimit, useCall, timestamp, callback) {
const self = this
@ -228,9 +227,8 @@ async function tryTillReceiptAvailable (txhash, executionContext) {
// Try again with a bit of delay if error or if result still null
await pause()
return resolve(await tryTillReceiptAvailable(txhash, executionContext))
} else {
return resolve(receipt)
}
return resolve(receipt)
})
})
}
@ -242,21 +240,20 @@ async function tryTillTxAvailable (txhash, executionContext) {
// Try again with a bit of delay if error or if result still null
await pause()
return resolve(await tryTillTxAvailable(txhash, executionContext))
} else {
return resolve(tx)
}
return resolve(tx)
})
})
}
async function pause () { return new Promise((resolve, reject) => { setTimeout(resolve, 500) }) }
function run (self, tx, stamp, confirmationCb, gasEstimationForceSend, promptCb, callback) {
function run(self, tx, stamp, confirmationCb, gasEstimationForceSend, promptCb, callback) {
if (!self.runAsync && Object.keys(self.pendingTxs).length) {
self.queusTxs.push({ tx, stamp, callback })
} else {
return self.queusTxs.push({ tx, stamp, callback })
}
self.pendingTxs[stamp] = tx
self.execute(tx, confirmationCb, gasEstimationForceSend, promptCb, function(error, result) {
self.execute(tx, confirmationCb, gasEstimationForceSend, promptCb, function (error, result) {
delete self.pendingTxs[stamp]
if (callback && typeof callback === 'function') callback(error, result)
if (self.queusTxs.length) {
@ -264,7 +261,6 @@ function run (self, tx, stamp, confirmationCb, gasEstimationForceSend, promptCb,
run(self, next.tx, next.stamp, next.callback)
}
})
}
}
module.exports = TxRunner

@ -27,10 +27,8 @@ function Storage (prefix) {
this.remove = function (name) {
if (typeof window !== 'undefined') {
window.localStorage.removeItem(prefix + name)
return true
} else {
return true
}
return true
}
this.rename = function (originalName, newName) {
@ -46,9 +44,8 @@ function Storage (prefix) {
// NOTE: this is a workaround for some browsers
if (typeof window !== 'undefined') {
return Object.keys(window.localStorage).filter(function (item) { return item !== null && item !== undefined })
} else {
return []
}
return []
}
this.keys = function () {

@ -91,10 +91,10 @@ module.exports = class UniversalDApp {
if (!this.config.get('settings/personal-mode')) {
return cb('Not running in personal mode')
}
passwordPromptCb((passphrase) => {
return passwordPromptCb((passphrase) => {
this.executionContext.web3().personal.newAccount(passphrase, cb)
})
} else {
}
let privateKey
do {
privateKey = crypto.randomBytes(32)
@ -102,7 +102,6 @@ module.exports = class UniversalDApp {
this._addAccount(privateKey, '0x56BC75E2D63100000')
cb(null, '0x' + privateToAddress(privateKey).toString('hex'))
}
}
/** Add an account to the list of account (only for Javascript VM) */
_addAccount (privateKey, balance) {
@ -110,7 +109,9 @@ module.exports = class UniversalDApp {
throw new Error('_addAccount() cannot be called in non-VM mode')
}
if (this.accounts) {
if (!this.accounts) {
return
}
privateKey = Buffer.from(privateKey, 'hex')
const address = privateToAddress(privateKey)
@ -119,14 +120,13 @@ module.exports = class UniversalDApp {
stateManager.getAccount(address, (error, account) => {
if (error) return console.log(error)
account.balance = balance || '0xf00000000000000001'
stateManager.putAccount(address, account, function cb (error) {
stateManager.putAccount(address, account, function cb(error) {
if (error) console.log(error)
})
})
this.accounts[toChecksumAddress('0x' + address.toString('hex'))] = { privateKey, nonce: 0 }
}
}
/** Return the list of accounts */
getAccounts (cb) {
@ -171,40 +171,36 @@ module.exports = class UniversalDApp {
}
/** Get the balance of an address */
getBalance (address, cb) {
getBalance(address, cb) {
address = stripHexPrefix(address)
if (!this.executionContext.isVM()) {
this.executionContext.web3().eth.getBalance(address, (err, res) => {
return this.executionContext.web3().eth.getBalance(address, (err, res) => {
if (err) {
cb(err)
} else {
cb(null, res.toString(10))
return cb(err)
}
cb(null, res.toString(10))
})
} else {
}
if (!this.accounts) {
return cb('No accounts?')
}
this.executionContext.vm().stateManager.getAccount(Buffer.from(address, 'hex'), (err, res) => {
if (err) {
cb('Account not found')
} else {
cb(null, new BN(res.balance).toString(10))
return cb('Account not found')
}
cb(null, new BN(res.balance).toString(10))
})
}
}
/** Get the balance of an address, and convert wei to ether */
getBalanceInEther (address, callback) {
this.getBalance(address, (error, balance) => {
if (error) {
callback(error)
} else {
callback(null, this.executionContext.web3().utils.fromWei(balance, 'ether'))
return callback(error)
}
callback(null, this.executionContext.web3().utils.fromWei(balance, 'ether'))
})
}
@ -219,10 +215,7 @@ module.exports = class UniversalDApp {
* @param {Function} callback - callback.
*/
createContract (data, confirmationCb, continueCb, promptCb, callback) {
this.runTx({data: data, useCall: false}, confirmationCb, continueCb, promptCb, (error, txResult) => {
// see universaldapp.js line 660 => 700 to check possible values of txResult (error case)
callback(error, txResult)
})
this.runTx({data: data, useCall: false}, confirmationCb, continueCb, promptCb, callback)
}
/**
@ -235,10 +228,7 @@ module.exports = class UniversalDApp {
*/
callFunction (to, data, funAbi, confirmationCb, continueCb, promptCb, callback) {
const useCall = funAbi.stateMutability === 'view' || funAbi.stateMutability === 'pure'
this.runTx({to, data, useCall}, confirmationCb, continueCb, promptCb, (error, txResult) => {
// see universaldapp.js line 660 => 700 to check possible values of txResult (error case)
callback(error, txResult)
})
this.runTx({to, data, useCall}, confirmationCb, continueCb, promptCb, callback)
}
/**
@ -249,10 +239,7 @@ module.exports = class UniversalDApp {
* @param {Function} callback - callback.
*/
sendRawTransaction (to, data, confirmationCb, continueCb, promptCb, callback) {
this.runTx({to, data, useCall: false}, confirmationCb, continueCb, promptCb, (error, txResult) => {
// see universaldapp.js line 660 => 700 to check possible values of txResult (error case)
callback(error, txResult)
})
this.runTx({to, data, useCall: false}, confirmationCb, continueCb, promptCb, callback)
}
context () {

@ -19,10 +19,9 @@ Web3Providers.prototype.addProvider = function (type, obj) {
Web3Providers.prototype.get = function (type, cb) {
if (this.modes[type]) {
cb(null, this.modes[type])
} else {
cb('error: this provider has not been setup (' + type + ')', null)
return cb(null, this.modes[type])
}
cb('error: this provider has not been setup (' + type + ')', null)
}
Web3Providers.prototype.addWeb3 = function (type, web3) {

@ -211,11 +211,10 @@ web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) {
cb(null, this.vmTraces[txHash])
}
return this.vmTraces[txHash]
} else {
}
if (cb) {
cb('unable to retrieve traces ' + txHash, null)
}
}
}
web3VmProvider.prototype.storageRangeAt = function (blockNumber, txIndex, address, start, maxLength, cb) { // txIndex is the hash in the case of the VM
@ -232,9 +231,8 @@ web3VmProvider.prototype.storageRangeAt = function (blockNumber, txIndex, addres
storage: JSON.parse(JSON.stringify(storage)),
nextKey: null
})
} else {
cb('unable to retrieve storage ' + txIndex + ' ' + address)
}
cb('unable to retrieve storage ' + txIndex + ' ' + address)
}
web3VmProvider.prototype.getBlockNumber = function (cb) { cb(null, 'vm provider') }
@ -245,11 +243,10 @@ web3VmProvider.prototype.getTransaction = function (txHash, cb) {
cb(null, this.txs[txHash])
}
return this.txs[txHash]
} else {
}
if (cb) {
cb('unable to retrieve tx ' + txHash, null)
}
}
}
web3VmProvider.prototype.getTransactionReceipt = function (txHash, cb) {
@ -259,11 +256,10 @@ web3VmProvider.prototype.getTransactionReceipt = function (txHash, cb) {
cb(null, this.txsReceipt[txHash])
}
return this.txsReceipt[txHash]
} else {
}
if (cb) {
cb('unable to retrieve txReceipt ' + txHash, null)
}
}
}
web3VmProvider.prototype.getTransactionFromBlock = function (blockNumber, txIndex, cb) {

Loading…
Cancel
Save