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 remixLib = require('@remix-project/remix-lib')
var yo = require('yo-yo') var yo = require('yo-yo')
var EventsDecoder = remixLib.execution.EventsDecoder var EventsDecoder = remixLib.execution.EventsDecoder
var TransactionReceiptResolver = require('../../lib/transactionReceiptResolver')
const transactionDetailsLinks = { const transactionDetailsLinks = {
'Main': 'https://www.etherscan.io/tx/', 'Main': 'https://www.etherscan.io/tx/',
@ -27,7 +26,19 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
}) })
// ----------------- Tx listener ----------------- // ----------------- 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({ const txlistener = blockchain.getTxListener({
api: { api: {
@ -35,9 +46,7 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
if (compilersArtefacts['__last']) return compilersArtefacts.getAllContractDatas() if (compilersArtefacts['__last']) return compilersArtefacts.getAllContractDatas()
return null return null
}, },
resolveReceipt: function (tx, cb) { resolveReceipt: transactionReceiptResolver
transactionReceiptResolver.resolve(tx, cb)
}
} }
}) })
@ -45,11 +54,7 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
blockchain.startListening(txlistener) blockchain.startListening(txlistener)
const eventsDecoder = new EventsDecoder({ const eventsDecoder = new EventsDecoder({
api: { resolveReceipt: transactionReceiptResolver
resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb)
}
}
}) })
txlistener.startListening() txlistener.startListening()
registry.put({api: eventsDecoder, name: 'eventsDecoder'}) 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.traceManager = new TraceManager({web3: this.web3})
this.codeManager = new CodeManager(this.traceManager) 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.storageResolver = null
this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true }) 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 () { Ethdebugger.prototype.setManagers = function () {
this.traceManager = new TraceManager({web3: this.web3}) this.traceManager = new TraceManager({web3: this.web3})
this.codeManager = new CodeManager(this.traceManager) 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.storageResolver = null
this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true }) this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true })
this.event.trigger('managersChanged')
} }
Ethdebugger.prototype.resolveStep = function (index) { Ethdebugger.prototype.resolveStep = function (index) {

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

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

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

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

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

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

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

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

@ -10,9 +10,8 @@ class Address extends ValueType {
decodeValue (value) { decodeValue (value) {
if (!value) { if (!value) {
return '0x0000000000000000000000000000000000000000' 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 currentLocation.offset = 0
} }
} }
return { return {value: ret, length: '0x' + size.toString(16), type: this.typeName}
value: ret,
length: '0x' + size.toString(16),
type: this.typeName
}
} }
decodeFromMemoryInternal (offset, memory) { decodeFromMemoryInternal (offset, memory) {
@ -89,11 +85,7 @@ class ArrayType extends RefType {
ret.push(this.underlyingType.decodeFromMemory(contentOffset, memory)) ret.push(this.underlyingType.decodeFromMemory(contentOffset, memory))
offset += 32 offset += 32
} }
return { return {value: ret, length: '0x' + length.toString(16), type: this.typeName}
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) value = await util.extractHexValue(location, storageResolver, this.storageBytes)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
return { return {value: '<decoding failed - ' + e.message + '>', type: this.typeName}
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
} }
const bn = new BN(value, 16) const bn = new BN(value, 16)
if (bn.testn(0)) { if (bn.testn(0)) {
@ -31,10 +28,7 @@ class DynamicByteArray extends RefType {
currentSlot = await util.readFromStorage(dataPos, storageResolver) currentSlot = await util.readFromStorage(dataPos, storageResolver)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
return { return {value: '<decoding failed - ' + e.message + '>', type: this.typeName}
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
} }
while (length.gt(ret.length) && ret.length < 32000) { while (length.gt(ret.length) && ret.length < 32000) {
currentSlot = currentSlot.replace('0x', '') currentSlot = currentSlot.replace('0x', '')
@ -44,24 +38,13 @@ class DynamicByteArray extends RefType {
currentSlot = await util.readFromStorage(dataPos, storageResolver) currentSlot = await util.readFromStorage(dataPos, storageResolver)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
return { return {value: '<decoding failed - ' + e.message + '>', type: this.typeName}
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
} }
} }
return { return {value: '0x' + ret.replace(/(00)+$/, ''), length: '0x' + length.toString(16), type: this.typeName}
value: '0x' + ret.replace(/(00)+$/, ''),
length: '0x' + length.toString(16),
type: this.typeName
}
} else { } else {
var size = parseInt(value.substr(value.length - 2, 2), 16) / 2 var size = parseInt(value.substr(value.length - 2, 2), 16) / 2
return { return {value: '0x' + value.substr(0, size * 2), length: '0x' + size.toString(16), type: this.typeName}
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 offset = 2 * offset
let length = memory.substr(offset, 64) let length = memory.substr(offset, 64)
length = 2 * parseInt(length, 16) length = 2 * parseInt(length, 16)
return { return {length: '0x' + length.toString(16), value: '0x' + memory.substr(offset + 64, length), type: this.typeName}
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) const mappingPreimages = await storageResolver.mappingsLocation(corrections)
let ret = await this.decodeMappingsLocation(mappingPreimages, location, storageResolver) // fetch mapping storage changes let ret = await this.decodeMappingsLocation(mappingPreimages, location, storageResolver) // fetch mapping storage changes
ret = Object.assign({}, this.initialDecodedState, ret) // merge changes ret = Object.assign({}, this.initialDecodedState, ret) // merge changes
return { return {value: ret, type: this.typeName}
value: ret,
type: this.typeName
}
} }
decodeFromMemoryInternal (offset, memory) { decodeFromMemoryInternal (offset, memory) {
// mappings can only exist in storage and not in memory // mappings can only exist in storage and not in memory
// so this should never be called // so this should never be called
return { return {value: '<not implemented>', length: '0x', type: this.typeName}
value: '<not implemented>',
length: '0x',
type: this.typeName
}
} }
async decodeMappingsLocation (preimages, location, storageResolver) { async decodeMappingsLocation (preimages, location, storageResolver) {

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

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

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

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

@ -2,20 +2,6 @@
const ethutil = require('ethereumjs-util') const ethutil = require('ethereumjs-util')
const BN = require('ethereumjs-util').BN 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) { function decodeIntFromHex (value, byteLength, signed) {
let bigNumber = new BN(value, 16) let bigNumber = new BN(value, 16)
if (signed) { if (signed) {
@ -24,21 +10,17 @@ function decodeIntFromHex (value, byteLength, signed) {
return bigNumber.toString(10) return bigNumber.toString(10)
} }
function readFromStorage (slot, storageResolver) { function readFromStorage(slot, storageResolver) {
const hexSlot = '0x' + normalizeHex(ethutil.bufferToHex(slot)) const hexSlot = '0x' + normalizeHex(ethutil.bufferToHex(slot))
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
storageResolver.storageSlot(hexSlot, (error, slot) => { storageResolver.storageSlot(hexSlot, (error, slot) => {
if (error) { if (error) {
return reject(error) return reject(error)
} else {
if (!slot) {
slot = {
key: slot,
value: ''
} }
if (!slot) {
slot = { key: slot, value: '' }
} }
return resolve(normalizeHex(slot.value)) return resolve(normalizeHex(slot.value))
}
}) })
}) })
} }
@ -120,3 +102,5 @@ function normalizeHex (hex) {
} }
return 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) const sourceMap = getSourceMap(address, result.bytecode, contracts)
if (sourceMap) { if (sourceMap) {
if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap
resolve(sourceMap) return resolve(sourceMap)
} else {
reject('no sourcemap associated with the code ' + address)
} }
reject('no sourcemap associated with the code ' + address)
}).catch(reject) }).catch(reject)
}) })
} }

