diff --git a/libs/remix-debug/src/solidity-decoder/internalCallTree.ts b/libs/remix-debug/src/solidity-decoder/internalCallTree.ts index 4233ec9cbb..4f74ad4585 100644 --- a/libs/remix-debug/src/solidity-decoder/internalCallTree.ts +++ b/libs/remix-debug/src/solidity-decoder/internalCallTree.ts @@ -165,7 +165,6 @@ export class InternalCallTree { const scope = this.findScope(vmtraceIndex) if (!scope) return [] let scopeId = this.scopeStarts[scope.firstStep] - const scopeDetail = this.scopes[scopeId] const functions = [] if (!scopeId) return functions let i = 0 @@ -174,6 +173,7 @@ export class InternalCallTree { i += 1 if (i > 1000) throw new Error('retrieFunctionStack: recursion too deep') const functionDefinition = this.functionDefinitionsByScope[scopeId] + const scopeDetail = this.scopes[scopeId] if (functionDefinition !== undefined) { functions.push({ ...functionDefinition, ...scopeDetail }) } @@ -280,7 +280,10 @@ async function buildTree (tree, step, scopeId, isCreation, functionDefinition?, const stepDetail: StepDetail = tree.traceManager.trace[step] const nextStepDetail: StepDetail = tree.traceManager.trace[step + 1] if (stepDetail && nextStepDetail) { + // for complicated opcodes which don't have a static gas cost: stepDetail.gasCost = parseInt(stepDetail.gas as string) - parseInt(nextStepDetail.gas as string) + } else { + stepDetail.gasCost = parseInt(stepDetail.gasCost as unknown as string) } // gas per line diff --git a/libs/remix-debug/test/decoder/localsTests/int.ts b/libs/remix-debug/test/decoder/localsTests/int.ts index 53f0e11978..fa52b55714 100644 --- a/libs/remix-debug/test/decoder/localsTests/int.ts +++ b/libs/remix-debug/test/decoder/localsTests/int.ts @@ -61,6 +61,11 @@ module.exports = function (st, privateKey, contractBytecode, compilationResult, st.equals(functions3.length, 1) st.equal(functions1[0].gasCost, 54) + st.equal(functions1[1].gasCost, 436) + + st.equal(functions2[0].gasCost, 23) + st.equal(functions2[1].gasCost, 54) + st.equal(functions2[2].gasCost, 436) st.equals(Object.keys(functions1[0])[0], 'functionDefinition') st.equals(Object.keys(functions1[0])[1], 'inputs') diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css index 1a5e4926a9..01754f6ca3 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css @@ -20,4 +20,7 @@ .debuggerPanels { overflow-y: auto; height: fit-content; +} +.jumpToFunctionClick span { + cursor: pointer; } \ No newline at end of file diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index 73333e01a5..6ea35adb1c 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -461,7 +461,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { {state.debugging && }
- {state.debugging && } + {state.debugging && } {state.debugging && ( { extractFunc, formatSelfFunc, registerEvent, + handleExpandFunc, + formatClassNamesFunc, triggerEvent, loadMoreEvent, loadMoreCompletedEvent, @@ -135,9 +137,9 @@ export const DropdownPanel = (props: DropdownPanelProps) => { toggleDropdown: !prevState.toggleDropdown } }) - } + }; - const handleExpand = (keyPath) => { + const handleExpand = handleExpandFunc || function (keyPath) { if (!state.expandPath.includes(keyPath)) { state.expandPath.push(keyPath) } else { @@ -221,6 +223,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { label={formatSelfFunc ? formatSelfFunc(key, data) : formatSelfDefault(key, data)} onClick={() => handleExpand(keyPath)} expand={state.expandPath.includes(keyPath)} + labelClass={formatClassNamesFunc && formatClassNamesFunc(key, data)} > {children} @@ -246,6 +249,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { label={formatSelfFunc ? formatSelfFunc(key, data) : formatSelfDefault(key, data)} onClick={() => handleExpand(keyPath)} expand={state.expandPath.includes(keyPath)} + labelClass={formatClassNamesFunc && formatClassNamesFunc(key, data)} /> ) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx index 6450536f5a..d2106977ed 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx @@ -2,16 +2,31 @@ import React, {useState, useEffect} from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line import {default as deepequal} from 'deep-equal' // eslint-disable-line -export const FunctionPanel = ({data, className}) => { - const [calldata, setCalldata] = useState(null) +export const FunctionPanel = ({data, className, stepManager}) => { + const [functionData, setFunctionData] = useState(null) useEffect(() => { - if (!deepequal(calldata, data)) setCalldata(data) + if (!deepequal(functionData, data)) { + setFunctionData(data.map(el => el.label)) + } }, [data]) + const formatSelfFunc = (key, data) => { + return data.self + } + + const handleExpandFunc = (keyPath) => { + stepManager.jumpTo(data[parseInt(keyPath)].function.firstStep) + } + + const formatClassNamesFunc = (keyPath, data) => { + return 'jumpToFunctionClick' + } + return ( +
- +
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx index 67ae5677fe..035d5f619a 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx @@ -5,7 +5,7 @@ import StepDetail from './step-detail' // eslint-disable-line import SolidityState from './solidity-state' // eslint-disable-line import SolidityLocals from './solidity-locals' // eslint-disable-line -export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debugging}) => { +export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debugging, stepManager}) => { const [functionPanel, setFunctionPanel] = useState(null) const [stepDetail, setStepDetail] = useState({ 'vm trace step': '-', @@ -32,7 +32,11 @@ export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debug const functions = [] for (const func of stack) { - functions.push((func.functionDefinition.name || func.functionDefinition.kind) + '(' + func.inputs.join(', ') + ')' + ' - ' + func.gasCost + ' gas') + const label = (func.functionDefinition.name || func.functionDefinition.kind) + '(' + func.inputs.join(', ') + ')' + ' - ' + func.gasCost + ' gas' + functions.push({ + label, + function: func + }) } setFunctionPanel(() => functions) }) @@ -127,7 +131,7 @@ export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debug return (
- +
diff --git a/libs/remix-ui/debugger-ui/src/types/index.ts b/libs/remix-ui/debugger-ui/src/types/index.ts index a319e354be..a5893905e7 100644 --- a/libs/remix-ui/debugger-ui/src/types/index.ts +++ b/libs/remix-ui/debugger-ui/src/types/index.ts @@ -18,6 +18,8 @@ export type ExtractFunc = (json: any, parent?: any) => ExtractData export type FormatSelfFunc = (key: string | number, data: ExtractData) => JSX.Element export type RegisterEventType = (type: string, listener: any) => void // listener is a function export type TriggerEventType = (type: string, payload: Array) => void +export type HandleExpandFunc = (keyPath: string) => void +export type FormatClassNamesFunc = (key: string | number, data: ExtractData) => string export interface DropdownPanelProps { dropdownName: string, className?: string, @@ -30,6 +32,8 @@ export interface DropdownPanelProps { extractFunc?: ExtractFunc, formatSelfFunc?: FormatSelfFunc, registerEvent?: RegisterEventType, + handleExpandFunc?: HandleExpandFunc, + formatClassNamesFunc?: FormatClassNamesFunc triggerEvent?: TriggerEventType, loadMoreEvent?: string, loadMoreCompletedEvent?: string,