Skip to content

Commit 49c8965

Browse files
committed
state locals stask memory
1 parent b6be45d commit 49c8965

File tree

3 files changed

+115
-73
lines changed

3 files changed

+115
-73
lines changed

libs/remix-ui/debugger-ui/src/lib/debug-layout/debug-layout.css

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,14 @@
8888

8989
.debug-tab {
9090
padding: 0.15rem 0.4rem;
91-
font-size: 0.7rem;
92-
font-weight: 500;
91+
font-size: 0.75rem;
92+
font-weight: 600;
9393
border: 1px solid var(--bs-border-color);
9494
background-color: transparent;
9595
color: var(--text-muted);
96-
border-radius: 0.25rem;
9796
cursor: pointer;
9897
transition: all 0.2s;
99-
height: 1.4rem;
98+
height: 1.5rem;
10099
line-height: 1;
101100
display: flex;
102101
align-items: center;

libs/remix-ui/debugger-ui/src/lib/debug-layout/debug-layout.tsx

Lines changed: 111 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ interface DebugLayoutProps {
2424
callTree?: any
2525
debugWithGeneratedSources?: boolean
2626
onDebugWithGeneratedSourcesChange?: (checked: boolean) => void
27+
registerEvent?: any
2728
}
2829

2930
export const DebugLayout = ({
@@ -45,9 +46,10 @@ export const DebugLayout = ({
4546
stepManager,
4647
callTree,
4748
debugWithGeneratedSources,
48-
onDebugWithGeneratedSourcesChange
49+
onDebugWithGeneratedSourcesChange,
50+
registerEvent
4951
}: DebugLayoutProps) => {
50-
const [activeObjectTab, setActiveObjectTab] = useState<'json' | 'raw'>('json')
52+
const [activeObjectTab, setActiveObjectTab] = useState<'stateLocals' | 'stackMemory'>('stateLocals')
5153
const [copyTooltips, setCopyTooltips] = useState<{ [key: string]: string }>({
5254
from: 'Copy address',
5355
to: 'Copy address'
@@ -60,6 +62,10 @@ export const DebugLayout = ({
6062
callTrace: true,
6163
parametersReturnValues: true
6264
})
65+
const [stackData, setStackData] = useState<any>(null)
66+
const [memoryData, setMemoryData] = useState<any>(null)
67+
const [callStackData, setCallStackData] = useState<any>(null)
68+
const [opcodeData, setOpcodeData] = useState<any>(null)
6369

6470
// Auto-expand sender node when nestedScopes are loaded
6571
React.useEffect(() => {
@@ -68,6 +74,27 @@ export const DebugLayout = ({
6874
}
6975
}, [nestedScopes])
7076

77+
// Register event listeners for stack, memory, call stack, and opcodes
78+
React.useEffect(() => {
79+
if (registerEvent) {
80+
registerEvent('traceManagerStackUpdate', (stack: any) => {
81+
setStackData(stack)
82+
})
83+
84+
registerEvent('traceManagerMemoryUpdate', (memory: any) => {
85+
setMemoryData(memory)
86+
})
87+
88+
registerEvent('traceManagerCallStackUpdate', (callStack: any) => {
89+
setCallStackData(callStack)
90+
})
91+
92+
registerEvent('codeManagerChanged', (code: any) => {
93+
setOpcodeData(code)
94+
})
95+
}
96+
}, [registerEvent])
97+
7198
const toggleSection = (section: 'transactionDetails' | 'callTrace' | 'parametersReturnValues') => {
7299
setExpandedSections(prev => ({
73100
...prev,
@@ -748,58 +775,49 @@ export const DebugLayout = ({
748775
}
749776

750777
const renderObjectContent = () => {
751-
const tx = currentTransaction
752-
753-
// Get input data (can be either 'data' or 'input' property)
754-
const inputData = tx?.data || tx?.input
778+
if (activeObjectTab === 'stateLocals') {
779+
// State & Locals tab - show parameters, locals, state
780+
const tx = currentTransaction
781+
const inputData = tx?.data || tx?.input
782+
783+
// Extract and decode parameters
784+
let parameters: any = 'N/A'
785+
786+
// First, try to get decoded parameters from solidityLocals
787+
if (solidityLocals && typeof solidityLocals === 'object') {
788+
const decodedParams: any = {}
789+
let hasParams = false
790+
791+
// Iterate through locals to find parameters
792+
for (const [key, value] of Object.entries(solidityLocals)) {
793+
if (key !== 'length' && key !== 'decode') {
794+
decodedParams[key] = value
795+
hasParams = true
796+
}
797+
}
755798

756-
// Extract and decode parameters
757-
let parameters: any = 'N/A'
758-
759-
// First, try to get decoded parameters from solidityLocals
760-
if (solidityLocals && typeof solidityLocals === 'object') {
761-
const decodedParams: any = {}
762-
let hasParams = false
763-
764-
// Iterate through locals to find parameters
765-
for (const [key, value] of Object.entries(solidityLocals)) {
766-
// Check if this is a parameter (either by checking a flag or by convention)
767-
// Parameters are typically stored as local variables
768-
if (key !== 'length' && key !== 'decode') {
769-
decodedParams[key] = value
770-
hasParams = true
799+
if (hasParams) {
800+
parameters = decodedParams
771801
}
772802
}
773803

774-
if (hasParams) {
775-
parameters = decodedParams
804+
// Fallback to raw hex if no decoded params available
805+
if (parameters === 'N/A' && tx && inputData) {
806+
if (inputData === '0x' || inputData === '') {
807+
parameters = !tx.to ? 'Contract Bytecode' : 'None (ETH Transfer)'
808+
} else if (inputData.length > 10) {
809+
parameters = '0x' + inputData.substring(10)
810+
} else {
811+
parameters = inputData
812+
}
776813
}
777-
}
778814

779-
// Fallback to raw hex if no decoded params available
780-
if (parameters === 'N/A' && tx && inputData) {
781-
if (inputData === '0x' || inputData === '') {
782-
parameters = !tx.to ? 'Contract Bytecode' : 'None (ETH Transfer)'
783-
} else if (inputData.length > 10) {
784-
// Strip the function selector (first 10 chars including '0x')
785-
parameters = '0x' + inputData.substring(10)
786-
} else {
787-
parameters = inputData
815+
const objectData: any = {
816+
parameters: parameters,
817+
locals: solidityLocals || 'No local variables at current step',
818+
state: solidityState || 'No state variables at current step'
788819
}
789-
}
790-
791-
// Debug logging
792-
console.log('[DebugLayout] solidityLocals:', solidityLocals)
793-
console.log('[DebugLayout] solidityState:', solidityState)
794-
795-
// Build objectData
796-
const objectData: any = {
797-
parameters: parameters,
798-
locals: solidityLocals || 'No local variables at current step',
799-
state: solidityState || 'No state variables at current step'
800-
}
801820

802-
if (activeObjectTab === 'json') {
803821
return (
804822
<div className="debug-object-content json-renderer">
805823
<div className="json-line">
@@ -827,10 +845,39 @@ export const DebugLayout = ({
827845
</div>
828846
)
829847
} else {
848+
// Stack & Memory tab - show opcode, call stack, memory
849+
const stackMemoryData: any = {
850+
opcode: opcodeData || 'No opcode data at current step',
851+
callStack: callStackData || 'No call stack at current step',
852+
memory: memoryData || 'No memory data at current step',
853+
stack: stackData || 'No stack data at current step'
854+
}
855+
830856
return (
831-
<pre className="debug-object-content">
832-
{JSON.stringify(objectData)}
833-
</pre>
857+
<div className="debug-object-content json-renderer">
858+
<div className="json-line">
859+
<span className="json-bracket">{'{'}</span>
860+
</div>
861+
{Object.keys(stackMemoryData).map((key) => {
862+
const value = stackMemoryData[key]
863+
const path = `root.${key}`
864+
if (isObject(value)) {
865+
return renderJsonValue(value, key, path, 1)
866+
}
867+
return (
868+
<div key={path} className="json-line" style={{ marginLeft: '12px' }}>
869+
<span className="json-expand-icon-placeholder"></span>
870+
<span className="json-key">"{key}"</span>
871+
<span className="json-separator">: </span>
872+
<span className="json-value">{JSON.stringify(value)}</span>
873+
{key !== Object.keys(stackMemoryData)[Object.keys(stackMemoryData).length - 1] && <span className="json-comma">,</span>}
874+
</div>
875+
)
876+
})}
877+
<div className="json-line">
878+
<span className="json-bracket">{'}'}</span>
879+
</div>
880+
</div>
834881
)
835882
}
836883
}
@@ -908,33 +955,28 @@ export const DebugLayout = ({
908955
)}
909956
</div>
910957

911-
{/* Section 4: Parameters & Return Values */}
958+
{/* Section 4: State & Locals / Stack & Memory */}
912959
<div className="debug-section debug-section-object" style={!expandedSections.parametersReturnValues ? { minHeight: 'auto' } : {}}>
913960
<div
914961
className="debug-section-header"
915962
onClick={() => toggleSection('parametersReturnValues')}
916963
style={{ cursor: 'pointer' }}
917964
>
918-
<h6 className="debug-section-title">
919-
<FormattedMessage id="debugger.parametersAndReturnValues" defaultMessage="Parameters & Return Values" />
920-
</h6>
921-
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
922-
<i className={`fas ${expandedSections.parametersReturnValues ? 'fa-chevron-down' : 'fa-chevron-right'}`} style={{ fontSize: '0.75rem', color: 'var(--bs-body-color)' }}></i>
923-
<div className="debug-tabs" onClick={(e) => e.stopPropagation()}>
924-
<button
925-
className={`debug-tab ${activeObjectTab === 'json' ? 'active' : ''}`}
926-
onClick={() => setActiveObjectTab('json')}
927-
>
928-
<FormattedMessage id="debugger.json" defaultMessage="JSON" />
929-
</button>
930-
<button
931-
className={`debug-tab ${activeObjectTab === 'raw' ? 'active' : ''}`}
932-
onClick={() => setActiveObjectTab('raw')}
933-
>
934-
<FormattedMessage id="debugger.raw" defaultMessage="Raw" />
935-
</button>
936-
</div>
965+
<div className="debug-tabs" onClick={(e) => e.stopPropagation()} style={{ paddingLeft: '1rem' }}>
966+
<button
967+
className={`debug-tab ${activeObjectTab === 'stateLocals' ? 'active' : ''}`}
968+
onClick={() => setActiveObjectTab('stateLocals')}
969+
>
970+
<FormattedMessage id="debugger.stateLocals" defaultMessage="State & Locals" />
971+
</button>
972+
<button
973+
className={`debug-tab ${activeObjectTab === 'stackMemory' ? 'active' : ''}`}
974+
onClick={() => setActiveObjectTab('stackMemory')}
975+
>
976+
<FormattedMessage id="debugger.stackMemory" defaultMessage="Stack & Memory" />
977+
</button>
937978
</div>
979+
<i className={`fas ${expandedSections.parametersReturnValues ? 'fa-chevron-down' : 'fa-chevron-right'}`} style={{ fontSize: '0.75rem', marginRight: '1rem', color: 'var(--bs-body-color)' }}></i>
938980
</div>
939981
{expandedSections.parametersReturnValues && (
940982
<div className="debug-section-content debug-section-scrollable">

libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
803803
}
804804
})
805805
}}
806+
registerEvent={vmDebugger.registerEvent}
806807
/>
807808
</div>
808809
)}

0 commit comments

Comments
 (0)