From 0a1363f2eb4e0cc2edb585bbbd6b59761c0876f4 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 7 Sep 2020 17:04:49 +0100 Subject: [PATCH] Put vm debugger components together --- .../debugger-ui/src/hooks/extract-data.tsx | 43 +++++---- .../debugger-ui/src/lib/debugger-ui.tsx | 2 + .../src/lib/vm-debugger/code-list-view.tsx | 20 +++-- .../src/lib/vm-debugger/dropdown-panel.tsx | 51 +++++++++-- .../src/lib/vm-debugger/solidity-locals.tsx | 44 +++++++++ .../src/lib/vm-debugger/solidity-state.tsx | 39 +++++++- .../utils/solidity-type-formatter.ts | 0 .../src/lib/vm-debugger/vm-debugger.tsx | 90 ++++++++++++++++++- libs/remix-ui/debugger-ui/src/types/index.ts | 14 +-- .../src/utils/solidityTypeFormatter.ts | 42 +++++++++ .../src/lib/tree-view-item/tree-view-item.tsx | 10 ++- libs/remix-ui/tree-view/src/types/index.ts | 6 ++ 12 files changed, 312 insertions(+), 49 deletions(-) create mode 100644 libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx delete mode 100644 libs/remix-ui/debugger-ui/src/lib/vm-debugger/utils/solidity-type-formatter.ts create mode 100644 libs/remix-ui/debugger-ui/src/utils/solidityTypeFormatter.ts diff --git a/libs/remix-ui/debugger-ui/src/hooks/extract-data.tsx b/libs/remix-ui/debugger-ui/src/hooks/extract-data.tsx index 06e653a801..3966329e4e 100644 --- a/libs/remix-ui/debugger-ui/src/hooks/extract-data.tsx +++ b/libs/remix-ui/debugger-ui/src/hooks/extract-data.tsx @@ -1,9 +1,32 @@ import React, { useState, useEffect } from 'react' import { ExtractData, ExtractFunc } from '../types' -export const useExtractData = (json, extractFunc?): Array<{ [key: string]: ExtractData }> => { +export const useExtractData = (json, extractFunc?: ExtractFunc): Array<{ key: string, data: ExtractData }> => { const [data, setData] = useState(null) - const extractDataDefault = (item, parent?) => { + + useEffect(() => { + const data: Array<{ key: string, data: ExtractData }> = Object.keys(json).map((innerKey) => { + if (extractFunc) { + return { + key: innerKey, + data : extractFunc(json[innerKey], json) + } + } else { + return { + key: innerKey, + data: extractDataDefault(json[innerKey], json) + } + } + }) + + setData(data) + + return () => { + setData(null) + } + }, [json, extractFunc]) + + const extractDataDefault: ExtractFunc = (item, parent?) => { const ret: ExtractData = {} if (item instanceof Array) { @@ -29,22 +52,6 @@ export const useExtractData = (json, extractFunc?): Array<{ [key: string]: Extra return ret } - useEffect(() => { - const data: Array<{ [key: string]: ExtractData }> = Object.keys(json).map((innerKey) => { - if (extractFunc) { - return { [innerKey]: extractFunc(json[innerKey], json) } - } else { - return { [innerKey]: extractDataDefault(json[innerKey], json) } - } - }) - - setData(data) - - return () => { - setData(null) - } - }, [json, extractFunc]) - return data } 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 7340e4d2d4..bbd52fcabe 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -1,4 +1,6 @@ import React from 'react' +import StepManager from './step-manager/step-manager' +import const DebuggerUI = () => { return ( diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx index c6b578431d..77cdc70b52 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx @@ -1,16 +1,23 @@ -import React, { useState, useRef } from 'react' +import React, { useState, useEffect } from 'react' import DropdownPanel from './dropdown-panel' -import EventManager from '../../../../../apps/remix-ide/src/lib/events' +/* eslint-disable-next-line */ +import EventManager from '../../../../../../apps/remix-ide/src/lib/events' -export const CodeListView = ({ vmDebuggerLogic }) => { +export const CodeListView = ({ vmDebuggerLogic, asm }) => { const event = new EventManager() const [state, setState] = useState({ - code: '', + code: [], address: '', itemSelected: null, index: null }) + useEffect(() => { + const { code, address, index } = asm + + changed(code, address, index) + }, [asm]) + const indexChanged = (index) => { if(index < 0) return setState(prevState => { @@ -21,10 +28,6 @@ export const CodeListView = ({ vmDebuggerLogic }) => { }) } - const reset = () => { - changed([], '', -1) - } - const changed = (code, address, index) => { if (state.address === address) { return indexChanged(index) @@ -36,7 +39,6 @@ export const CodeListView = ({ vmDebuggerLogic }) => { address } }) - this.basicPanel.setContent(this.renderAssemblyItems()) indexChanged(index) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx index 66af8a6a92..a5b090b2a1 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx @@ -3,15 +3,17 @@ import AssemblyItems from './assembly-items' /* eslint-disable-next-line */ import { TreeView, TreeViewItem } from '../../../../tree-view/src/index' import useExtractData from '../../hooks/extract-data' -import { ExtractData, ExtractFunc, DropdownPanelProps } from '../../types' +import { DropdownPanelProps, ExtractData } from '../../types' import './styles/dropdown-panel.css' -import EventManager from '../../../../../apps/remix-ide/src/lib/events' -import copyToClipboard from '../../../../../apps/remix-ide/src/app/ui/copy-to-clipboard' +/* eslint-disable-next-line */ +import EventManager from '../../../../../../apps/remix-ide/src/lib/events' +/* eslint-disable-next-line */ +import copyToClipboard from '../../../../../../apps/remix-ide/src/app/ui/copy-to-clipboard' export const DropdownPanel = (props: DropdownPanelProps) => { - const { dropdownName, opts, codeView, index, calldata, header, extractFunc } = props + const { dropdownName, opts, codeView, index, calldata, header, extractFunc, formatSelfFunc } = props const data = useExtractData(calldata, extractFunc) const event = new EventManager() const dropdownRawEl = useRef(null) @@ -150,9 +152,46 @@ export const DropdownPanel = (props: DropdownPanelProps) => { event.trigger('show', []) } - let content =
Empty
+ const formatSelfDefault = (key: string, data: ExtractData) => { + return ( +
+ + +
+ ) + } + + const renderData = (item: ExtractData, key: string) => { + const children = (item.children || []).map((child) => { + const childKey = key + '/' + child.key + + return ( + + { renderData(child.value, childKey) } + + ) + }) + + if (children && children.length > 0 ) { + return ( + + { children } + + ) + } else { + return + } + } + + let content: JSX.Element | JSX.Element[] =
Empty
if (state.json) { - content = treeView.render({}, null) + content = data.map(item => { + return ( + + { renderData(item.data, item.key) } + + ) + }) } const title = !state.displayContentOnly ?
diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx new file mode 100644 index 0000000000..e6f222da19 --- /dev/null +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx @@ -0,0 +1,44 @@ +import React from 'react' +import DropdownPanel from './dropdown-panel' +import { extractData } from '../../utils/solidityTypeFormatter' +import { ExtractData } from '../../types' + +export const SolidityLocals = () => { + + const formatSelf = (key: string, data: ExtractData) => { + let color = 'var(--primary)' + if (data.isArray || data.isStruct || data.isMapping) { + color = 'var(--info)' + } else if ( + data.type.indexOf('uint') === 0 || + data.type.indexOf('int') === 0 || + data.type.indexOf('bool') === 0 || + data.type.indexOf('enum') === 0 + ) { + color = 'var(--green)' + } else if (data.type === 'string') { + color = 'var(--teal)' + } else if (data.self == 0x0) { // eslint-disable-line + color = 'var(--gray)' + } + return ( + + ) + } + + return ( +
+ +
+ ) +} + +export default SolidityLocals \ No newline at end of file diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx index c67d061da3..9fdade9f4b 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx @@ -1,11 +1,44 @@ import React from 'react' import DropdownPanel from './dropdown-panel' +import { extractData } from '../../utils/solidityTypeFormatter' +import { ExtractData } from '../../types' export const SolidityState = () => { + const formatSelf = (key: string, data: ExtractData) => { + let color = 'var(--primary)' + if (data.isArray || data.isStruct || data.isMapping) { + color = 'var(--info)' + } else if ( + data.type.indexOf('uint') === 0 || + data.type.indexOf('int') === 0 || + data.type.indexOf('bool') === 0 || + data.type.indexOf('enum') === 0 + ) { + color = 'var(--green)' + } else if (data.type === 'string') { + color = 'var(--teal)' + } else if (data.self == 0x0) { // eslint-disable-line + color = 'var(--gray)' + } + return ( + + ) + } + return ( - +
+ { + + } +
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/utils/solidity-type-formatter.ts b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/utils/solidity-type-formatter.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger.tsx index 42da693ba8..4114afbb5d 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger.tsx @@ -1,15 +1,97 @@ -import React, { useState } from 'react' +import React, { useState, useEffect } from 'react' import CodeListView from './code-list-view' +import CalldataPanel from './calldata-panel' +import MemoryPanel from './memory-panel' +import CallstackPanel from './callstack-panel' +import FunctionPanel from './function-panel' +import StackPanel from './stack-panel' +import StoragePanel from './storage-panel' +import StepDetail from './step-detail' +import SolidityState from './solidity-state' +import SolidityLocals from './solidity-locals' +import FullStoragesChangesPanel from './full-storages-changes' +import DropdownPanel from './dropdown-panel' import './vm-debugger.css'; export const VmDebugger = ({ vmDebuggerLogic }) => { const [state, setState] = useState({ - }) + const [asm, setAsm] = useState({ + code: null, + address: null, + index: null + }) + const [calldataPanel, setCalldataPanel] = useState(null) + const [memoryPanel, setMemoryPanel] = useState(null) + const [callStackPanel, setCallStackPanel] = useState(null) + + useEffect(() => { + vmDebuggerLogic.event.register('codeManagerChanged', updateAsm) + vmDebuggerLogic.event.register('traceUnloaded', resetAsm) + vmDebuggerLogic.event.register('traceManagerCallDataUpdate', updateCalldataPanel) + vmDebuggerLogic.event.register('traceManagerMemoryUpdate', updateMemoryPanel) + vmDebuggerLogic.event.register('traceManagerCallStackUpdate', updateCallStackPanel) + }, []) + + const updateAsm = (code, address, index) => { + setAsm({ + code, + address, + index + }) + } + + const resetAsm = () => { + setAsm({ + code: [], + address: '', + index: -1 + }) + } + + const updateCalldataPanel = (calldata) => { + setCalldataPanel(calldata) + } + + const updateMemoryPanel = (calldata) => { + setMemoryPanel(calldata) + } + + const updateCallStackPanel = (calldata) => { + setCallStackPanel(calldata) + } + + useEffect(() => { + vmDebuggerLogic.event.register('codeManagerChanged', ) + }, []) + + const renderHead = () => { + return ( +
+
+ +
{this.asmCode.render()}
+
{this.stepDetail.render()}
+
+
+ ) + } return ( -
-

Welcome to vmDebugger!

+
+
+ {this.stackPanel.render()} + {this.memoryPanel.render()} + {this.storagePanel.render()} + {this.callstackPanel.render()} + {this.calldataPanel.render()} + {this.returnValuesPanel.render()} + {this.fullStoragesChangesPanel.render()} +
); }; diff --git a/libs/remix-ui/debugger-ui/src/types/index.ts b/libs/remix-ui/debugger-ui/src/types/index.ts index 331c2af838..b8e02d3fb3 100644 --- a/libs/remix-ui/debugger-ui/src/types/index.ts +++ b/libs/remix-ui/debugger-ui/src/types/index.ts @@ -1,12 +1,13 @@ export interface ExtractData { - children?: Array<{key: number | string, value: string}> | { key: number | string, value: string } - self?: string, + children?: Array<{key: number | string, value: ExtractData}> + self?: string | number, isNode?: boolean, isLeaf?: boolean, isArray?: boolean, isStruct?: boolean, isMapping?: boolean, - type?: string + type?: string, + isProperty?: boolean } export type ExtractFunc = (json: any, parent?: any) => ExtractData @@ -26,5 +27,8 @@ export interface DropdownPanelProps { [key: string]: string }, header?: string, - extractFunc?: ExtractFunc -} \ No newline at end of file + extractFunc?: ExtractFunc, + formatSelfFunc?: FormatSelfFunc +} + +export type FormatSelfFunc = (key: string, data: ExtractData) => JSX.Element \ No newline at end of file diff --git a/libs/remix-ui/debugger-ui/src/utils/solidityTypeFormatter.ts b/libs/remix-ui/debugger-ui/src/utils/solidityTypeFormatter.ts new file mode 100644 index 0000000000..eb3637c2f4 --- /dev/null +++ b/libs/remix-ui/debugger-ui/src/utils/solidityTypeFormatter.ts @@ -0,0 +1,42 @@ +import { BN } from 'ethereumjs-util' +import { ExtractData } from '../types' + +export function extractData (item, parent): ExtractData { + const ret: ExtractData = {} + + if (item.isProperty) { + return item + } + if (item.type.lastIndexOf(']') === item.type.length - 1) { + ret.children = (item.value || []).map(function (item, index) { + return {key: index, value: item} + }) + ret.children.unshift({ + key: 'length', + value: { + self: (new BN(item.length.replace('0x', ''), 16)).toString(10), + type: 'uint', + isProperty: true + } + }) + ret.isArray = true + ret.self = parent.isArray ? '' : item.type + } else if (item.type.indexOf('struct') === 0) { + ret.children = Object.keys((item.value || {})).map(function (key) { + return {key: key, value: item.value[key]} + }) + ret.self = item.type + ret.isStruct = true + } else if (item.type.indexOf('mapping') === 0) { + ret.children = Object.keys((item.value || {})).map(function (key) { + return {key: key, value: item.value[key]} + }) + ret.isMapping = true + ret.self = item.type + } else { + ret.children = null + ret.self = item.value + ret.type = item.type + } + return ret +} \ No newline at end of file diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index 796a8c6a04..a5b1de95da 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -1,8 +1,10 @@ import React, { useState } from 'react' +import { TreeViewItemProps } from '../../types' import './tree-view-item.css' -export const TreeViewItem = ({ key, children, label, ...otherProps }) => { +export const TreeViewItem = (props: TreeViewItemProps) => { + const { key, children, label, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) return ( @@ -15,7 +17,7 @@ export const TreeViewItem = ({ key, children, label, ...otherProps }) => {
{ isExpanded ? children : null } - ); -}; + ) +} -export default TreeViewItem; +export default TreeViewItem diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index 800d92d40d..6e36ec108b 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -1,4 +1,10 @@ export interface TreeViewProps { children?: React.ReactNode, key: string +} + +export interface TreeViewItemProps { + children?: React.ReactNode, + key: string, + label: string | number | React.ReactNode } \ No newline at end of file