@ -94,12 +94,8 @@ SourceMappingDecoder.prototype.convertOffsetToLineColumn = function (sourceLocat
start: convertFromCharPosition(sourceLocation.start, lineBreakPositions), start: convertFromCharPosition(sourceLocation.start, lineBreakPositions),
end: convertFromCharPosition(sourceLocation.start + sourceLocation.length, 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 beginColumn = line === 0 ? 0 : (lineBreakPositions[line - 1] + 1)
const column = pos - beginColumn const column = pos - beginColumn
return { return {line, column}
line: line,
column: column
}
} }
function sourceLocationFromAstNode (astNode) { function sourceLocationFromAstNode (astNode) {

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

@ -273,8 +273,14 @@ function testDebugging (debugManager) {
tape('breakPointManager', (t) => { tape('breakPointManager', (t) => {
t.plan(2) t.plan(2)
var sourceMappingDecoder = new SourceMappingDecoder() 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)) 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}) breakPointManager.add({fileName: 'test.sol', row: 38})

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

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

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

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

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

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

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

@ -9,6 +9,16 @@ const defaultExecutionContext = require('./execution-context')
const txFormat = require('./txFormat') const txFormat = require('./txFormat')
const txHelper = require('./txHelper') 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 * poll web3 each 2s if web3
* listen on transaction executed event if VM * 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 let data = args.data
if (data.slice(0, 2) !== '0x') { if (data.slice(0, 2) !== '0x') {
data = '0x' + data data = '0x' + data
} }
if (!this.executionContext.isVM()) { if (!this.executionContext.isVM()) {
this.runInNode(args.from, args.to, data, args.value, args.gasLimit, args.useCall, confirmationCb, gasEstimationForceSend, promptCb, callback) return this.runInNode(args.from, args.to, data, args.value, args.gasLimit, args.useCall, confirmationCb, gasEstimationForceSend, promptCb, callback)
} else { }
try { try {
this.runInVm(args.from, args.to, data, args.value, args.gasLimit, args.useCall, args.timestamp, callback) this.runInVm(args.from, args.to, data, args.value, args.gasLimit, args.useCall, args.timestamp, callback)
} catch (e) { } catch (e) {
callback(e, null) callback(e, null)
} }
} }
}
runInVm (from, to, data, value, gasLimit, useCall, timestamp, callback) { runInVm (from, to, data, value, gasLimit, useCall, timestamp, callback) {
const self = this 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 // Try again with a bit of delay if error or if result still null
await pause() await pause()
return resolve(await tryTillReceiptAvailable(txhash, executionContext)) 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 // Try again with a bit of delay if error or if result still null
await pause() await pause()
return resolve(await tryTillTxAvailable(txhash, executionContext)) return resolve(await tryTillTxAvailable(txhash, executionContext))
} else {
return resolve(tx)
} }
return resolve(tx)
}) })
}) })
} }
async function pause () { return new Promise((resolve, reject) => { setTimeout(resolve, 500) }) } 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) { if (!self.runAsync && Object.keys(self.pendingTxs).length) {
self.queusTxs.push({ tx, stamp, callback }) return self.queusTxs.push({ tx, stamp, callback })
} else { }
self.pendingTxs[stamp] = tx 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] delete self.pendingTxs[stamp]
if (callback && typeof callback === 'function') callback(error, result) if (callback && typeof callback === 'function') callback(error, result)
if (self.queusTxs.length) { if (self.queusTxs.length) {
@ -264,7 +261,6 @@ function run (self, tx, stamp, confirmationCb, gasEstimationForceSend, promptCb,
run(self, next.tx, next.stamp, next.callback) run(self, next.tx, next.stamp, next.callback)
} }
}) })
}
} }
module.exports = TxRunner module.exports = TxRunner

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

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

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

