Merge pull request #694 from ethereum/fixCompilationTargets

Fixes for the debugger
pull/5370/head
yann300 4 years ago committed by GitHub
commit 5651a3df1a
  1. 4
      apps/remix-ide/src/app/compiler/compiler-helpers.js
  2. 7
      apps/remix-ide/src/app/compiler/compiler-imports.js
  3. 17
      apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js
  4. 4
      apps/remix-ide/src/app/tabs/debugger-tab.js
  5. 13
      libs/remix-debug/src/code/breakpointManager.ts
  6. 2
      libs/remix-debug/src/debugger/debugger.ts
  7. 48
      libs/remix-debug/src/solidity-decoder/internalCallTree.ts
  8. 2
      libs/remix-debug/src/trace/traceHelper.ts
  9. 8
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx

@ -3,10 +3,10 @@ import { canUseWorker, urlFromVersion } from './compiler-utils'
import { Compiler } from '@remix-project/remix-solidity'
import CompilerAbstract from './compiler-abstract'
export const compile = async (compilationTargets, settings) => {
export const compile = async (compilationTargets, settings, contentResolverCallback) => {
const res = await (() => {
return new Promise((resolve, reject) => {
const compiler = new Compiler(() => {})
const compiler = new Compiler(contentResolverCallback)
compiler.set('evmVersion', settings.evmVersion)
compiler.set('optimize', settings.optimize)
compiler.set('language', settings.language)

@ -12,7 +12,7 @@ const profile = {
name: 'contentImport',
displayName: 'content import',
version: packageJson.version,
methods: ['resolve', 'resolveAndSave']
methods: ['resolve', 'resolveAndSave', 'isExternalUrl']
}
module.exports = class CompilerImports extends Plugin {
@ -30,6 +30,11 @@ module.exports = class CompilerImports extends Plugin {
return /^([^/]+)/.exec(url)
}
isExternalUrl (url) {
const handlers = this.handlers()
return handlers.some(handler => handler.match.exec(url))
}
/**
* resolve the content of @arg url. This only resolves external URLs.
*

@ -92,10 +92,14 @@ export default class FetchAndCompile extends Plugin {
if (url.includes('ipfs')) {
const stdUrl = `ipfs://${url.split('/')[2]}`
const source = await this.call('contentImport', 'resolve', stdUrl)
file = file.replace('browser/', '') // should be fixed in the remix IDE end.
const path = `${targetPath}/${name}/${contractAddress}/${file}`
await this.call('fileManager', 'setFile', path, source.content)
compilationTargets[path] = { content: source.content }
if (await this.call('contentImport', 'isExternalUrl', file)) {
// nothing to do, the compiler callback will handle those
} else {
file = file.replace('browser/', '') // should be fixed in the remix IDE end.
const path = `${targetPath}/${name}/${contractAddress}/${file}`
await this.call('fileManager', 'setFile', path, source.content)
compilationTargets[path] = { content: source.content }
}
break
}
}
@ -111,7 +115,10 @@ export default class FetchAndCompile extends Plugin {
}
try {
setTimeout(_ => this.emit('compiling', settings), 0)
const compData = await compile(compilationTargets, settings)
const compData = await compile(
compilationTargets,
settings,
(url, cb) => this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message)))
compilersartefacts.addResolvedContract(contractAddress, compData)
return compData
} catch (e) {

@ -140,8 +140,8 @@ class DebuggerTab extends ViewPlugin {
fetchContractAndCompile (address, receipt) {
const target = (address && remixDebug.traceHelper.isContractCreation(address)) ? receipt.contractAddress : address
return this.call('fetchAndCompile', 'resolve', target || receipt.contractAddress || receipt.to, '.debug', this.blockchain.web3())
const targetAddress = target || receipt.contractAddress || receipt.to
return this.call('fetchAndCompile', 'resolve', targetAddress, 'browser/.debug', this.blockchain.web3())
}
// debugger () {

@ -15,8 +15,7 @@ export class BreakpointManager {
solidityProxy
breakpoints
locationToRowConverter
previousLine
/**
* constructor
*
@ -92,22 +91,26 @@ export class BreakpointManager {
let previousSourceLocation
let currentStep = fromStep + direction
let lineHadBreakpoint = false
let initialLine
while (currentStep > 0 && currentStep < trace.length) {
try {
previousSourceLocation = sourceLocation
sourceLocation = await this.callTree.extractValidSourceLocation(currentStep)
} catch (e) {
return console.log('cannot jump to breakpoint ' + e)
console.log('cannot jump to breakpoint ' + e)
currentStep += direction
continue
}
const lineColumn = await this.locationToRowConverter(sourceLocation)
if (this.previousLine !== lineColumn.start.line) {
if (!initialLine) initialLine = lineColumn
if (initialLine.start.line !== lineColumn.start.line) {
if (direction === -1 && lineHadBreakpoint) { // TODO : improve this when we will build the correct structure before hand
lineHadBreakpoint = false
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 && this.hitLine(currentStep, sourceLocation, previousSourceLocation, trace)) {

@ -82,7 +82,7 @@ export class Debugger {
}
}
var lineColumnPos = this.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, sources, astSources)
this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources])
this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address])
} else {
this.event.trigger('newSourceLocation', [null])
}

@ -224,7 +224,7 @@ async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
// if not, we are in the current scope.
// We check in `includeVariableDeclaration` if there is a new local variable in scope for this specific `step`
if (tree.includeLocalVariables) {
includeVariableDeclaration(tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation)
await includeVariableDeclaration(tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation)
}
previousSourceLocation = sourceLocation
step++
@ -249,32 +249,36 @@ async function includeVariableDeclaration (tree, step, sourceLocation, scopeId,
const contractObj = await tree.solidityProxy.contractObjectAt(step)
let states = null
const generatedSources = getGeneratedSources(tree, scopeId, contractObj)
const variableDeclaration = resolveVariableDeclaration(tree, sourceLocation, generatedSources)
const variableDeclarations = resolveVariableDeclaration(tree, sourceLocation, generatedSources)
// using the vm trace step, the current source location and the ast,
// we check if the current vm trace step target a new ast node of type VariableDeclaration
// that way we know that there is a new local variable from here.
if (variableDeclaration && !tree.scopes[scopeId].locals[variableDeclaration.name]) {
try {
const stack = tree.traceManager.getStackAt(step)
// the stack length at this point is where the value of the new local variable will be stored.
// so, either this is the direct value, or the offset in memory. That depends on the type.
if (variableDeclaration.name !== '') {
states = tree.solidityProxy.extractStatesDefinitions()
var location = extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location
// we push the new local variable in our tree
tree.scopes[scopeId].locals[variableDeclaration.name] = {
name: variableDeclaration.name,
type: parseType(variableDeclaration.typeDescriptions.typeString, states, contractObj.name, location),
stackDepth: stack.length,
sourceLocation: sourceLocation
if (variableDeclarations && variableDeclarations.length) {
for (const variableDeclaration of variableDeclarations) {
if (variableDeclaration && !tree.scopes[scopeId].locals[variableDeclaration.name]) {
try {
const stack = tree.traceManager.getStackAt(step)
// the stack length at this point is where the value of the new local variable will be stored.
// so, either this is the direct value, or the offset in memory. That depends on the type.
if (variableDeclaration.name !== '') {
states = tree.solidityProxy.extractStatesDefinitions()
var location = extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location
// we push the new local variable in our tree
tree.scopes[scopeId].locals[variableDeclaration.name] = {
name: variableDeclaration.name,
type: parseType(variableDeclaration.typeDescriptions.typeString, states, contractObj.name, location),
stackDepth: stack.length,
sourceLocation: sourceLocation
}
}
} catch (error) {
console.log(error)
}
}
} catch (error) {
console.log(error)
}
}
// we check here if we are at the beginning inside a new function.
// if that is the case, we have to add to locals tree the inputs and output params
const functionDefinition = resolveFunctionDefinition(tree, previousSourceLocation, generatedSources)
@ -351,8 +355,10 @@ function extractVariableDeclarations (ast, astWalker) {
const ret = {}
astWalker.walkFull(ast, (node) => {
if (node.nodeType === 'VariableDeclaration' || node.nodeType === 'YulVariableDeclaration') {
ret[node.src] = node
ret[node.src] = [node]
}
const hasChild = node.initialValue && (node.nodeType === 'VariableDeclarationStatement' || node.nodeType === 'YulVariableDeclarationStatement')
if (hasChild) ret[node.initialValue.src] = node.declarations
})
return ret
}

@ -15,7 +15,7 @@ export function resolveCalledAddress (vmTraceIndex, trace) {
}
export function isCallInstruction (step) {
return step.op === 'CALL' || step.op === 'CALLCODE' || step.op === 'CREATE' || step.op === 'DELEGATECALL'
return ['CALL', 'STATICCALL', 'CALLCODE', 'CREATE', 'DELEGATECALL'].includes(step.op)
}
export function isCreateInstruction (step) {

@ -74,12 +74,11 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
})
})
debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources) => {
debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources, address) => {
if (!lineColumnPos) return
const contracts = await debuggerModule.fetchContractAndCompile(
currentReceipt.contractAddress || currentReceipt.to,
address || currentReceipt.contractAddress || currentReceipt.to,
currentReceipt)
if (contracts) {
let path = contracts.getSourceName(rawLocation.file)
if (!path) {
@ -153,7 +152,8 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
offsetToLineColumnConverter: debuggerModule.offsetToLineColumnConverter,
compilationResult: async (address) => {
try {
return await debuggerModule.fetchContractAndCompile(address, currentReceipt)
const ret = await debuggerModule.fetchContractAndCompile(address, currentReceipt)
return ret
} catch (e) {
console.error(e)
}

Loading…
Cancel
Save