Debugging Tools: Development and Debugging Techniques
Introduction
Debugging is an essential skill for any Rippled developer. Whether you're tracking down a subtle transaction processing bug, investigating network connectivity issues, or optimizing performance, having a solid understanding of debugging tools and techniques is critical. The complexity of distributed systems like the XRP Ledger means that effective debugging often requires multiple approaches—from analyzing logs to using debuggers to running controlled experiments.
This deep dive covers the comprehensive toolkit available for debugging Rippled, from basic logging to advanced profiling techniques. You'll learn how to diagnose issues quickly, understand system behavior, and develop confidence in working with the Rippled codebase.
Logging System
Overview
Rippled includes a sophisticated logging system that provides detailed visibility into system behavior. Understanding how to configure and use logging effectively is the foundation of debugging Rippled.
Log Structure
Partitions: Logs are organized by subsystem (partition) Severity Levels: Each log entry has a severity level Timestamps: All logs include precise timestamps Context: Logs include relevant context (account IDs, ledger numbers, etc.)
Severity Levels
From most to least verbose:
trace - Extremely detailed, every function call
debug - Detailed debugging information
info - General informational messages
warning - Warning conditions
error - Error conditions
fatal - Fatal errors that cause terminationUsage Guidelines:
Production: Use
warningorerrorto minimize disk I/ODevelopment: Use
debugortracefor active debuggingInvestigation: Temporarily enable
tracefor specific partitions
Log Partitions
Major subsystems have their own partitions:
Configuring Logging
In Configuration File
Edit rippled.cfg:
Via RPC Command
Dynamic adjustment without restart:
Programmatically
In code:
Log File Location
Default Locations:
Linux:
/var/log/rippled/debug.logmacOS:
~/Library/Application Support/rippled/debug.logCustom: Set in
rippled.cfg:
Log Rotation
Configure log rotation to prevent disk space issues:
Using system tools (Linux):
Reading Log Files
Tail Live Logs:
Filter by Partition:
Filter by Severity:
Timestamp Range:
Common Patterns:
Standalone Mode
What is Standalone Mode?
Standalone mode runs Rippled as a single-node network where you have complete control:
No peers: Runs without connecting to other nodes
Manual ledger close: You trigger ledger closes
Deterministic: No network randomness
Fast: No consensus delays
Isolated: Perfect for testing
Starting Standalone Mode
Configuration for Standalone:
Using Standalone Mode
Check Status:
Look for:
Submit Transaction:
Manually Close Ledger:
This immediately closes the current ledger and advances to the next one.
Check Transaction:
Standalone Mode Workflow
Advantages for Debugging
Deterministic Behavior:
No network randomness
Repeatable tests
Predictable timing
Complete Control:
Manual ledger progression
No unexpected transactions
Isolated environment
Fast Iteration:
Instant ledger closes
No waiting for consensus
Quick test cycles
Safe Experimentation:
Can't affect mainnet
Easy to reset (delete database)
Test dangerous operations safely
GDB Debugging
Setting Up GDB
Install GDB:
Compile with Debug Symbols:
Launch with GDB:
Basic GDB Commands
Starting:
Breakpoints:
Execution Control:
Inspection:
Advanced:
Debugging Transaction Processing
Example Session:
Debugging Consensus
Debugging Crashes
Core Dumps:
Enable core dumps:
Run program until crash:
Analyze core dump:
Common Crash Patterns:
Log Analysis and Interpretation
Transaction Logs
Successful Payment:
Failed Payment:
Consensus Logs
Normal Consensus Round:
Disputed Transaction:
Network Logs
Peer Connection:
Connection Failure:
Performance Logs
Slow Ledger Close:
Performance Profiling
CPU Profiling
Using perf (Linux):
Using Instruments (macOS):
Interpreting Results:
Look for:
Hot functions (high CPU usage)
Unexpected call patterns
Inefficient algorithms
Lock contention
Memory Profiling
Using Valgrind:
Using AddressSanitizer:
Network Profiling
Wireshark:
Filter by:
Protocol messages
Connection handshakes
Bandwidth usage
Measuring Latency:
Testing Strategies
Unit Testing
Run All Tests:
Run Specific Test Suite:
Run with Verbose Output:
Writing Tests:
Integration Testing
Test Network Setup:
Test Scenarios:
Multi-node consensus
Network partitions
Peer discovery
Transaction propagation
Common Debugging Scenarios
Scenario 1: Transaction Not Validating
Symptoms: Transaction stuck in pending state
Debug Steps:
Check transaction status:
Check for sequence gaps:
Check logs for rejection:
Verify fee is sufficient:
Check LastLedgerSequence:
Scenario 2: Consensus Not Progressing
Symptoms: Ledger not closing, network stalled
Debug Steps:
Check validator connectivity:
Examine consensus logs:
Check network connectivity:
Look for disputes:
Scenario 3: High Memory Usage
Symptoms: Rippled consuming excessive memory
Debug Steps:
Check ledger history:
Review configuration:
Profile memory usage:
Check for leaks:
Scenario 4: Slow Ledger Closes
Symptoms: Ledgers taking >5 seconds to close
Debug Steps:
Enable performance logging:
Check transaction count:
Profile CPU usage:
Check database performance:
Hands-On Exercise
Exercise: Debug a Transaction Failure
Objective: Use debugging tools to diagnose and fix a transaction issue.
Part 1: Setup
Step 1: Start standalone mode with detailed logging
Step 2: Create test scenario with intentional issue
Part 2: Debugging Process
Step 3: Submit and observe failure
Step 4: Examine logs
Look for:
Step 5: Verify balance
Step 6: Calculate required amount
Step 7: Fix and resubmit
Part 3: Advanced Debugging
Step 8: Debug with GDB
Step 9: Set breakpoints
Step 10: Submit transaction (in another terminal)
Step 11: Examine state in GDB
Analysis Questions
What error code was returned?
tecUNFUNDED_PAYMENT
At which validation phase did it fail?
Preclaim (ledger state check)
What was the root cause?
Insufficient balance for payment + fee + reserve
How would you prevent this in client code?
Check balance before submitting
Account for reserve requirements
Include fee in calculation
What logs helped identify the issue?
Transaction partition trace logs
Preclaim failure message
Key Takeaways
Core Debugging Skills
✅ Logging System: Understand partitions, severity levels, and configuration
✅ Standalone Mode: Essential for controlled testing and debugging
✅ GDB: Set breakpoints, inspect variables, trace execution
✅ Log Analysis: Read and interpret logs to diagnose issues
✅ Performance Profiling: Identify bottlenecks and optimize
Best Practices
✅ Start Simple: Use logs before reaching for debugger
✅ Reproduce Reliably: Use standalone mode for consistent reproduction
✅ Isolate Issues: Narrow down to specific component
✅ Read the Code: Logs point you to code, understand the implementation
✅ Test Thoroughly: Write unit tests for bugs you fix
Tool Selection
✅ Logs: First line of defense, always available
✅ Standalone Mode: Controlled environment, fast iteration
✅ GDB: Deep inspection, understanding execution flow
✅ Profiling: Performance issues, optimization
✅ Tests: Regression prevention, continuous validation
Additional Resources
Official Documentation
XRP Ledger Dev Portal: xrpl.org/docs
Rippled Repository: github.com/XRPLF/rippled
Build Instructions: github.com/XRPLF/rippled/blob/develop/BUILD.md
Debugging Resources
GDB Documentation: sourceware.org/gdb/documentation
Valgrind Manual: valgrind.org/docs/manual
Linux Perf Wiki: perf.wiki.kernel.org
Codebase References
src/ripple/core/impl/JobQueue.cpp- Job queue debuggingsrc/ripple/app/main/Application.cpp- Application startup debuggingsrc/test/- Unit test examples
Related Topics
Application Layer - Understanding system architecture
Transaction Lifecycle - Understanding transaction flow
Codebase Navigation - Finding code to debug
Last updated

