gas cost per line

pull/3068/head
yann300 2 years ago
parent 11b7e038bb
commit ef4e096554
  1. 10
      apps/debugger/src/app/debugger-api.ts
  2. 10
      libs/remix-debug/src/Ethdebugger.ts
  3. 12
      libs/remix-debug/src/debugger/debugger.ts
  4. 25
      libs/remix-debug/src/solidity-decoder/internalCallTree.ts
  5. 7
      libs/remix-debug/src/solidity-decoder/solidityProxy.ts
  6. 5
      libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx
  7. 9
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  8. 2
      libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts

@ -1,13 +1,7 @@
import Web3 from 'web3'
import remixDebug, { TransactionDebugger as Debugger } from '@remix-project/remix-debug'
<<<<<<< HEAD
import { CompilerAbstract } from '@remix-project/remix-solidity'
=======
import { CompilationOutput, Sources } from '@remix-ui/debugger-ui'
import { lineText } from '@remix-ui/editor'
import type { CompilationResult } from '@remix-project/remix-solidity-ts'
>>>>>>> show inline gas cost
export const DebuggerApiMixin = (Base) => class extends Base {
@ -48,9 +42,9 @@ export const DebuggerApiMixin = (Base) => class extends Base {
await this.call('editor', 'discardLineTexts' as any)
}
async highlight (lineColumnPos, path, rawLocation, stepDetail) {
async highlight (lineColumnPos, path, rawLocation, stepDetail, lineGasCost) {
await this.call('editor', 'highlight', lineColumnPos, path, '', { focus: true })
const label = `${stepDetail.op} costs ${stepDetail.gasCost} gas - ${stepDetail.gas} gas left`
const label = `${stepDetail.op} costs ${stepDetail.gasCost} gas - this line costs ${lineGasCost} gas - ${stepDetail.gas} total gas left`
const linetext: lineText = {
content: label,
position: lineColumnPos,

@ -32,9 +32,11 @@ export class Ethdebugger {
storageResolver
callTree
breakpointManager
offsetToLineColumnConverter
constructor (opts) {
this.compilationResult = opts.compilationResult || function (contractAddress) { return null }
this.offsetToLineColumnConverter = opts.offsetToLineColumnConverter
this.web3 = opts.web3
this.opts = opts
@ -49,7 +51,8 @@ export class Ethdebugger {
this.traceManager,
this.solidityProxy,
this.codeManager,
{ ...opts, includeLocalVariables })
{ ...opts, includeLocalVariables },
this.offsetToLineColumnConverter)
}
setManagers () {
@ -63,7 +66,8 @@ export class Ethdebugger {
this.traceManager,
this.solidityProxy,
this.codeManager,
{ ...this.opts, includeLocalVariables })
{ ...this.opts, includeLocalVariables },
this.offsetToLineColumnConverter)
}
resolveStep (index) {
@ -71,7 +75,7 @@ export class Ethdebugger {
}
setCompilationResult (compilationResult) {
this.solidityProxy.reset((compilationResult && compilationResult.data) || {})
this.solidityProxy.reset((compilationResult && compilationResult.data) || {}, (compilationResult && compilationResult.source && compilationResult.source.sources) || {})
}
async sourceLocationFromVMTraceIndex (address, stepIndex) {

@ -26,7 +26,8 @@ export class Debugger {
this.debugger = new Ethdebugger({
web3: options.web3,
debugWithGeneratedSources: options.debugWithGeneratedSources,
compilationResult: this.compilationResult
compilationResult: this.compilationResult,
offsetToLineColumnConverter: this.offsetToLineColumnConverter
})
const { traceManager, callTree, solidityProxy } = this.debugger
@ -90,7 +91,14 @@ export class Debugger {
}
}
const lineColumnPos = await this.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, sources, astSources)
this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address, stepDetail])
let lineGasCost = -1
try {
lineGasCost = await this.debugger.callTree.getGasCostPerLine(rawLocation.file, lineColumnPos.start.line)
} catch (e) {
console.log(e)
}
this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address, stepDetail, lineGasCost])
this.vmDebuggerLogic.event.trigger('sourceLocationChanged', [rawLocation])
} else {
this.event.trigger('newSourceLocation', [null])

@ -41,6 +41,8 @@ export class InternalCallTree {
locationAndOpcodePerVMTraceIndex: {
[Key: number]: any
}
gasCostPerLine
offsetToLineColumnConverter
/**
* constructor
@ -51,12 +53,13 @@ export class InternalCallTree {
* @param {Object} codeManager - code manager
* @param {Object} opts - { includeLocalVariables, debugWithGeneratedSources }
*/
constructor (debuggerEvent, traceManager, solidityProxy, codeManager, opts) {
constructor (debuggerEvent, traceManager, solidityProxy, codeManager, opts, offsetToLineColumnConverter?) {
this.includeLocalVariables = opts.includeLocalVariables
this.debugWithGeneratedSources = opts.debugWithGeneratedSources
this.event = new EventManager()
this.solidityProxy = solidityProxy
this.traceManager = traceManager
this.offsetToLineColumnConverter = offsetToLineColumnConverter
this.sourceLocationTracker = new SourceLocationTracker(codeManager, { debugWithGeneratedSources: opts.debugWithGeneratedSources })
debuggerEvent.register('newTraceLoaded', (trace) => {
this.reset()
@ -99,6 +102,7 @@ export class InternalCallTree {
this.functionCallStack = []
this.functionDefinitionsByScope = {}
this.scopeStarts = {}
this.gasCostPerLine = {}
this.variableDeclarationByFile = {}
this.functionDefinitionByFile = {}
this.astWalker = new AstWalker()
@ -181,6 +185,13 @@ export class InternalCallTree {
async getValidSourceLocationFromVMTraceIndexFromCache (address: string, step: number, contracts: any) {
return await this.sourceLocationTracker.getValidSourceLocationFromVMTraceIndexFromCache(address, step, contracts, this.locationAndOpcodePerVMTraceIndex)
}
async getGasCostPerLine(file: number, line: number) {
if (this.gasCostPerLine[file] && this.gasCostPerLine[file][line]) {
return this.gasCostPerLine[file][line]
}
throw new Error('Could not find gas cost per line')
}
}
async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
@ -211,6 +222,7 @@ async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
let newLocation = false
try {
sourceLocation = await tree.extractSourceLocation(step)
if (!includedSource(sourceLocation, currentSourceLocation)) {
tree.reducedTrace.push(step)
currentSourceLocation = sourceLocation
@ -229,7 +241,16 @@ async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
}
tree.locationAndOpcodePerVMTraceIndex[step] = { sourceLocation, stepDetail }
tree.scopes[scopeId].gasCost += stepDetail.gasCost
console.log(step, stepDetail.op, stepDetail.gas, nextStepDetail.gas)
// gas per line
if (tree.offsetToLineColumnConverter) {
try {
const lineColumnPos = await tree.offsetToLineColumnConverter.offsetToLineColumn(sourceLocation, sourceLocation.file, tree.solidityProxy.sourcesCode, tree.solidityProxy.sources)
if (!tree.gasCostPerLine[sourceLocation.file]) tree.gasCostPerLine[sourceLocation.file] = {}
if (!tree.gasCostPerLine[sourceLocation.file][lineColumnPos.start.line]) tree.gasCostPerLine[sourceLocation.file][lineColumnPos.start.line] = 0
tree.gasCostPerLine[sourceLocation.file][lineColumnPos.start.line] += stepDetail.gasCost
} catch (e) {}
}
const isCallInstrn = isCallInstruction(stepDetail)
const isCreateInstrn = isCreateInstruction(stepDetail)

@ -10,6 +10,8 @@ export class SolidityProxy {
getCode
sources
contracts
compilationResult
sourcesCode
constructor ({ getCurrentCalledAddressAt, getCode }) {
this.cache = new Cache()
@ -23,9 +25,10 @@ export class SolidityProxy {
*
* @param {Object} compilationResult - result os a compilatiion (diectly returned by the compiler)
*/
reset (compilationResult) {
this.sources = compilationResult.sources
reset (compilationResult, sources?) {
this.sources = compilationResult.sources // ast
this.contracts = compilationResult.contracts
if (sources) this.sourcesCode = sources
this.cache.reset()
}

@ -1,6 +1,11 @@
import React, { useContext, useEffect, useState } from 'react'
import { AppContext } from '../../context/context'
import { useDialogDispatchers } from '../../context/provider'
declare global {
interface Window {
_paq: any
}
}
const _paq = window._paq = window._paq || []
const MatomoDialog = (props) => {

@ -121,7 +121,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
})
})
debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources, address, stepDetail) => {
debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources, address, stepDetail, lineGasCost) => {
if (!lineColumnPos) {
await debuggerModule.discardHighlight()
setState(prevState => {
@ -158,7 +158,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
return { ...prevState, sourceLocationStatus: '' }
})
await debuggerModule.discardHighlight()
await debuggerModule.highlight(lineColumnPos, path, rawLocation, stepDetail)
await debuggerModule.highlight(lineColumnPos, path, rawLocation, stepDetail, lineGasCost)
}
}
})
@ -266,13 +266,14 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
console.log(e.message)
}
const localCache = {}
const debuggerInstance = new Debugger({
web3,
offsetToLineColumnConverter: debuggerModule.offsetToLineColumnConverter,
compilationResult: async (address) => {
try {
const ret = await debuggerModule.fetchContractAndCompile(address, currentReceipt)
return ret
if (!localCache[address]) localCache[address] = await debuggerModule.fetchContractAndCompile(address, currentReceipt)
return localCache[address]
} catch (e) {
// debuggerModule.showMessage('Debugging error', 'Unable to fetch a transaction.')
console.error(e)

@ -44,7 +44,7 @@ export interface IDebuggerApi {
onEditorContentChanged: (listener: onEditorContentChanged) => void
onEnvChanged: (listener: onEnvChangedListener) => void
discardHighlight: () => Promise<void>
highlight: (lineColumnPos: LineColumnLocation, path: string, rawLocation: any, stepDetail: any) => Promise<void>
highlight: (lineColumnPos: LineColumnLocation, path: string, rawLocation: any, stepDetail: any, highlight: any) => Promise<void>
fetchContractAndCompile: (address: string, currentReceipt: TransactionReceipt) => Promise<CompilerAbstract>
getFile: (path: string) => Promise<string>
setFile: (path: string, content: string) => Promise<void>

Loading…
Cancel
Save