diff --git a/libs/remix-debug/src/code/codeManager.ts b/libs/remix-debug/src/code/codeManager.ts index b0f61a0a24..fb04f64945 100644 --- a/libs/remix-debug/src/code/codeManager.ts +++ b/libs/remix-debug/src/code/codeManager.ts @@ -145,17 +145,37 @@ export class CodeManager { }) } - private retrieveIndexAndTrigger (codeMananger, address, step, code) { + private async retrieveIndexAndTrigger (codeMananger, address, step, code) { let result let next + let returnInstructionIndexes = [] + let outOfGasInstructionIndexes = [] + try { result = codeMananger.getInstructionIndex(address, step) next = codeMananger.getInstructionIndex(address, step + 1) - } catch (error) { - return console.log(error) - } + + let values = this.traceManager.getAllStopIndexes() + values = values.filter((value) => value.address === address) + if (values) { + for (const value of values) { + returnInstructionIndexes.push({ instructionIndex: this.getInstructionIndex(address, value.index), address }) + } + } + + values = this.traceManager.getAllOutofGasIndexes() + values = values.filter((value) => value.address === address) + if (values) { + for (const value of values) { + outOfGasInstructionIndexes.push({ instructionIndex: this.getInstructionIndex(address, value.index), address }) + } + } + + } catch (error) { + return console.log(error) + } try { - codeMananger.event.trigger('changed', [code, address, result, next]) + codeMananger.event.trigger('changed', [code, address, result, next, returnInstructionIndexes, outOfGasInstructionIndexes]) } catch (e) { console.log('dispatching event failed', e) } diff --git a/libs/remix-debug/src/debugger/VmDebugger.ts b/libs/remix-debug/src/debugger/VmDebugger.ts index 47ea75ea4b..72a131cfd6 100644 --- a/libs/remix-debug/src/debugger/VmDebugger.ts +++ b/libs/remix-debug/src/debugger/VmDebugger.ts @@ -59,8 +59,8 @@ export class VmDebuggerLogic { } listenToCodeManagerEvents () { - this._codeManager.event.register('changed', (code, address, index, nextIndex) => { - this.event.trigger('codeManagerChanged', [code, address, index, nextIndex]) + this._codeManager.event.register('changed', (code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes) => { + this.event.trigger('codeManagerChanged', [code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes]) }) } diff --git a/libs/remix-debug/src/trace/traceAnalyser.ts b/libs/remix-debug/src/trace/traceAnalyser.ts index ae8957b5ac..ba66f2dbb1 100644 --- a/libs/remix-debug/src/trace/traceAnalyser.ts +++ b/libs/remix-debug/src/trace/traceAnalyser.ts @@ -49,6 +49,17 @@ export class TraceAnalyser { this.traceCache.pushReturnValue(index, returnParamsObj) } + if (traceHelper.isReturnInstruction(step) || traceHelper.isStopInstruction(step) || traceHelper.isRevertInstruction(step)) { + this.traceCache.pushStopIndex(index, this.traceCache.currentCall.call.address) + } + + try { + if (parseInt(step.gas) - parseInt(step.gasCost) <= 0 || step.error === 'OutOfGas') { + this.traceCache.pushOutOfGasIndex(index, this.traceCache.currentCall.call.address) + } + } catch (e) { + console.error(e) + } } buildCalldata (index, step, tx, newContext) { diff --git a/libs/remix-debug/src/trace/traceCache.ts b/libs/remix-debug/src/trace/traceCache.ts index 7c2d381ccc..411e8e617c 100644 --- a/libs/remix-debug/src/trace/traceCache.ts +++ b/libs/remix-debug/src/trace/traceCache.ts @@ -5,6 +5,8 @@ const { sha3_256 } = util export class TraceCache { returnValues + stopIndexes + outofgasIndexes currentCall callsTree callsData @@ -24,6 +26,8 @@ export class TraceCache { // ...Changes contains index in the vmtrace of the corresponding changes this.returnValues = {} + this.stopIndexes = [] + this.outofgasIndexes = [] this.currentCall = null this.callsTree = null this.callsData = {} @@ -59,7 +63,7 @@ export class TraceCache { this.currentCall.call.reverted = reverted } var parent = this.currentCall.parent - this.currentCall = parent ? { call: parent.call, parent: parent.parent } : null + if (parent) this.currentCall = { call: parent.call, parent: parent.parent } return } const call = { @@ -78,6 +82,14 @@ export class TraceCache { this.currentCall = { call: call, parent: this.currentCall } } + pushOutOfGasIndex (index, address) { + this.outofgasIndexes.push({ index, address }) + } + + pushStopIndex (index, address) { + this.stopIndexes.push({ index, address }) + } + pushReturnValue (step, value) { this.returnValues[step] = value } diff --git a/libs/remix-debug/src/trace/traceManager.ts b/libs/remix-debug/src/trace/traceManager.ts index 8e78782922..848b3c57aa 100644 --- a/libs/remix-debug/src/trace/traceManager.ts +++ b/libs/remix-debug/src/trace/traceManager.ts @@ -209,6 +209,14 @@ export class TraceManager { return this.trace[stepIndex].pc } + getAllStopIndexes () { + return this.traceCache.stopIndexes + } + + getAllOutofGasIndexes () { + return this.traceCache.outofgasIndexes + } + getReturnValue (stepIndex) { try { this.checkRequestedStep(stepIndex) diff --git a/libs/remix-lib/src/web3Provider/web3VmProvider.ts b/libs/remix-lib/src/web3Provider/web3VmProvider.ts index 59b0e7e909..b5d8ea4732 100644 --- a/libs/remix-lib/src/web3Provider/web3VmProvider.ts +++ b/libs/remix-lib/src/web3Provider/web3VmProvider.ts @@ -138,7 +138,7 @@ export class Web3VmProvider { async txProcessed (data) { const lastOp = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1] if (lastOp) { - lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'thisDESTRUCT' + lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'DESTRUCT' } this.vmTraces[this.processingHash].gas = '0x' + data.gasUsed.toString(16) diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx index 248e4be9cc..de9c37e1bc 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx @@ -7,12 +7,14 @@ export const AssemblyItems = ({ registerEvent }) => { const [absoluteSelectedIndex, setAbsoluteSelectedIndex] = useState(0) const [selectedItem, setSelectedItem] = useState(0) const [nextSelectedItem, setNextSelectedItem] = useState(1) + const [returnInstructionIndexes, setReturnInstructionIndexes] = useState([]) + const [outOfGasInstructionIndexes, setOutOfGasInstructionIndexes] = useState([]) const refs = useRef({}) const asmItemsRef = useRef(null) useEffect(() => { - registerEvent && registerEvent('codeManagerChanged', (code, address, index, nextIndex) => { - dispatch({ type: 'FETCH_OPCODES_SUCCESS', payload: { code, address, index, nextIndex } }) + registerEvent && registerEvent('codeManagerChanged', (code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes) => { + dispatch({ type: 'FETCH_OPCODES_SUCCESS', payload: { code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes } }) }) }, []) @@ -22,6 +24,8 @@ export const AssemblyItems = ({ registerEvent }) => { clearItems() indexChanged(assemblyItems.index) nextIndexChanged(assemblyItems.nextIndex) + returnIndexes(assemblyItems.returnInstructionIndexes) + outOfGasIndexes(assemblyItems.outOfGasInstructionIndexes) } }, [assemblyItems.opCodes.index]) @@ -45,10 +49,37 @@ export const AssemblyItems = ({ registerEvent }) => { currentItem.firstChild.removeAttribute('style') } } + + returnInstructionIndexes.map((index) => { + if (index < 0) return + + currentItem = refs.current[index] ? refs.current[index] : null + + if (currentItem) { + currentItem.removeAttribute('selected') + currentItem.removeAttribute('style') + if (currentItem.firstChild) { + currentItem.firstChild.removeAttribute('style') + } + } + }) + + outOfGasInstructionIndexes.map((index) => { + if (index < 0) return + + currentItem = refs.current[index] ? refs.current[index] : null + + if (currentItem) { + currentItem.removeAttribute('selected') + currentItem.removeAttribute('style') + if (currentItem.firstChild) { + currentItem.firstChild.removeAttribute('style') + } + } + }) } const indexChanged = (index: number) => { - console.log('index ' + index) if (index < 0) return const codeView = asmItemsRef.current @@ -79,6 +110,38 @@ export const AssemblyItems = ({ registerEvent }) => { setNextSelectedItem(index) } + const returnIndexes = (indexes) => { + indexes.map((index) => { + if (index < 0) return + + const codeView = asmItemsRef.current + + const currentItem = codeView.children[index] + if (currentItem) { + currentItem.style.setProperty('border-color', 'var(--warning)') + currentItem.style.setProperty('border-style', 'dotted') + currentItem.setAttribute('selected', 'selected') + } + }) + setReturnInstructionIndexes(indexes) + } + + const outOfGasIndexes = (indexes) => { + indexes.map((index) => { + if (index < 0) return + + const codeView = asmItemsRef.current + + const currentItem = codeView.children[index] + if (currentItem) { + currentItem.style.setProperty('border-color', 'var(--danger)') + currentItem.style.setProperty('border-style', 'dotted') + currentItem.setAttribute('selected', 'selected') + } + }) + setOutOfGasInstructionIndexes(indexes) + } + return (
diff --git a/libs/remix-ui/debugger-ui/src/reducers/assembly-items.ts b/libs/remix-ui/debugger-ui/src/reducers/assembly-items.ts index bc9ea96580..d5a936bc95 100644 --- a/libs/remix-ui/debugger-ui/src/reducers/assembly-items.ts +++ b/libs/remix-ui/debugger-ui/src/reducers/assembly-items.ts @@ -14,6 +14,8 @@ export const initialState = { display: [], index: 0, nextIndex: -1, + returnInstructionIndexes: [], + outOfGasInstructionIndexes: [], top: 0, bottom: 0, isRequesting: false, @@ -21,7 +23,7 @@ export const initialState = { hasError: null } -const reducedOpcode = (opCodes) => { +const reducedOpcode = (opCodes, payload) => { const length = 100 let bottom = opCodes.index - 10 bottom = bottom < 0 ? 0 : bottom @@ -29,7 +31,9 @@ const reducedOpcode = (opCodes) => { return { index: opCodes.index - bottom, nextIndex: opCodes.nextIndex - bottom, - display: opCodes.code.slice(bottom, top) + display: opCodes.code.slice(bottom, top), + returnInstructionIndexes: payload.returnInstructionIndexes.map((index) => index.instructionIndex - bottom ), + outOfGasInstructionIndexes: payload.outOfGasInstructionIndexes.map((index) => index.instructionIndex - bottom ) } } @@ -48,7 +52,7 @@ export const reducer = (state = initialState, action: Action) => { ...state.opCodes, index: action.payload.index, nextIndex: action.payload.nextIndex } : deepEqual(action.payload.code, state.opCodes.code) ? state.opCodes : action.payload - const reduced = reducedOpcode(opCodes) + const reduced = reducedOpcode(opCodes, action.payload) return { opCodes, display: reduced.display, @@ -56,7 +60,9 @@ export const reducer = (state = initialState, action: Action) => { nextIndex: reduced.nextIndex, isRequesting: false, isSuccessful: true, - hasError: null + hasError: null, + returnInstructionIndexes: reduced.returnInstructionIndexes, + outOfGasInstructionIndexes: reduced.outOfGasInstructionIndexes } } case 'FETCH_OPCODES_ERROR': {