@ -211,11 +211,10 @@ web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) {
cb(null, this.vmTraces[txHash]) cb(null, this.vmTraces[txHash])
} }
return this.vmTraces[txHash] return this.vmTraces[txHash]
} else { }
if (cb) { if (cb) {
cb('unable to retrieve traces ' + txHash, null) 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 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)), storage: JSON.parse(JSON.stringify(storage)),
nextKey: null 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') } web3VmProvider.prototype.getBlockNumber = function (cb) { cb(null, 'vm provider') }
@ -245,11 +243,10 @@ web3VmProvider.prototype.getTransaction = function (txHash, cb) {
cb(null, this.txs[txHash]) cb(null, this.txs[txHash])
} }
return this.txs[txHash] return this.txs[txHash]
} else { }
if (cb) { if (cb) {
cb('unable to retrieve tx ' + txHash, null) cb('unable to retrieve tx ' + txHash, null)
} }
}
} }
web3VmProvider.prototype.getTransactionReceipt = function (txHash, cb) { web3VmProvider.prototype.getTransactionReceipt = function (txHash, cb) {
@ -259,11 +256,10 @@ web3VmProvider.prototype.getTransactionReceipt = function (txHash, cb) {
cb(null, this.txsReceipt[txHash]) cb(null, this.txsReceipt[txHash])
} }
return this.txsReceipt[txHash] return this.txsReceipt[txHash]
} else { }
if (cb) { if (cb) {
cb('unable to retrieve txReceipt ' + txHash, null) cb('unable to retrieve txReceipt ' + txHash, null)
} }
}
} }
web3VmProvider.prototype.getTransactionFromBlock = function (blockNumber, txIndex, cb) { web3VmProvider.prototype.getTransactionFromBlock = function (blockNumber, txIndex, cb) {

Loading…
Cancel
Save