Debugging Tools Overview
Minichain provides several tools for debugging:- VM Tracer: Records every instruction executed
- LOG Opcode: Emit debug values during execution
- Gas Monitoring: Track gas consumption per instruction
- Error Messages: Detailed error information
- Register Inspection: View register state at each step
Understanding the VM Tracer
The VM tracer records detailed information about contract execution:- PC (Program Counter): Current position in bytecode
- Opcode: Instruction being executed
- Gas: Remaining gas before and after
- Registers: Complete register state (R0-R15)
Using the Tracer
-
Enable Tracing in Code
When creating a VM instance, enable the tracer:
-
Understanding Trace Output
The tracer prints execution in this format:
Example trace for the counter contract:
-
Analyze Execution Flow
Step 0: Load Immediate
- Started with 1,000,000 gas
- LOADI loaded
0into R0 (costs 2 gas) - R0 now contains storage slot number
- SLOAD read from storage slot 0 (R0)
- Loaded value
0into R1 (first call, slot empty) - Cost 100 gas
- Program counter jumped to 0x000A
- Loaded constant
1into R2 - This is the increment amount
- Added R1 (0) + R2 (1) = 1
- Result stored in R1
- R1 now contains the new counter value
- Stored R1 (1) to storage slot R0 (0)
- Cost 5,000 gas (writing to existing slot)
- Notice the large gas drop!
- Execution completed successfully
- Total gas used: 1,000,000 - 994,894 = 5,106 gas
-
Using LOG for Debugging
Add LOG instructions to emit values:
The LOG opcode emits values that appear in execution results:
Common Debugging Scenarios
Scenario 1: Out of Gas
Symptom:-
Check the trace to see where gas ran out:
-
Identify expensive operations:
- SSTORE: 5,000-20,000 gas
- SLOAD: 100 gas
- Loops with many iterations
-
Solutions:
- Increase gas limit when deploying/calling
- Optimize contract: reduce storage operations
- Break complex operations into multiple transactions
Scenario 2: Incorrect Storage Values
Symptom: Counter always returns 0 instead of incrementing. How to debug:-
Add LOG instructions to inspect values:
-
Check the trace for storage operations:
-
Verify storage slot numbers:
Make sure the same slot is used for load and store!
Scenario 3: Wrong Register Values
Symptom: Calculation produces unexpected results. Debugging approach:Scenario 4: Invalid Jump
Symptom:-
Check label resolution:
-
Verify bytecode length:
- Jump target must be within bytecode bounds
- Check for typos in label names
-
Use tracer to see where jump occurred:
Scenario 5: Division by Zero
Symptom:Debugging Workflow
-
Reproduce the Issue
- Deploy contract with known inputs
- Call contract and observe failure
- Note error message and transaction details
-
Add Debug Instrumentation
-
Run with Tracer
- Enable VM tracer
- Execute the failing transaction
- Review trace output line by line
-
Analyze Register State
- Check register values at each step
- Verify calculations are correct
- Identify where values diverge from expected
-
Check Gas Consumption
- Look for unexpected gas spikes
- Calculate expected vs actual gas
- Identify expensive operations
-
Fix and Verify
- Make necessary changes to assembly
- Remove or disable debug LOGs
- Test with various inputs
- Monitor gas usage
Best Practices
During Development
-
Use Liberal Logging
-
Comment Your Code
-
Test Incrementally
- Write and test small functions first
- Build up to complex logic
- Verify each section works independently
For Production
-
Remove Debug Logs
Saves 2 gas per LOG instruction.
-
Add Input Validation
-
Handle Edge Cases
- Check for zero values
- Verify storage slots exist
- Handle maximum value overflows
-
Monitor Gas Limits
Tools Reference
VM Tracer API
LOG Opcode
- Gas cost: 2
- Output available in
ExecutionResult.logs - Useful for debugging during development
- Remove before production deployment
Next Steps
- Learn testing strategies in Testing Guide
- Explore advanced patterns in Contract Examples
- Reference all opcodes in Opcode Reference
- Understand gas costs in Gas Metering