add skills

This commit is contained in:
Denis Angell
2026-02-27 23:42:16 +01:00
parent b418b416b0
commit 38850e1180
64 changed files with 3429 additions and 0 deletions

99
.claude/skills/index.md Normal file
View File

@@ -0,0 +1,99 @@
# xrpld Codebase Skills Index
## Description
This is the top-level guide for all best-practices skills in this repository. Use this to understand the codebase organization and find the right skill for any task.
## When to Use Skills
Reference a skill whenever you are:
- **Writing new code** in a module - check the skill first for established patterns
- **Modifying existing code** - verify your changes follow module conventions
- **Adding a new transaction type** - see `libxrpl/tx/transactors.md` for the full template
- **Debugging** - skills list key files and common pitfalls per module
- **Reviewing code** - skills document what "correct" looks like for each module
## Codebase Architecture
The codebase is split into two main areas:
### `src/libxrpl/` — The Library (skills in `.claude/skills/libxrpl/`)
Reusable library code: data types, serialization, cryptography, ledger state, transaction processing, and storage. This is the **protocol layer**.
| Module | Responsibility |
|--------|---------------|
| `basics` | Foundational types: Buffer, Slice, base_uint, Number, logging, error contracts |
| `beast` | Support layer: Journal logging, test framework, instrumentation, IP types |
| `conditions` | Crypto-conditions (RFC): fulfillment validation, DER encoding |
| `core` | Job queue, load monitoring, hash-based message dedup |
| `crypto` | CSPRNG, secure erasure, RFC1751 encoding |
| `json` | Json::Value, parsing, serialization, StaticString optimization |
| `ledger` | ReadView/ApplyView, state tables, payment sandbox, credit ops |
| `net` | HTTP/HTTPS client, SSL certs, async I/O |
| `nodestore` | Persistent node storage: RocksDB, NuDB, Memory backends |
| `protocol` | STObject hierarchy, SField, Serializer, TER codes, Features, Keylets |
| `proto` | Protocol Buffer generated headers (gRPC API definitions) |
| `rdb` | SOCI database wrapper, checkpointing |
| `resource` | Rate limiting, endpoint tracking, abuse prevention |
| `server` | Port config, SSL/TLS, WebSocket, admin networks |
| `shamap` | SHA-256 Merkle radix tree (16-way branching, COW) |
| `tx` | Transaction pipeline: Transactor base, preflight/preclaim/doApply |
### `src/xrpld/` — The Server Application (skills in `.claude/skills/xrpld/`)
The running rippled server: application lifecycle, consensus, networking, RPC, and peer management. This is the **application layer**.
| Module | Responsibility |
|--------|---------------|
| `app` | Application singleton, ledger management, consensus adapters, services |
| `app/main` | Application initialization and lifecycle |
| `app/ledger` | Ledger storage, retrieval, immutable state management |
| `app/consensus` | RCL consensus adapters (bridges generic algorithm to rippled) |
| `app/misc` | Fee voting, amendments, SHAMapStore, TxQ, validators, NetworkOPs |
| `app/paths` | Payment path finding algorithm, trust line caching |
| `app/rdb` | Application-level database operations |
| `app/tx` | Application-level transaction handling |
| `consensus` | Generic consensus algorithm (CRTP-based, app-independent) |
| `core` | Configuration (Config.h), time keeping, network ID |
| `overlay` | P2P networking: peer connections, protocol buffers, clustering |
| `peerfinder` | Network discovery: bootcache, livecache, slot management |
| `perflog` | Performance logging and instrumentation |
| `rpc` | RPC handler dispatch, coroutine suspension, 40+ command handlers |
| `shamap` | Application-level SHAMap operations (NodeFamily) |
### `include/xrpl/` — Header Files
Headers live in `include/xrpl/` and mirror the `src/libxrpl/` structure. Each skill already references its corresponding headers in the "Key Files" section.
## Cross-Cutting Conventions
### Error Handling
- **Transaction errors**: Return `TER` enum (tesSUCCESS, tecFROZEN, temBAD_AMOUNT, etc.)
- **Logic errors**: `Throw<std::runtime_error>()`, `LogicError()`, `XRPL_ASSERT()`
- **I/O errors**: `Status` enum or `boost::system::error_code`
- **RPC errors**: Inject via `context.params`
### Assertions
```cpp
XRPL_ASSERT(condition, "ClassName::method : description"); // Debug only
XRPL_VERIFY(condition, "ClassName::method : description"); // Always enabled
```
### Logging
```cpp
JLOG(j_.warn()) << "Message"; // Always wrap in JLOG macro
```
### Memory Management
- `IntrusiveRefCounts` + `SharedIntrusive` for shared ownership in libxrpl
- `std::shared_ptr` for shared ownership in xrpld
- `std::unique_ptr` for exclusive ownership
- `CountedObject<T>` mixin for instance tracking
### Feature Gating
```cpp
if (ctx.rules.enabled(featureMyFeature)) { /* new behavior */ }
```
### Code Organization
- Headers in `include/xrpl/`, implementations in `src/libxrpl/` or `src/xrpld/`
- `#pragma once` (never `#ifndef` guards)
- `namespace xrpl { }` for all code
- `detail/` namespace for internal helpers
- Factory functions: `make_*()` returning `unique_ptr` or `shared_ptr`

View File

@@ -0,0 +1,79 @@
# Basics Module Best Practices
## Description
Use when working with foundational utilities in `src/libxrpl/basics/` or `include/xrpl/basics/`. Covers data structures, memory management, logging, numeric operations, error handling, and string utilities.
## Responsibility
Provides fundamental building blocks for the entire codebase: memory types (Buffer, Slice, Blob), intrusive smart pointers, arbitrary-precision integers (base_uint), multi-precision decimal arithmetic (Number), logging infrastructure, exception handling contracts, and platform abstractions.
## Key Patterns
### Memory Types
- **Slice** - Non-owning view into contiguous bytes (like std::span)
- **Buffer** - Owning byte container (like std::vector<uint8_t>)
- **Blob** - Alias for std::vector<unsigned char>
- Prefer `Slice` for read-only parameters, `Buffer` for owned data
### Intrusive Smart Pointers
```cpp
// Prefer intrusive pointers over std::shared_ptr for minimal overhead
// Object embeds its own reference count
class MyObject : public IntrusiveRefCounts {
// ...
};
// Use SharedIntrusive<MyObject> when weak pointers needed
```
### Error Handling
```cpp
// Contract-based exceptions (logs call stack then throws)
Throw<std::runtime_error>("Invalid source file");
LogThrow("exception message");
// Logic errors for invariant violations
LogicError("This should never happen");
// Assertions (fuzzing-aware)
XRPL_ASSERT(condition, "function_name : description");
XRPL_VERIFY(condition, "message"); // Always enabled, not just debug
```
### Logging
```cpp
// Use JLOG macro - short-circuits if level disabled
JLOG(debugLog().warn()) << "Message: " << value;
JLOG(j_.trace()) << "Verbose detail";
// Never: debugLog().warn() << "msg"; // Missing JLOG wastes formatting
```
### Number Precision
```cpp
// Use Number for multi-precision decimal arithmetic
// Always use RAII guard for rounding mode
NumberRoundModeGuard mg(Number::towards_zero);
auto result = amount * rate;
// Guard restores previous mode on scope exit
```
### base_uint Template
```cpp
// Typed big-endian integers: base_uint<Bits, Tag>
// Tag prevents mixing unrelated types of same width
using uint256 = base_uint<256, void>;
using AccountID = base_uint<160, detail::AccountIDTag>;
```
## Common Pitfalls
- Never use `std::shared_ptr` when IntrusiveRefCounts is available - it adds a separate allocation
- Never format log messages without JLOG wrapper - wastes CPU when level is disabled
- Never use raw `assert()` - use `XRPL_ASSERT` for fuzzing instrumentation support
- Never mix `Buffer` and `Slice` ownership semantics - Slice does NOT own its data
## Key Files
- `include/xrpl/basics/IntrusiveRefCounts.h` - Atomic reference counting
- `include/xrpl/basics/IntrusivePointer.h` - Smart pointer using intrusive refs
- `include/xrpl/basics/base_uint.h` - Arbitrary-length big-endian integers
- `include/xrpl/basics/Buffer.h`, `Blob.h`, `Slice.h` - Memory types
- `include/xrpl/basics/Number.h` - Multi-precision decimal arithmetic
- `include/xrpl/basics/Log.h` - Logging infrastructure
- `include/xrpl/basics/contract.h` - Throw, LogicError, XRPL_ASSERT

View File

@@ -0,0 +1,62 @@
# Beast Module Best Practices
## Description
Use when working with the Beast support layer in `src/libxrpl/beast/` or `include/xrpl/beast/`. Covers networking types, unit testing, Journal logging, and instrumentation.
## Responsibility
Library support layer providing network types (IP addresses, endpoints), unit testing framework, Journal/logging abstractions, instrumentation/assertion macros, and type introspection utilities.
## Key Patterns
### Journal Logging
```cpp
// Journal wraps a Sink pointer - copy by value is cheap
beast::Journal const j_;
// Severity levels: kTrace, kDebug, kInfo, kWarning, kError, kFatal
JLOG(j_.warn()) << "User-facing issue";
JLOG(j_.debug()) << "Implementation detail";
JLOG(j_.trace()) << "Very verbose diagnostic";
JLOG(j_.error()) << "Unexpected failure";
```
### Unit Testing
```cpp
class MyTest : public beast::unit_test::suite {
void run() override {
testcase("feature description");
BEAST_EXPECT(value == expected); // Non-fatal assertion
BEAST_REQUIRE(value == expected); // Fatal - aborts test on failure
}
};
BEAST_DEFINE_TESTSUITE(MyTest, module, ripple);
```
### Instrumentation
```cpp
// Use XRPL_ASSERT for debug-only assertions (fuzzing-aware)
XRPL_ASSERT(ptr != nullptr, "MyClass::method : null pointer");
// Format: "ClassName::methodName : description"
// The string format is important for fuzzing instrumentation
```
### IP Endpoint Types
```cpp
// Use beast::IP::Endpoint for network addresses
beast::IP::Endpoint endpoint;
// Supports both IPv4 and IPv6
// Includes port information
```
## Common Pitfalls
- Never use `BEAST_EXPECT` when the test cannot continue on failure - use `BEAST_REQUIRE` instead
- Never create a Journal with a dangling Sink pointer - ensure Sink outlives Journal
- Always include "ClassName::methodName" prefix in XRPL_ASSERT messages for traceability
## Key Files
- `include/xrpl/beast/utility/Journal.h` - Log sink abstraction
- `include/xrpl/beast/unit_test/suite.h` - Test framework
- `include/xrpl/beast/utility/instrumentation.h` - XRPL_ASSERT macros
- `include/xrpl/beast/net/IPEndpoint.h` - Network endpoint types
- `include/xrpl/beast/core/SemanticVersion.h` - Version parsing

View File

@@ -0,0 +1,33 @@
# Beast Clock Module Best Practices
## Description
Use when working with clock abstractions in `src/libxrpl/beast/clock/` or `include/xrpl/beast/clock/`. Covers abstract clock interfaces and manual clock implementations for testing.
## Responsibility
Provides clock abstractions that decouple code from system time, enabling deterministic testing with manual clocks and supporting different time granularities.
## Key Patterns
### Abstract Clock Interface
```cpp
// Use abstract_clock<T> for testable time-dependent code
// Production: uses system clock
// Testing: uses manual_clock for deterministic control
```
### Manual Clock for Testing
```cpp
// Advance time manually in tests
manual_clock<std::chrono::steady_clock> clock;
clock.advance(std::chrono::seconds(30));
// Deterministic - no flaky tests from timing issues
```
## Common Pitfalls
- Never use `std::chrono::system_clock::now()` directly - inject clock dependency
- Always use manual_clock in unit tests for deterministic behavior
- Be aware of Ripple Epoch vs Unix Epoch when working with ledger timestamps
## Key Files
- `include/xrpl/beast/clock/abstract_clock.h` - Abstract clock interface
- `include/xrpl/beast/clock/manual_clock.h` - Testable clock implementation

View File

@@ -0,0 +1,29 @@
# Beast Core Module Best Practices
## Description
Use when working with core beast utilities in `src/libxrpl/beast/core/` or `include/xrpl/beast/core/`. Covers semantic versioning and core type utilities.
## Responsibility
Provides core utilities including semantic version parsing/comparison, system abstractions, and foundational type support.
## Key Patterns
### Semantic Version Parsing
```cpp
// Parse version strings following semver spec
SemanticVersion version;
if (version.parse("1.2.3-beta")) {
auto major = version.majorVersion;
auto minor = version.minorVersion;
auto patch = version.patchVersion;
}
// Supports comparison operators for version ordering
```
## Common Pitfalls
- Always validate version strings before using - parse() returns false on invalid input
- Remember that pre-release versions have lower precedence than release versions
## Key Files
- `include/xrpl/beast/core/SemanticVersion.h` - Version parsing and comparison
- `src/libxrpl/beast/core/SemanticVersion.cpp` - Implementation

View File

@@ -0,0 +1,41 @@
# Beast Insight Module Best Practices
## Description
Use when working with metrics and monitoring in `src/libxrpl/beast/insight/` or `include/xrpl/beast/insight/`. Covers counters, gauges, and metrics collection.
## Responsibility
Provides metrics collection infrastructure for monitoring application performance: counters for cumulative values, gauges for point-in-time measurements, and hooks for metrics export.
## Key Patterns
### Metrics Types
```cpp
// Counter: Monotonically increasing value (e.g., total requests)
insight::Counter requests;
++requests;
// Gauge: Point-in-time value (e.g., current connections)
insight::Gauge connections;
connections = currentCount;
// Event: Timed operation tracking
insight::Event latency;
```
### Null Metrics
```cpp
// Use NullCollector when metrics disabled
// All operations become no-ops with zero overhead
auto collector = insight::NullCollector::New();
```
## Common Pitfalls
- Use Counter for cumulative values, Gauge for current state - don't mix them
- Always use NullCollector for tests - avoids metrics overhead
- Never store raw metric values in long-lived objects - use the insight types
## Key Files
- `include/xrpl/beast/insight/Counter.h` - Cumulative counter
- `include/xrpl/beast/insight/Gauge.h` - Point-in-time gauge
- `include/xrpl/beast/insight/Collector.h` - Metrics collector interface
- `include/xrpl/beast/insight/NullCollector.h` - No-op collector

View File

@@ -0,0 +1,46 @@
# Beast Net Module Best Practices
## Description
Use when working with network types in `src/libxrpl/beast/net/` or `include/xrpl/beast/net/`. Covers IP address and endpoint representations.
## Responsibility
Provides network type abstractions for IP addresses (v4 and v6) and endpoints (address + port), with parsing utilities and comparison operators.
## Key Patterns
### IP Endpoint Usage
```cpp
// beast::IP::Endpoint combines address + port
beast::IP::Endpoint endpoint(
beast::IP::Address::from_string("127.0.0.1"), 51235);
// Supports both IPv4 and IPv6
beast::IP::Endpoint v6endpoint(
beast::IP::Address::from_string("::1"), 51235);
```
### Address Parsing
```cpp
// Parse from string with error handling
boost::system::error_code ec;
auto address = beast::IP::Address::from_string(input, ec);
if (ec) { /* handle invalid address */ }
```
### Comparison and Ordering
```cpp
// Endpoints support full comparison for use in containers
std::set<beast::IP::Endpoint> endpoints;
std::map<beast::IP::Endpoint, Consumer> consumers;
```
## Common Pitfalls
- Always handle both IPv4 and IPv6 when working with endpoints
- Use error_code overload of from_string to handle invalid input gracefully
- Never assume address format - always parse and validate
## Key Files
- `include/xrpl/beast/net/IPEndpoint.h` - Combined address + port
- `include/xrpl/beast/net/IPAddress.h` - IP address types
- `include/xrpl/beast/net/IPAddressV4.h` - IPv4 specific
- `include/xrpl/beast/net/IPAddressV6.h` - IPv6 specific

View File

@@ -0,0 +1,47 @@
# Beast Utility Module Best Practices
## Description
Use when working with beast utility classes in `src/libxrpl/beast/utility/` or `include/xrpl/beast/utility/`. Covers Journal logging, instrumentation, and type introspection.
## Responsibility
Provides utility classes including the Journal logging abstraction (Sink + Stream), XRPL_ASSERT/XRPL_VERIFY instrumentation macros, and type introspection helpers.
## Key Patterns
### Journal and Sink Architecture
```cpp
// Sink: abstract base for log message routing
class Sink {
virtual void write(beast::severities::Severity level, std::string const& text) = 0;
void console(bool output); // Enable console output
};
// Journal: lightweight wrapper around Sink* (copy by value)
beast::Journal j(sinkPtr);
JLOG(j.warn()) << "Message";
// WrappedSink: adds prefix to all messages
beast::WrappedSink wrappedSink(parentSink, "MyModule");
```
### Instrumentation Macros
```cpp
// XRPL_ASSERT: Debug-only assertion (disabled in release, fuzzing-aware)
XRPL_ASSERT(condition, "ClassName::method : description");
// XRPL_VERIFY: Always-enabled assertion
XRPL_VERIFY(condition, "ClassName::method : description");
// Format convention: "ClassName::methodName : human-readable description"
```
## Common Pitfalls
- Always use "ClassName::methodName" prefix in assertion messages
- Journal is cheap to copy (just a pointer) - pass by value is fine
- WrappedSink must outlive any Journal created from it
- XRPL_ASSERT is no-op in release builds - don't put side effects in the condition
## Key Files
- `include/xrpl/beast/utility/Journal.h` - Log sink abstraction and Journal
- `include/xrpl/beast/utility/instrumentation.h` - XRPL_ASSERT, XRPL_VERIFY
- `include/xrpl/beast/utility/WrappedSink.h` - Prefixed log sink

View File

@@ -0,0 +1,63 @@
# Conditions Module Best Practices
## Description
Use when working with crypto-conditions in `src/libxrpl/conditions/` or `include/xrpl/conditions/`. Implements the RFC crypto-conditions specification.
## Responsibility
Implements crypto-conditions for conditional payments: condition fingerprints, fulfillment validation, multiple condition types (preimage, prefix, threshold, RSA, Ed25519), and binary DER serialization/deserialization.
## Key Patterns
### Fulfillment Interface
```cpp
// Abstract base for all fulfillment types
struct Fulfillment {
virtual ~Fulfillment() = default;
virtual Buffer fingerprint() const = 0;
virtual Type type() const = 0;
virtual bool validate(Slice data) const = 0;
virtual std::uint32_t cost() const = 0;
virtual Condition condition() const = 0;
};
```
### Factory Pattern for Deserialization
```cpp
// Returns unique_ptr + sets error_code (non-throwing)
std::unique_ptr<Fulfillment> deserialize(Slice s, std::error_code& ec);
// Usage:
std::error_code ec;
auto fulfillment = Fulfillment::deserialize(data, ec);
if (ec) return {}; // Early return on error
```
### Type-Safe Enums
```cpp
enum class Type : std::uint8_t {
preimageSha256 = 0,
prefixSha256 = 1,
thresholdSha256 = 2,
rsaSha256 = 3,
ed25519Sha256 = 4
};
```
### Size Limits
```cpp
static constexpr std::size_t maxSerializedCondition = 128;
static constexpr std::size_t maxSerializedFulfillment = 256;
// Always respect these limits when creating conditions
```
## Common Pitfalls
- Never throw exceptions from binary parsing - use `std::error_code` parameter pattern
- Always check `ec` after deserialization before using the result
- Respect `maxSerializedFulfillment` size limits
## Key Files
- `include/xrpl/conditions/Condition.h` - Base condition with type/fingerprint/cost
- `include/xrpl/conditions/Fulfillment.h` - Abstract fulfillment interface
- `include/xrpl/conditions/detail/PreimageSha256.h` - Preimage implementation
- `include/xrpl/conditions/detail/utils.h` - DER encoding/decoding
- `include/xrpl/conditions/detail/error.h` - Error codes

View File

@@ -0,0 +1,61 @@
# Core Module Best Practices
## Description
Use when working with job processing and routing infrastructure in `src/libxrpl/core/` or `include/xrpl/core/`. Covers job queues, load monitoring, and message deduplication.
## Responsibility
Distributed job processing with priority levels, load monitoring for execution tracking, and hash-based message suppression/routing for peer deduplication.
## Key Patterns
### Job Queue Priorities
```cpp
// Job types ordered by priority (lower enum = lower priority)
enum JobType {
jtINVALID = -1,
jtPACK, // Lowest priority
jtCLIENT_WEBSOCKET,
// ...
jtVALIDATION_t, // Trusted validation (high)
jtADMIN // Admin operations (highest)
};
// Position in enum determines scheduling priority
```
### HashRouter for Deduplication
```cpp
// Suppress duplicate messages from peers
std::optional<std::set<PeerShortID>> shouldRelay(uint256 const& key);
// Returns {} if already relayed, set of peers if should relay
// Track peer that sent a message
auto result = router.addSuppressionPeer(key, peer);
```
### RAII Locking
```cpp
// Always use lock_guard for mutex protection
std::lock_guard lock(mutex_);
auto result = emplace(key);
result.first.addPeer(peer);
return result.second; // Return while lock is held
```
### Optional Return Types
```cpp
// Use std::optional for "maybe" results
std::optional<std::set<PeerShortID>> shouldRelay(uint256 const& key);
// Caller checks: if (auto peers = shouldRelay(key)) { ... }
```
## Common Pitfalls
- Never hold locks longer than necessary - lock_guard scope = critical section
- Never ignore job priorities when scheduling work - use appropriate JobType
- Always let HashRouter handle message deduplication rather than implementing custom logic
## Key Files
- `include/xrpl/core/Job.h` - Job wrapper with type, index, function
- `include/xrpl/core/JobTypes.h` - Job type enumerations and metadata
- `include/xrpl/core/JobQueue.h` - Priority queue for dispatching jobs
- `include/xrpl/core/HashRouter.h` - Duplicate message suppression
- `include/xrpl/core/LoadMonitor.h` - Job execution time tracking

View File

@@ -0,0 +1,32 @@
# Core Detail Module Best Practices
## Description
Use when working with internal core implementation details in `src/libxrpl/core/detail/`. These are private implementation helpers not intended for direct external use.
## Responsibility
Internal implementation details for the core module, including helper functions and private data structures used by JobQueue, HashRouter, and LoadMonitor.
## Key Patterns
### Detail Namespace Convention
```cpp
namespace xrpl {
namespace detail {
// Internal helpers - not part of public API
// May change without notice between versions
}
}
```
### Encapsulation
- Code in `detail/` should only be included by its parent module
- Never include detail headers from outside the core module
- If you need functionality from detail, use the public core API instead
## Common Pitfalls
- Never depend on detail namespace types or functions from outside the core module
- Detail implementations may change without preserving API compatibility
- Always use the public `core/` headers for stable interfaces
## Key Files
- Files in this directory are implementation details of `include/xrpl/core/` headers

View File

@@ -0,0 +1,51 @@
# Crypto Module Best Practices
## Description
Use when working with cryptographic operations in `src/libxrpl/crypto/` or `include/xrpl/crypto/`. Covers CSPRNG, secure memory erasure, and RFC1751 encoding.
## Responsibility
Low-level cryptographic operations: cryptographically secure random number generation (CSPRNG), RFC1751 word-based encoding for keys, and secure memory erasure to prevent sensitive data leakage.
## Key Patterns
### CSPRNG Usage
```cpp
// Thread-safe PRNG - use the global singleton
auto& prng = crypto_prng();
// Generate random value
auto randomValue = prng();
// Fill buffer with random bytes
prng(buffer.data(), buffer.size());
// NEVER create your own csprng_engine - use crypto_prng()
```
### Secure Memory Erasure
```cpp
// Use volatile memset to prevent compiler optimization
secure_erase(secretKey.data(), secretKey.size());
// MUST be called before destroying any buffer containing secrets
```
### Engine Concept Conformance
```cpp
// csprng_engine meets UniformRandomNumberEngine requirements
using result_type = std::uint64_t;
static constexpr result_type min();
static constexpr result_type max();
// Can be used with standard distributions
```
## Common Pitfalls
- Never create a local `csprng_engine` instance - always use `crypto_prng()` singleton
- Never use `std::rand()` or `std::mt19937` for security-sensitive operations
- Always call `secure_erase()` on secret key material before destruction
- Never copy or move a `csprng_engine` - it's non-copyable and non-movable by design
- Be aware of OpenSSL version differences - locking behavior varies
## Key Files
- `include/xrpl/crypto/csprng.h` - Thread-safe PRNG engine
- `include/xrpl/crypto/RFC1751.h` - Human-readable key encoding
- `include/xrpl/crypto/secure_erase.h` - Volatile memset for secrets

View File

@@ -0,0 +1,68 @@
# JSON Module Best Practices
## Description
Use when working with JSON parsing and serialization in `src/libxrpl/json/` or `include/xrpl/json/`. Covers Json::Value, readers, writers, and custom allocators.
## Responsibility
JSON value representation (discriminated union for all JSON types), parsing text to Value objects, serialization from Value to text, and custom string allocation for memory control.
## Key Patterns
### Json::Value Usage
```cpp
// Discriminated union - supports all JSON types
Json::Value obj(Json::objectValue);
obj["key"] = "string_value";
obj["count"] = 42u;
obj["flag"] = true;
obj["nested"] = Json::objectValue;
// Array creation
Json::Value arr(Json::arrayValue);
arr.append("item");
arr.append(123);
// Type checking
if (obj.isObject()) { ... }
if (obj.isMember("key")) { ... }
```
### StaticString Optimization
```cpp
// Use StaticString for compile-time known keys to avoid allocation
static const Json::StaticString code("code");
static const Json::StaticString message("message");
object[code] = 1234; // No dynamic allocation for key
object[message] = "ok"; // Key stored as pointer, not copied
```
### Value Type Enum
```cpp
enum ValueType {
nullValue = 0,
intValue, uintValue, realValue,
stringValue, booleanValue,
arrayValue, objectValue
};
// Check type before accessing to avoid undefined behavior
```
### Lazy Initialization
```cpp
// Container elements auto-created on access (like JavaScript)
Json::Value obj;
obj["newKey"]["nested"] = 1; // Creates intermediate objects automatically
// Be aware: accessing a non-existent key creates it
```
## Common Pitfalls
- Accessing a non-existent key via `operator[]` creates a null entry - use `isMember()` to check first if you don't want side effects
- Use `const` overload of `operator[]` to avoid auto-creation: `obj["key"]` on const ref returns null reference
- Prefer `StaticString` for frequently-used keys to avoid repeated allocations
- Never assume JSON numeric types - check `isInt()`, `isUInt()`, `isDouble()` explicitly
## Key Files
- `include/xrpl/json/json_value.h` - Main Value class
- `include/xrpl/json/json_reader.h` - Text-to-Value parser
- `include/xrpl/json/json_writer.h` - Value-to-text serializer
- `include/xrpl/json/json_forwards.h` - Forward declarations and aliases

View File

@@ -0,0 +1,84 @@
# Ledger Module Best Practices
## Description
Use when working with ledger state management in `src/libxrpl/ledger/` or `include/xrpl/ledger/`. Covers views, state tables, payments, and credit operations.
## Responsibility
Manages the state of the distributed ledger: abstractions for viewing, reading, and applying transactions to ledger state. Handles account ownership tracking, trust lines, payment processing, directory management, and credential verification.
## Key Patterns
### ReadView vs ApplyView
```cpp
// ReadView: Read-only access to ledger state
bool exists = view.exists(keylet::account(accountID));
auto sle = view.read(keylet::account(accountID)); // Returns shared_ptr<SLE const>
// ApplyView: Mutable access for transaction application
auto sle = view.peek(keylet::account(accountID)); // Returns shared_ptr<SLE>
sle->setFieldAmount(sfBalance, newBalance);
view.update(sle); // Commit change
view.insert(newSle); // Create new entry
view.erase(sle); // Remove entry
```
### Enum-Based Control (No Boolean Blindness)
```cpp
// NEVER: bool ignoreFreeze = true;
// ALWAYS: Use named enums
enum FreezeHandling { fhIGNORE_FREEZE, fhZERO_IF_FROZEN };
enum AuthHandling { ahIGNORE_AUTH, ahZERO_IF_UNAUTHORIZED };
STAmount accountHolds(ReadView const& view, AccountID const& account,
Currency const& currency, AccountID const& issuer,
FreezeHandling zeroIfFrozen, beast::Journal j);
```
### Asset Variant Handling
```cpp
// Use std::visit for Asset (Issue or MPTIssue)
return std::visit(
[&](auto const& issue) {
return isIndividualFrozen(view, account, issue);
},
asset.value());
```
### PaymentSandbox for Isolation
```cpp
// Test payment effects before committing
PaymentSandbox sandbox(&view);
// ... apply changes to sandbox ...
sandbox.apply(view); // Commit all changes atomically
// Or let sandbox destruct to discard
```
### TER Return Codes
```cpp
// Transaction results are returned as TER, not exceptions
TER result = doApply();
if (result != tesSUCCESS) return result;
// TER categories: tes (success), tec (claimed fee), tef (failure), tel (local), tem (malformed)
```
### Depth Limiting
```cpp
// Recursive operations use depth parameter to prevent infinite recursion
TER checkVaultState(ReadView const& view, AccountID const& id, int depth = 0);
if (depth > maxDepth) return tecINTERNAL;
```
## Common Pitfalls
- Never use `read()` when you need to modify - use `peek()` instead
- Never forget to call `view.update(sle)` after modifying a peeked SLE
- Never use bare booleans for control flags - use the enum types
- Always check for frozen/unauthorized states before operating on trust lines
- Never ignore TER return values - propagate them up the call chain
## Key Files
- `include/xrpl/ledger/View.h` - Core read/write operations (largest file)
- `include/xrpl/ledger/ReadView.h` - Read-only interface
- `include/xrpl/ledger/ApplyView.h` - Mutable interface
- `src/libxrpl/ledger/PaymentSandbox.cpp` - Isolated payment testing
- `src/libxrpl/ledger/ApplyStateTable.cpp` - State change management
- `src/libxrpl/ledger/Credit.cpp` - Trust line and IOU operations

View File

@@ -0,0 +1,58 @@
# Net Module Best Practices
## Description
Use when working with network communication in `src/libxrpl/net/` or `include/xrpl/net/`. Covers HTTP/HTTPS client functionality and SSL certificate management.
## Responsibility
Provides HTTP/HTTPS client functionality for network requests, including SSL certificate registration, asynchronous request handling with boost::asio, and callback-based completion.
## Key Patterns
### Async HTTP with Callbacks
```cpp
// Callback returns bool indicating success/continuation
HTTPClient::get(
bSSL, io_context,
std::deque<std::string>{"site1.com", "site2.com"}, // Fallback sites
443, "/path",
maxResponseBytes,
timeout,
[](boost::system::error_code const& ec, int status, std::string const& body) -> bool {
if (ec) return false; // Stop
// Process response
return true; // Success
},
headers, journal);
```
### Lifetime Management with shared_from_this
```cpp
// Async callbacks use intrusive_ptr for safe lifetime
class HTTPClientImp : public HTTPClient,
public std::enable_shared_from_this<HTTPClientImp> {
void startAsync() {
auto self = shared_from_this(); // Prevent premature destruction
// ... schedule async operations ...
}
};
```
### Deadline Timers
```cpp
// Always set timeouts for network operations
boost::asio::basic_waitable_timer<std::chrono::steady_clock> timer_;
timer_.expires_after(std::chrono::seconds(timeout));
// Cancel pending operation on timeout
```
## Common Pitfalls
- Never start async operations without capturing shared_from_this - object may be destroyed before callback
- Always set deadline timers on network operations to prevent hanging connections
- Always set maximum response size limits to prevent resource exhaustion
- Never assume DNS resolution will succeed - handle resolver errors
## Key Files
- `include/xrpl/net/HTTPClient.h` - Main HTTP client interface
- `src/libxrpl/net/HTTPClient.cpp` - Implementation with async I/O
- `src/libxrpl/net/RegisterSSLCerts.cpp` - SSL certificate registration
- `include/xrpl/net/HTTPClientSSLContext.h` - SSL context management

View File

@@ -0,0 +1,24 @@
# Net Images Module Best Practices
## Description
Use when working with static image assets in `src/libxrpl/net/images/`. Contains embedded image data used by the HTTP server.
## Responsibility
Stores static image assets (favicons, logos) as embedded byte arrays for serving via the built-in HTTP server without external file dependencies.
## Key Patterns
### Embedded Assets
```cpp
// Images stored as static const byte arrays
// Compiled directly into the binary - no file I/O needed at runtime
static unsigned char const favicon[] = { /* ... */ };
```
## Common Pitfalls
- Keep embedded images small - they increase binary size
- Use appropriate image formats (ICO for favicons, PNG for logos)
- Update both the source image and the byte array when changing assets
## Key Files
- `src/libxrpl/net/images/` - Static image byte arrays embedded in the binary

View File

@@ -0,0 +1,68 @@
# NodeStore Module Best Practices
## Description
Use when working with persistent node storage in `src/libxrpl/nodestore/` or `include/xrpl/nodestore/`. Covers the storage abstraction layer, backend implementations, and caching.
## Responsibility
Abstraction layer for persistent storage of ledger nodes (SHAMap leaves and inner nodes). Supports multiple backend implementations (RocksDB, NuDB, Memory, Null) with a plugin architecture, caching, and async operations.
## Key Patterns
### Abstract Factory for Backends
```cpp
// Backend is pure virtual - concrete implementations selected at runtime
class Backend {
virtual ~Backend() = default;
virtual Status fetch(void const* key, std::shared_ptr<NodeObject>*) = 0;
virtual void store(std::shared_ptr<NodeObject> const&) = 0;
virtual void storeBatch(Batch const& batch) = 0;
};
// Backends: RocksDB, NuDB, Memory (testing), Null (disabled)
```
### Batch Operations
```cpp
// Always prefer batch operations for multiple reads/writes
virtual std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
fetchBatch(std::vector<uint256 const*> const& hashes) = 0;
virtual void storeBatch(Batch const& batch) = 0;
// Significantly reduces I/O overhead vs individual operations
```
### Status Enum (Not Exceptions)
```cpp
enum class Status { ok, notFound, keyTooBig, /* ... */ };
// I/O operations return Status, NOT throw exceptions
auto [objects, status] = backend->fetchBatch(hashes);
if (status != Status::ok) { /* handle */ }
```
### Configuration via Section
```cpp
// Backend options come from config file sections
RocksDBBackend(int keyBytes, Section const& keyValues,
Scheduler& scheduler, beast::Journal journal);
// Allows runtime tuning without recompilation
```
### Async Fetch with Scheduler
```cpp
// Non-blocking reads via scheduler integration
virtual void asyncFetch(uint256 const& hash,
std::function<void(std::shared_ptr<NodeObject>)>&& callback);
// Callback invoked on scheduler thread
```
## Common Pitfalls
- Never use individual fetch/store in tight loops - use batch operations
- Never throw exceptions from backend implementations - return Status enum
- Always configure appropriate cache sizes for the workload
- Never assume a fetch will succeed - always check Status
- Use Memory backend for unit tests, never RocksDB
## Key Files
- `include/xrpl/nodestore/Database.h` - Main storage interface
- `include/xrpl/nodestore/Backend.h` - Abstract backend interface
- `include/xrpl/nodestore/Manager.h` - Backend factory
- `include/xrpl/nodestore/NodeObject.h` - Individual node wrapper
- `src/libxrpl/nodestore/BatchWriter.cpp` - Batch write optimization

View File

@@ -0,0 +1,66 @@
# NodeStore Backend Module Best Practices
## Description
Use when working with storage backend implementations in `src/libxrpl/nodestore/backend/`. Covers RocksDB, NuDB, Memory, and Null backend factories.
## Responsibility
Concrete backend implementations for the NodeStore abstraction layer. Each backend provides persistent (or ephemeral) storage with different performance characteristics and use cases.
## Key Patterns
### Backend Factory Registration
```cpp
// Each backend is a factory that creates Backend instances
// Registered by name in the Manager
class RocksDBFactory : public Factory {
std::string getName() const override { return "RocksDB"; }
std::unique_ptr<Backend> createInstance(...) override;
};
```
### RocksDB Configuration
```cpp
// Extensive tuning via config Section
// Key options:
// open_files - Max open file descriptors
// filter_bits - Bloom filter bits per key (default 10)
// cache_mb - Block cache size in MB
// file_size_mb - Target SST file size
// compression - snappy (default), zlib, lz4, none
// block_size - Block size in KB (default 4)
// num_threads - Background compaction threads
```
### NuDB for Deterministic Storage
```cpp
// NuDB supports deterministic initialization
// Useful for reproducible test databases
// Hash-based storage with direct memory-mapped I/O
// Lower CPU overhead than RocksDB for write-heavy workloads
```
### Memory Backend for Testing
```cpp
// In-memory storage - fast but not persistent
// Use for unit tests only
// Thread-safe with internal mutex
```
### Null Backend for Disabled Storage
```cpp
// No-op backend - all operations succeed but store nothing
// Use when storage feature is disabled in config
```
## Common Pitfalls
- Use Memory backend for tests, never RocksDB (test isolation and speed)
- Always tune RocksDB bloom filter bits - default 10 is good for most workloads
- NuDB doesn't support range queries - only point lookups by hash
- Never use Null backend in production - data loss guaranteed
- Always configure appropriate open_files limits for the OS
## Key Files
- `src/libxrpl/nodestore/backend/RocksDBFactory.cpp` - RocksDB backend (~12.5KB)
- `src/libxrpl/nodestore/backend/NuDBFactory.cpp` - NuDB backend (~12KB)
- `src/libxrpl/nodestore/backend/MemoryFactory.cpp` - In-memory backend (~5KB)
- `src/libxrpl/nodestore/backend/NullFactory.cpp` - No-op backend (~2KB)

View File

@@ -0,0 +1,35 @@
# Proto Module Best Practices
## Description
Use when working with Protocol Buffer definitions in `include/xrpl/proto/`. Covers gRPC API definitions and generated protobuf headers.
## Responsibility
Contains Protocol Buffer generated headers defining the gRPC API for rippled. These define the wire format for RPC communication between clients and the server.
## Key Patterns
### Proto Organization
```
include/xrpl/proto/
└── org/xrpl/rpc/v1/
└── *.proto generated headers
```
### Usage
```cpp
#include <xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h>
// Use generated types for gRPC request/response
```
### Versioning
- API is versioned under `org/xrpl/rpc/v1/`
- New versions get a new directory (v2/, etc.)
- Never modify generated files directly - modify the .proto source
## Common Pitfalls
- Never hand-edit generated .pb.h files - regenerate from .proto sources
- Always use the versioned path (v1/) when including proto headers
- Proto types are for serialization only - convert to native types for business logic
## Key Files
- `include/xrpl/proto/org/xrpl/rpc/v1/` - Generated gRPC API headers

View File

@@ -0,0 +1,123 @@
# Protocol Module Best Practices
## Description
Use when working with serialization and data types in `src/libxrpl/protocol/` or `include/xrpl/protocol/`. Covers STObject hierarchy, SField registry, serialization, TER codes, features, and keylets.
## Responsibility
Defines serialization formats, data types, and protocol constants. Handles conversion between C++ objects and wire format, JSON representation, and database storage. The largest module in libxrpl with 60+ files.
## Key Patterns
### STObject Hierarchy
```cpp
// STBase is the abstract root for all serializable types
// Concrete types: STInteger<N>, STBlob, STAmount, STArray, STObject, STPathSet, STVector256
// Access fields type-safely via SField references
auto amount = obj[sfAmount]; // Returns STAmount
auto flags = obj[sfFlags]; // Returns uint32
auto dest = obj[sfDestination]; // Returns AccountID
auto has = obj.isFieldPresent(sfMemos); // Check presence
```
### SField Registry
```cpp
// Fields are statically registered - never create SField at runtime
// SField carries type information and field ID
extern SField const sfAmount; // STAmount type
extern SField const sfFlags; // STInteger<uint32> type
extern SField const sfDestination; // STAccount type
// Field IDs are protocol-defined and must not change
```
### Serializer for Binary Format
```cpp
// Deterministic binary serialization
Serializer s;
obj.add(s); // Append binary representation
auto blob = s.peekData(); // Get bytes
// Deserialization
SerialIter sit(blob.data(), blob.size());
auto obj = std::make_shared<STObject>(sit, sfTransaction);
```
### Bidirectional JSON/Binary Conversion
```cpp
// Object to JSON
Json::Value json = obj.getJson(JsonOptions::none);
// JSON to Object
STParsedJSONObject parsed("tx_json", json);
if (parsed.object) { /* use parsed.object */ }
```
### TER (Transaction Error Result) Codes
```cpp
// Categories:
// tes - success (tesSUCCESS)
// tec - claimed fee, no effect (tecNO_DST, tecFROZEN, tecINSUFFICIENT_RESERVE)
// tef - failure (tefFAILURE)
// tel - local error (telNETWORK_ID_MAKES_TX_NON_CANONICAL)
// tem - malformed (temINVALID, temBAD_AMOUNT, temDISABLED)
// Check categories:
isTesSuccess(ter) // ter == tesSUCCESS
isTecClaim(ter) // tec range
isTemMalformed(ter) // tem range
```
### Feature/Amendment Flags
```cpp
// Gate new behavior on amendments
if (ctx.rules.enabled(featureMyFeature)) {
// New behavior
} else {
// Legacy behavior
}
// Register features in Feature.cpp
```
### Keylet for Ledger Entry Keys
```cpp
// Type-safe ledger key generation
auto key = keylet::account(accountID); // Account root
auto key = keylet::line(a, b, currency); // Trust line
auto key = keylet::offer(account, seq); // Offer
auto key = keylet::nftoken(tokenID); // NFT
// Keylet carries both the key (uint256) and the expected ledger entry type
```
### SOTemplate for Schema Validation
```cpp
// Define expected fields for a ledger entry type
SOTemplate const ltACCOUNT_ROOT = {
{sfAccount, soeREQUIRED},
{sfBalance, soeREQUIRED},
{sfFlags, soeREQUIRED},
{sfSequence, soeREQUIRED},
{sfOwnerCount, soeDEFAULT},
// ...
};
```
## Common Pitfalls
- Never create SField instances at runtime - they are static protocol definitions
- Never modify field IDs - they are part of the binary protocol
- Always use `isFieldPresent()` before accessing optional fields
- Never ignore TER return values - they carry critical error information
- Always gate new fields/behavior on feature amendments for consensus safety
- Respect JSON parsing depth limit of 10 to prevent stack overflow
- Use `[[nodiscard]]` on functions returning TER
## Key Files
- `include/xrpl/protocol/STObject.h` - Generic structured object container
- `include/xrpl/protocol/STAmount.h` - XRP and IOU amounts
- `include/xrpl/protocol/SField.h` - Field definitions
- `include/xrpl/protocol/TER.h` - Transaction result codes
- `include/xrpl/protocol/Feature.h` - Amendment flags
- `include/xrpl/protocol/Indexes.h` - Ledger entry key generation
- `include/xrpl/protocol/Keylet.h` - Type-safe ledger keys
- `include/xrpl/protocol/SOTemplate.h` - Object schema definitions
- `src/libxrpl/protocol/STParsedJSON.cpp` - JSON to object conversion

View File

@@ -0,0 +1,60 @@
# RDB Module Best Practices
## Description
Use when working with relational database access in `src/libxrpl/rdb/` or `include/xrpl/rdb/`. Covers SOCI wrapper, database configuration, and checkpointing.
## Responsibility
Provides a C++ wrapper around SOCI (SQLite/PostgreSQL abstraction) for relational data access, configuration management, blob type conversions, and periodic WAL checkpoint management.
## Key Patterns
### DBConfig Lazy Initialization
```cpp
// Construct config without opening connection
DBConfig config(basicConfig, "my_database");
// Open session later when needed
soci::session session;
config.open(session);
// Allows config parsing separate from database I/O
```
### Blob Conversions
```cpp
// Convert between SOCI blobs and standard types
soci::blob blob(session);
std::vector<std::uint8_t> bytes;
convert(blob, bytes); // blob -> vector
std::string str;
convert(blob, str); // blob -> string
```
### Checkpointer with Weak Pointer Safety
```cpp
// Checkpointer uses weak_ptr to detect session destruction
auto checkpointer = makeCheckpointer(
id,
std::weak_ptr<soci::session>(sessionPtr),
jobQueue,
logs);
checkpointer->schedule(); // Periodic WAL checkpoints
// If session is destroyed, checkpointer safely no-ops
```
### Thread-Safe Sessions
```cpp
// Each thread gets its own soci::session from the pool
// Never share a soci::session across threads
```
## Common Pitfalls
- Never share a soci::session across threads - each thread needs its own
- Always use `std::weak_ptr` for session references in long-lived objects (like Checkpointer)
- Be aware of SOCI include warnings - use pragma diagnostic push/pop
- Always convert blobs to standard types before processing
## Key Files
- `include/xrpl/rdb/SociDB.h` - Main wrapper interface
- `src/libxrpl/rdb/SociDB.cpp` - Implementation
- `src/libxrpl/rdb/DatabaseCon.cpp` - Database connection setup

View File

@@ -0,0 +1,64 @@
# Resource Module Best Practices
## Description
Use when working with rate limiting and resource management in `src/libxrpl/resource/` or `include/xrpl/resource/`. Covers endpoint tracking, charge/fee management, and abuse prevention.
## Responsibility
Tracks resource consumption by network endpoints (inbound/outbound connections) to prevent abuse and ensure fair resource allocation. Manages consumer lifecycle, charge accounting, and gossip-based reputation sharing.
## Key Patterns
### Manager/Impl Pattern
```cpp
// Abstract Manager interface with factory function
class Manager { virtual ~Manager() = 0; };
std::unique_ptr<Manager> make_Manager(beast::Journal journal);
// Implementation hidden in cpp
class ManagerImp : public Manager { /* ... */ };
```
### Consumer Factory
```cpp
// Different consumer types for different connection sources
Consumer newInboundEndpoint(beast::IP::Endpoint const& address);
Consumer newOutboundEndpoint(beast::IP::Endpoint const& address);
Consumer newUnlimitedEndpoint(beast::IP::Endpoint const& address);
```
### Background Thread Shutdown
```cpp
// Clean shutdown pattern with condition variable
~ManagerImp() {
{
std::lock_guard lock(mutex_);
stop_ = true;
cond_.notify_one();
}
thread_.join(); // Wait for thread to finish
}
```
### Proxy-Aware Endpoint Detection
```cpp
// Handle forwarded-for headers safely
boost::system::error_code ec;
auto proxiedIp = boost::asio::ip::make_address(forwardedFor, ec);
if (ec) {
journal_.warn() << "Invalid IP: " << ec.message();
return newInboundEndpoint(address); // Fallback to socket IP
}
```
## Common Pitfalls
- Never trust forwarded-for headers without proxy flag validation
- Always use the factory methods - never construct Consumer directly
- Always join background threads in destructor
- Use separate consumer types for different connection trust levels
## Key Files
- `include/xrpl/resource/ResourceManager.h` - Manager interface
- `src/libxrpl/resource/ResourceManager.cpp` - Implementation
- `include/xrpl/resource/Consumer.h` - Per-endpoint tracking
- `src/libxrpl/resource/Charge.cpp` - Cost definitions
- `src/libxrpl/resource/Fees.cpp` - Fee calculations

View File

@@ -0,0 +1,68 @@
# Server Module Best Practices
## Description
Use when working with server configuration in `src/libxrpl/server/` or `include/xrpl/server/`. Covers port configuration, SSL/TLS, WebSocket options, and authentication.
## Responsibility
Manages server listening ports, WebSocket configuration, SSL/TLS setup, authentication credentials, and admin network restrictions. Handles parsing configuration into validated port structures.
## Key Patterns
### Dual ParsedPort/Port Pattern
```cpp
// ParsedPort: intermediate parsing result (may be incomplete)
struct ParsedPort { /* partially validated fields */ };
// Port: final validated configuration (ready to use)
struct Port {
std::string name;
boost::asio::ip::address ip;
std::uint16_t port = 0;
std::set<std::string, iless> protocol;
// ...
};
```
### Configuration Section Parsing
```cpp
// Parse from config file section, log errors to stream
void parse_Port(ParsedPort& port, Section const& section, std::ostream& log);
// Does NOT throw - logs issues and sets defaults
```
### CIDR Admin Networks
```cpp
// IP-based admin access control with CIDR support
std::vector<boost::asio::ip::network_v4> admin_nets_v4;
std::vector<boost::asio::ip::network_v6> admin_nets_v6;
// Supports both IPv4 and IPv6 ranges
```
### WebSocket Options
```cpp
// Fine-grained compression control
boost::beast::websocket::permessage_deflate pmd_options;
// Queue limits prevent memory exhaustion
std::optional<std::uint16_t> ws_queue_limit;
// limit=0 means unlimited (not -1)
```
### SSL Context Lazy Creation
```cpp
// SSL context created only when needed
std::shared_ptr<boost::asio::ssl::context> context;
// Initialized when first SSL connection established
```
## Common Pitfalls
- Never use port-only access control - always use CIDR network restrictions for admin
- Use `iless` comparator for protocol names (case-insensitive)
- Remember that `limit=0` means unlimited, not disabled
- Always log parsing errors rather than throwing
- Separate user/admin credentials - don't reuse
## Key Files
- `include/xrpl/server/Port.h` - Port configuration structure
- `src/libxrpl/server/Port.cpp` - Parsing and validation
- `src/libxrpl/server/JSONRPCUtil.cpp` - RPC utility functions
- `src/libxrpl/server/LoadFeeTrack.cpp` - Load and fee tracking

View File

@@ -0,0 +1,83 @@
# SHAMap Module Best Practices
## Description
Use when working with the Merkle tree implementation in `src/libxrpl/shamap/` or `include/xrpl/shamap/`. Covers the SHA-256 based radix tree used for ledger state representation.
## Responsibility
Implements a SHA-256 based Merkle radix tree with 16-way branching (hexadecimal). Provides efficient ledger state representation with O(log N) proof-of-inclusion, copy-on-write snapshots, synchronization, and delta calculation.
## Key Patterns
### State Machine Lifecycle
```cpp
enum class SHAMapState { Modifying, Immutable, Synching, Invalid };
// Modifying: Can add/remove/modify entries
// Immutable: Snapshot - no modifications allowed
// Synching: Being synchronized from peers
// Invalid: Corrupted or destroyed
// Transitions are one-way: Modifying -> Immutable (via snapshot)
```
### Copy-on-Write via COWID
```cpp
std::uint32_t cowid_ = 1;
// Each snapshot gets a new COWID
// Children are only copied when modified (lazy copy)
// Immutable snapshots share nodes with the active map
auto snapshot = map.snapShot(true); // Creates immutable copy
```
### 16-Way Radix Branching
```cpp
static inline constexpr unsigned int branchFactor = 16;
static inline constexpr unsigned int leafDepth = 64;
// 256-bit key / 4 bits per nibble = 64 levels max
// Each inner node has up to 16 children
```
### Node Type Hierarchy
```cpp
// SHAMapTreeNode (base) -> SHAMapInnerNode (16 children)
// -> SHAMapLeafNode (data + key)
// Use dynamic_pointer_cast for safe downcasting
auto inner = intr_ptr::dynamic_pointer_cast<SHAMapInnerNode>(node);
if (inner) { /* process inner node */ }
```
### Walk-Up for Modifications (dirtyUp)
```cpp
// After modifying a leaf, propagate hash changes to root
void dirtyUp(SharedPtrNodeStack& stack, uint256 const& target, ...);
// Updates hashes from leaf -> root through the stack
```
### Lazy Traversal
```cpp
// Navigate to a leaf by key
SHAMapLeafNode* walkTowardsKey(uint256 const& id,
SharedPtrNodeStack* stack = nullptr);
// Returns leaf or nullptr; optionally records path for dirtyUp
```
### Intrusive Pointers for Nodes
```cpp
// Nodes use intrusive reference counting (not std::shared_ptr)
intr_ptr::SharedPtr<SHAMapTreeNode> root_;
// Minimal overhead - reference count embedded in node
```
## Common Pitfalls
- Never modify an Immutable map - check state before mutations
- Always call dirtyUp after modifying a leaf to maintain hash integrity
- Never assume node type without dynamic_pointer_cast check
- Remember that snapshots share nodes - COW means nodes are only copied on write
- Always use the provided iterators for safe traversal, not manual tree walking
## Key Files
- `include/xrpl/shamap/SHAMap.h` - Main map implementation
- `include/xrpl/shamap/SHAMapTreeNode.h` - Base node class
- `include/xrpl/shamap/SHAMapInnerNode.h` - Interior nodes (16-way)
- `include/xrpl/shamap/SHAMapLeafNode.h` - Leaf nodes with data
- `include/xrpl/shamap/SHAMapNodeID.h` - Tree position identifier
- `src/libxrpl/shamap/SHAMapDelta.cpp` - Difference between maps
- `src/libxrpl/shamap/SHAMapSync.cpp` - Synchronization algorithm

View File

@@ -0,0 +1,137 @@
# Transaction (tx) Module Best Practices
## Description
Use when working with transaction processing in `src/libxrpl/tx/` or `include/xrpl/tx/`. Covers the Transactor base class, transaction pipeline, invariant checks, and apply context.
## Responsibility
Implements the transaction processing pipeline: static validation (preflight), fee-claim checks (preclaim), transaction execution (doApply), and post-apply invariant verification. All transaction types derive from the Transactor base class.
## Key Patterns
### Transaction Pipeline (3 Phases)
```cpp
// Phase 1: Preflight - Static validation, NO ledger access
static NotTEC preflight(PreflightContext const& ctx) {
if (ctx.tx[sfAmount] <= beast::zero)
return temBAD_AMOUNT;
return tesSUCCESS;
}
// Phase 2: Preclaim - Ledger read-only checks
static TER preclaim(PreclaimContext const& ctx) {
auto sle = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
if (!sle) return tecNO_DST;
return tesSUCCESS;
}
// Phase 3: doApply - Actual ledger mutations
TER doApply() override {
auto sle = view().peek(keylet::account(account_));
sle->setFieldAmount(sfBalance, newBalance);
view().update(sle);
return tesSUCCESS;
}
```
### Transactor Base Class
```cpp
class MyTransaction : public Transactor {
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
explicit MyTransaction(ApplyContext& ctx) : Transactor(ctx) {}
// Optional: Gate on amendment
static bool checkExtraFeatures(PreflightContext const& ctx);
// Optional: Custom flag mask
static std::uint32_t getFlagsMask(PreflightContext const& ctx);
// Required
static NotTEC preflight(PreflightContext const& ctx);
static TER preclaim(PreclaimContext const& ctx);
TER doApply() override;
// Optional: Custom fee calculation
static XRPAmount calculateBaseFee(ReadView const& view, STTx const& tx);
};
```
### Feature Gating
```cpp
static bool checkExtraFeatures(PreflightContext const& ctx) {
// Return false to disable when amendment not enabled
return ctx.rules.enabled(featureMyFeature);
}
```
### Flag Validation
```cpp
static std::uint32_t getFlagsMask(PreflightContext const& ctx) {
return tfMyTransactionMask; // Allowed flags
}
// Base class validates: (tx.getFlags() & ~getFlagsMask()) == 0
```
### ConsequencesFactory Types
```cpp
// Normal: Standard transaction
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
// Blocker: Affects subsequent transactions' ability to claim fees
static constexpr ConsequencesFactoryType ConsequencesFactory{Blocker};
// Custom: Override makeTxConsequences() static method
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
```
### TER Error Code Progression
```
tem* (malformed): temINVALID, temBAD_AMOUNT, temDISABLED - preflight errors
tef* (failure): tefFAILURE, tefNESTED_FAILURE - infrastructure errors
tel* (local): telNETWORK_ID_MAKES_TX_NON_CANONICAL - local-only errors
tec* (claimed): tecNO_DST, tecFROZEN, tecINSUFFICIENT_RESERVE - fee claimed, no effect
tes (success): tesSUCCESS - transaction applied
```
### Logging Convention
```cpp
JLOG(ctx.j.warn()) << "User error message"; // User-facing issues
JLOG(ctx.j.debug()) << "Detailed diagnostic"; // Implementation details
JLOG(ctx.j.trace()) << "Very verbose info"; // Deep debugging
JLOG(ctx.j.error()) << "Unexpected failure"; // Should not happen
```
### View Operations in doApply
```cpp
// Read-only (returns const SLE)
auto sle = view().read(keylet::account(accountID));
// Mutable (returns non-const SLE)
auto sle = view().peek(keylet::account(accountID));
sle->setFieldAmount(sfBalance, newBalance);
view().update(sle); // MUST call after modification
// Create new entry
auto sle = std::make_shared<SLE>(keylet::myEntry(id));
sle->setFieldText(sfData, data);
view().insert(sle);
// Remove entry
view().erase(sle);
```
## Common Pitfalls
- Never access ledger state in preflight - it only has PreflightContext (no view)
- Never mutate ledger state in preclaim - it has ReadView only
- Always call `view().update(sle)` after modifying a peeked SLE
- Never return `tesSUCCESS` from preclaim/preflight if validation failed
- Always gate new transaction types on feature amendments
- Use `NotTEC` return type for preflight (not TER) - prevents returning tec codes from static checks
- Never forget to register new transaction types in `transactions.macro` and `applySteps.cpp`
## Key Files
- `include/xrpl/tx/Transactor.h` - Base class with static method signatures
- `src/libxrpl/tx/Transactor.cpp` - Base implementation (41KB)
- `src/libxrpl/tx/apply.cpp` - Transaction application entry point
- `src/libxrpl/tx/ApplyContext.cpp` - Context management
- `src/libxrpl/tx/InvariantCheck.cpp` - Post-apply invariant validation (117KB)
- `src/libxrpl/tx/applySteps.cpp` - Step-by-step dispatch

View File

@@ -0,0 +1,72 @@
# Transaction Paths Module Best Practices
## Description
Use when working with payment path finding and execution in `src/libxrpl/tx/paths/` or `include/xrpl/tx/paths/`. Covers the flow engine, ripple calculation, and offer stream processing.
## Responsibility
Implements payment path finding and execution for cross-currency payments. Handles the flow engine for executing payments across multiple paths (strands), offer book management, and amount calculation.
## Key Patterns
### Flow Engine Entry Point
```cpp
path::RippleCalc::Output flow(
PaymentSandbox& view,
STAmount const& deliver,
AccountID const& src,
AccountID const& dst,
STPathSet const& paths,
bool defaultPaths,
bool partialPayment,
bool ownerPaysTransferFee,
OfferCrossing offerCrossing,
std::optional<Quality> const& limitQuality,
std::optional<STAmount> const& sendMax,
std::optional<uint256> const& domainID,
beast::Journal j,
path::detail::FlowDebugInfo* flowDebugInfo = nullptr);
```
### Strand-Based Execution
```cpp
// A "strand" is a single payment path through the DEX
// Multiple strands can be tried to find the best rate
// StrandFlow executes a single strand
// Flow tries all strands and picks the best result
```
### OfferStream for Order Book Processing
```cpp
// Iterates through offers in an order book
// Handles expired offers, unfunded offers, and self-crossing
// Automatically cleans up stale offers during traversal
```
### Quality-Based Routing
```cpp
// Quality = exchange rate between input and output
// Lower quality number = better rate
// limitQuality prevents accepting rates worse than threshold
```
### PaymentSandbox Isolation
```cpp
// All path calculations happen in a PaymentSandbox
// Changes are only committed if the payment succeeds
// Allows trying multiple paths without side effects
```
## Common Pitfalls
- Never modify the ledger directly during path calculation - use PaymentSandbox
- Always respect limitQuality to prevent unfavorable exchange rates
- Be aware that offer traversal may clean up stale offers as a side effect
- FlowDebugInfo is optional and only for debugging - never rely on it in production logic
- Path finding is computationally expensive - respect depth and complexity limits
## Key Files
- `include/xrpl/tx/paths/Flow.h` - Main flow engine entry point
- `include/xrpl/tx/paths/RippleCalc.h` - Payment amount calculation
- `src/libxrpl/tx/paths/OfferStream.cpp` - Order book traversal (~12KB)
- `src/libxrpl/tx/paths/BookTip.cpp` - Order book tip management
- `src/libxrpl/tx/paths/detail/Steps.h` - Step-by-step calculation
- `src/libxrpl/tx/paths/detail/StrandFlow.h` - Single path execution

View File

@@ -0,0 +1,164 @@
# Transactors Module Best Practices
## Description
Use when adding or modifying transaction types in `src/libxrpl/tx/transactors/`. This is the guide for implementing new transactors following the established patterns.
## Responsibility
Contains all concrete transaction type implementations. Each transactor follows the Transactor base class pattern with preflight/preclaim/doApply phases. Transaction types are organized by feature area in subdirectories.
## Template for New Transactors
### Header File (`include/xrpl/tx/transactors/MyTx.h`)
```cpp
#pragma once
#include <xrpl/tx/Transactor.h>
namespace xrpl {
class MyTransaction : public Transactor {
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
explicit MyTransaction(ApplyContext& ctx) : Transactor(ctx) {}
static bool checkExtraFeatures(PreflightContext const& ctx);
static std::uint32_t getFlagsMask(PreflightContext const& ctx);
static NotTEC preflight(PreflightContext const& ctx);
static TER preclaim(PreclaimContext const& ctx);
TER doApply() override;
};
}
```
### Implementation File (`src/libxrpl/tx/transactors/MyFeature/MyTx.cpp`)
```cpp
#include <xrpl/tx/transactors/MyTx.h>
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/TxFlags.h>
namespace xrpl {
bool
MyTransaction::checkExtraFeatures(PreflightContext const& ctx)
{
return ctx.rules.enabled(featureMyFeature);
}
std::uint32_t
MyTransaction::getFlagsMask(PreflightContext const& ctx)
{
return tfUniversalMask; // Or custom mask
}
NotTEC
MyTransaction::preflight(PreflightContext const& ctx)
{
// Static validation - NO ledger access
auto const& tx = ctx.tx;
if (tx[sfAmount] <= beast::zero)
{
JLOG(ctx.j.warn()) << "Bad amount.";
return temBAD_AMOUNT;
}
return tesSUCCESS;
}
TER
MyTransaction::preclaim(PreclaimContext const& ctx)
{
// Ledger read-only checks
auto const sle = ctx.view.read(
keylet::account(ctx.tx[sfAccount]));
if (!sle)
return terNO_ACCOUNT;
return tesSUCCESS;
}
TER
MyTransaction::doApply()
{
// Mutate ledger state
auto sle = view().peek(keylet::account(account_));
if (!sle)
return tefINTERNAL;
sle->setFieldAmount(sfBalance, newBalance);
view().update(sle);
return tesSUCCESS;
}
}
```
### Registration Checklist
1. Add transaction type to `include/xrpl/protocol/detail/transactions.macro`
2. Add dispatch case to `src/libxrpl/tx/applySteps.cpp`
3. Add feature flag to `include/xrpl/protocol/Feature.h` and `src/libxrpl/protocol/Feature.cpp`
4. Add invariant checks if needed in `src/libxrpl/tx/InvariantCheck.cpp`
5. Add to `disabledTxTypes` in Batch.cpp if not batch-compatible
## Key Patterns Across All Transactors
### Feature Gating
```cpp
static bool checkExtraFeatures(PreflightContext const& ctx) {
return ctx.rules.enabled(featureMyFeature);
}
```
### Variant-Aware Validation
```cpp
// When handling Asset (Issue or MPTIssue):
if (auto const ret = std::visit(
[&]<typename T>(T const&) { return preflightHelper<T>(ctx); },
ctx.tx[sfAmount].asset().value()); !isTesSuccess(ret))
return ret;
```
### Ledger Entry CRUD in doApply
```cpp
// Create
auto sle = std::make_shared<SLE>(keylet::myEntry(id));
view().insert(sle);
// Read (mutable)
auto sle = view().peek(keylet::myEntry(id));
// Update
sle->setFieldU32(sfFlags, newFlags);
view().update(sle);
// Delete
view().erase(sle);
```
### Helper/Utils Files
```cpp
// Complex features use a separate Helpers/Utils file:
// AMM -> AMMHelpers.h, AMMUtils.h
// NFT -> NFTokenUtils.h
// Lending -> LendingHelpers.h
// Keep reusable logic in helpers, transaction-specific logic in transactors
```
## Common Pitfalls
- Never forget to register in `transactions.macro` and `applySteps.cpp`
- Never access ledger state in preflight (no view available)
- Never mutate state in preclaim (read-only view)
- Always call `view().update(sle)` after modifying a peeked entry
- Always gate on feature amendment for consensus safety
- Use `NotTEC` return type from preflight, `TER` from preclaim/doApply
- Put shared logic in a *Helpers.h file, not duplicated across transactors
## Key Files
- `include/xrpl/tx/Transactor.h` - Base class definition
- `src/libxrpl/tx/applySteps.cpp` - Transaction type dispatch
- `include/xrpl/protocol/detail/transactions.macro` - Transaction type registry
- `src/libxrpl/tx/InvariantCheck.cpp` - Post-apply validation

View File

@@ -0,0 +1,68 @@
# AMM (Automated Market Maker) Transactors Best Practices
## Description
Use when working with AMM transaction types in `src/libxrpl/tx/transactors/AMM/`. Covers pool creation, deposits, withdrawals, voting, bidding, deletion, and clawback.
## Responsibility
Implements decentralized trading pools with liquidity provider (LP) tokens. Allows users to create AMM pools, deposit/withdraw liquidity, vote on trading fees, bid on auction slots, and manage pool lifecycle.
## Key Patterns
### AMM Transaction Types
- **AMMCreate** - Create a new AMM pool with two assets
- **AMMDeposit** - Add liquidity to a pool, receive LP tokens
- **AMMWithdraw** - Remove liquidity, burn LP tokens
- **AMMVote** - Vote on trading fee percentage
- **AMMBid** - Bid on the auction slot for discounted trading
- **AMMDelete** - Remove an empty AMM pool
- **AMMClawback** - Issuer clawback of assets from AMM
### Precision Arithmetic
```cpp
// AMM calculations require controlled rounding
// ALWAYS use NumberRoundModeGuard for rounding control
NumberRoundModeGuard mg(Number::towards_zero);
auto lpTokens = ammLPTokens(amount1, amount2, lptIssue);
// Or explicit mode changes with RAII save
{
saveNumberRoundMode _{Number::getround()};
Number::setround(Number::upward);
auto value = calculation;
}
```
### Helper Functions (AMMHelpers.h)
```cpp
ammLPTokens() // Calculate LP tokens from pool reserves
lpTokensOut() // LP tokens from deposit
ammAssetIn() / ammAssetOut() // Calculate swap amounts
withinRelativeDistance() // Quality tolerance checks
changeSpotPriceQuality() // Quote generation algorithm
// Quadratic equation solving for pricing
```
### Feature Gates
```cpp
// Multiple amendment versions
ammEnabled(ctx.rules) // Base AMM feature
fixAMMv1_1 // First fix amendment
fixAMMv1_3 // Third fix amendment
// Always check which amendments are active
```
## Common Pitfalls
- Never perform AMM math without setting the rounding mode first
- Always use `NumberRoundModeGuard` (RAII) - never manually set/restore rounding
- Be aware that AMM calculations involve quadratic equations - precision matters
- AMMClawback has different authorization requirements than regular clawback
- Check `withinRelativeDistance` for quality tolerance rather than exact equality
## Key Files
- `src/libxrpl/tx/transactors/AMM/AMMCreate.cpp` - Pool creation
- `src/libxrpl/tx/transactors/AMM/AMMDeposit.cpp` - Liquidity deposit (~887 lines)
- `src/libxrpl/tx/transactors/AMM/AMMWithdraw.cpp` - Liquidity withdrawal (~911 lines)
- `src/libxrpl/tx/transactors/AMM/AMMVote.cpp` - Fee voting
- `src/libxrpl/tx/transactors/AMM/AMMBid.cpp` - Auction slot bidding
- `include/xrpl/tx/transactors/AMM/AMMHelpers.h` - Shared math utilities
- `include/xrpl/tx/transactors/AMM/AMMUtils.h` - AMM state utilities

View File

@@ -0,0 +1,44 @@
# Check Transactors Best Practices
## Description
Use when working with Check transaction types in `src/libxrpl/tx/transactors/Check/`. Covers check creation, cashing, and cancellation.
## Responsibility
Implements a check-like payment mechanism (delayed payment authorization). A sender creates a check, the recipient cashes it, and either party can cancel it (with expiration support).
## Key Patterns
### Check Lifecycle
```cpp
// 1. CreateCheck - Sender authorizes payment
// Validates: destination exists, amount valid, expiration future
// Creates: Check ledger entry with sender, destination, amount
// 2. CashCheck - Recipient claims payment
// Validates: caller is destination, check not expired
// Executes: transfers funds from sender to destination
// 3. CancelCheck - Either party cancels
// Validates: caller is sender or destination, or check expired
// Removes: Check ledger entry
```
### Error Codes
```cpp
tecNO_DST // Destination account doesn't exist
temREDUNDANT // Check to self
temBAD_AMOUNT // Invalid amount
temBAD_EXPIRATION // Expiration in the past
tecEXPIRED // Check has expired (for CashCheck)
```
## Common Pitfalls
- Checks can be cancelled by either sender or destination
- Expired checks can be cancelled by anyone
- CashCheck must handle both exact amount and "deliver minimum" modes
- Always validate expiration against the parent ledger close time
## Key Files
- `src/libxrpl/tx/transactors/Check/CreateCheck.cpp` - Check creation
- `src/libxrpl/tx/transactors/Check/CashCheck.cpp` - Check fulfillment (~440 lines)
- `src/libxrpl/tx/transactors/Check/CancelCheck.cpp` - Check cancellation

View File

@@ -0,0 +1,43 @@
# Delegate Transactors Best Practices
## Description
Use when working with delegation transaction types in `src/libxrpl/tx/transactors/Delegate/`. Covers delegate set and utilities.
## Responsibility
Manages transaction signing delegation, allowing accounts to authorize other accounts to sign transactions on their behalf without exposing the master key.
## Key Patterns
### Delegate Operations
```cpp
// DelegateSet - Create or modify a delegation
// Validates: delegate account exists, permissions valid
// Creates/Updates: Delegate ledger entry
// DelegateUtils - Shared utilities
// deleteDelegate() - Public cleanup interface, used by DeleteAccount
```
### Feature Gates
```cpp
// fixDelegateV1_1 - Added data existence checks
if (ctx.rules.enabled(fixDelegateV1_1)) {
// Perform additional validation
}
```
### Integration with DeleteAccount
```cpp
// DelegateUtils::deleteDelegate() is called by DeleteAccount
// for cleanup when an account is being deleted
// Must handle all delegation-related ledger entries
```
## Common Pitfalls
- Always check feature gate `fixDelegateV1_1` for data existence validation
- Delegate cleanup must be thorough - used by DeleteAccount
- Never allow self-delegation
## Key Files
- `src/libxrpl/tx/transactors/Delegate/DelegateSet.cpp` - Delegation management
- `include/xrpl/tx/transactors/Delegate/DelegateUtils.h` - Shared utilities

View File

@@ -0,0 +1,69 @@
# Lending Transactors Best Practices
## Description
Use when working with lending protocol transaction types in `src/libxrpl/tx/transactors/Lending/`. Covers loan management, broker operations, and payment calculation.
## Responsibility
Implements a complex loan protocol with amortization schedules, interest calculation, broker management, and collateral handling. The largest transactor feature area by code volume.
## Key Patterns
### Loan Lifecycle
```cpp
// LoanSet - Create or configure a loan
// LoanPay - Make loan payments (principal + interest)
// LoanManage - Manage loan state transitions
// LoanDelete - Remove a completed/cancelled loan
```
### Broker Operations
```cpp
// LoanBrokerSet - Create/configure a broker
// LoanBrokerDelete - Remove a broker
// LoanBrokerCoverDeposit - Deposit collateral
// LoanBrokerCoverWithdraw - Withdraw collateral
// LoanBrokerCoverClawback - Clawback broker assets
```
### Payment Calculation (LendingHelpers.h)
```cpp
struct LoanPaymentParts {
Number principalPaid; // Reduces loan balance
Number interestPaid; // Goes to Vault
Number valueChange; // Loan value adjustment
Number feePaid; // Goes to Broker
};
// Key helper functions:
checkLendingProtocolDependencies() // Validate feature gates
loanPeriodicRate() // Interest with secondsInYear
roundPeriodicPayment() // Consistent rounding
```
### Feature Gate
```cpp
// All lending operations gated on single feature
ctx.rules.enabled(featureLendingProtocol)
```
### Batch Transaction Restriction
```cpp
// Lending transactions are DISABLED in batch transactions
// Listed in Batch::disabledTxTypes
// Cannot be included in atomic batch operations
```
## Common Pitfalls
- Lending is disabled in Batch transactions - do not try to batch lending ops
- Payment calculations require precise rounding - use LendingHelpers functions
- Always validate lending protocol dependencies before operations
- Interest calculation uses `secondsInYear` constant - be aware of leap year handling
- LendingHelpers.h is ~1800 lines - the most complex helper file in the codebase
## Key Files
- `src/libxrpl/tx/transactors/Lending/LoanSet.cpp` - Loan configuration (~585 lines)
- `src/libxrpl/tx/transactors/Lending/LoanPay.cpp` - Payment processing (~548 lines)
- `src/libxrpl/tx/transactors/Lending/LoanManage.cpp` - State management
- `src/libxrpl/tx/transactors/Lending/LoanDelete.cpp` - Loan removal
- `src/libxrpl/tx/transactors/Lending/LoanBrokerSet.cpp` - Broker setup
- `include/xrpl/tx/transactors/Lending/LendingHelpers.h` - Shared calculations (~1799 lines)

View File

@@ -0,0 +1,53 @@
# MPT (Multi-Purpose Token) Transactors Best Practices
## Description
Use when working with MPT transaction types in `src/libxrpl/tx/transactors/MPT/`. Covers token issuance creation, configuration, destruction, and authorization.
## Responsibility
Implements Multi-Purpose Token (MPT) operations - a fungible token system simpler than full IOU trust lines. Handles token issuance lifecycle and holder authorization.
## Key Patterns
### MPT Transaction Types
```cpp
// MPTokenIssuanceCreate - Create a new token issuance
// MPTokenIssuanceSet - Modify issuance settings
// MPTokenIssuanceDestroy - Destroy an issuance (if no holders)
// MPTokenAuthorize - Authorize/deauthorize a holder
```
### MPT vs IOU Trust Lines
```cpp
// MPT is simpler than IOU trust lines:
// - No rippling mechanics
// - No transfer fees between holders (only issuer)
// - Simpler authorization model
// - Uses MPTIssue instead of Issue
// - Uses MPTAmount instead of IOUAmount
```
### Feature Gate
```cpp
ctx.rules.enabled(featureMPTokensV1)
```
### Asset Variant Handling
```cpp
// MPTIssue is part of the Asset variant (Issue | MPTIssue)
// Use std::visit when handling Asset generically:
std::visit([&](auto const& issue) {
// Works for both Issue and MPTIssue
}, asset.value());
```
## Common Pitfalls
- MPT issuances cannot be destroyed if any holders exist
- Authorization is per-holder, not per-token
- Don't confuse MPTIssue with Issue - they have different keylet types
- Always check `featureMPTokensV1` before MPT operations
## Key Files
- `src/libxrpl/tx/transactors/MPT/MPTokenIssuanceCreate.cpp` - Create issuance
- `src/libxrpl/tx/transactors/MPT/MPTokenIssuanceSet.cpp` - Modify settings
- `src/libxrpl/tx/transactors/MPT/MPTokenIssuanceDestroy.cpp` - Destroy issuance
- `src/libxrpl/tx/transactors/MPT/MPTokenAuthorize.cpp` - Holder authorization

View File

@@ -0,0 +1,76 @@
# NFT (Non-Fungible Token) Transactors Best Practices
## Description
Use when working with NFT transaction types in `src/libxrpl/tx/transactors/NFT/`. Covers minting, burning, offer management, and token modification.
## Responsibility
Implements NFT creation, trading, and lifecycle management. Handles token minting, burning, buy/sell offer creation and acceptance, offer cancellation, and dynamic NFT modification.
## Key Patterns
### NFT Transaction Types
```cpp
// NFTokenMint - Create a new NFT
// NFTokenBurn - Destroy an NFT
// NFTokenCreateOffer - Create a buy or sell offer
// NFTokenCancelOffer - Cancel an existing offer
// NFTokenAcceptOffer - Accept a buy or sell offer (execute trade)
// NFTokenModify - Modify NFT metadata (dynamic NFTs)
```
### NFTokenUtils - Shared Utilities (~1025 lines)
```cpp
// Key utility functions:
findToken() // Find an NFT in owner's token pages
insertToken() // Add NFT to owner's directory
removeToken() // Remove NFT from owner's directory
deleteTokenOffer() // Clean up a single offer
removeTokenOffersWithLimit() // Batch cleanup with limit
notTooManyOffers() // Check offer count limits
changeTokenURI() // Update NFT URI (dynamic NFTs)
struct TokenAndPage {
STObject token;
std::shared_ptr<SLE> page;
};
```
### Token Storage in Pages
```cpp
// NFTs are stored in paginated directories
// Each page holds multiple tokens
// Pages are linked as a doubly-linked list
// insertToken/removeToken manage page splits and merges
```
### Feature Gates
```cpp
featureNFTokenMintOffer // Combined mint + offer
fixRemoveNFTokenAutoTrustLine // Fix for auto trust line removal
featureDynamicNFT // NFTokenModify support
```
### Offer Directory Structure
```cpp
// Buy offers and sell offers stored in separate directories
// Indexed by token ID
// Offers can have expiration times
// Offers can specify a destination (private offers)
```
## Common Pitfalls
- Token page management is complex - always use NFTokenUtils functions
- Offer cleanup has limits (`removeTokenOffersWithLimit`) - don't assume all offers removed
- `notTooManyOffers()` must be checked before creating new offers
- Dynamic NFT modification requires `featureDynamicNFT` amendment
- Transfer fees only apply when the NFT issuer is not a party to the trade
- Burning an NFT with outstanding offers requires offer cleanup
## Key Files
- `src/libxrpl/tx/transactors/NFT/NFTokenMint.cpp` - Token minting
- `src/libxrpl/tx/transactors/NFT/NFTokenBurn.cpp` - Token destruction
- `src/libxrpl/tx/transactors/NFT/NFTokenCreateOffer.cpp` - Offer creation
- `src/libxrpl/tx/transactors/NFT/NFTokenAcceptOffer.cpp` - Offer acceptance (trade)
- `src/libxrpl/tx/transactors/NFT/NFTokenCancelOffer.cpp` - Offer cancellation
- `src/libxrpl/tx/transactors/NFT/NFTokenModify.cpp` - Dynamic NFT changes
- `include/xrpl/tx/transactors/NFT/NFTokenUtils.h` - Shared utilities (~1025 lines)

View File

@@ -0,0 +1,56 @@
# Offer Transactors Best Practices
## Description
Use when working with DEX offer transaction types in `src/libxrpl/tx/transactors/Offer/`. Covers order creation and cancellation on the native decentralized exchange.
## Responsibility
Implements decentralized exchange order management for the native XRPL order book. Handles offer creation (with matching/crossing), cancellation, and order book management.
## Key Patterns
### Offer Transaction Types
```cpp
// CreateOffer (~854 lines) - Create a new DEX order
// - Validates amounts, currency pairs, account state
// - Attempts to cross with existing offers (matching engine)
// - Remaining amount becomes a standing order if not fully filled
// - Handles self-crossing, expired offers, unfunded offers
// CancelOffer - Remove an existing order
// - Validates caller owns the offer
// - Removes offer from order book directory
```
### Offer Crossing (Matching Engine)
```cpp
// CreateOffer performs offer crossing inline:
// 1. Look up existing offers on the opposite side
// 2. Match at the offer's quality (exchange rate)
// 3. Consume matched offers (partial or full)
// 4. Place remaining amount as standing order
// This is the core DEX matching engine
```
### Quality and Order Books
```cpp
// Quality = exchange rate between TakerPays and TakerGets
// Order books indexed by currency pair and sorted by quality
// Lower quality number = better rate for taker
```
### Ticket Support
```cpp
// Offers can use tickets for sequence management
// Feature gate: featureTickets
```
## Common Pitfalls
- CreateOffer is one of the most complex transactors (~854 lines) - be thorough with changes
- Offer crossing modifies multiple ledger entries atomically
- Self-crossing (same account on both sides) has special handling
- Expired and unfunded offers are cleaned up during crossing
- Always validate that TakerPays and TakerGets are different assets
## Key Files
- `src/libxrpl/tx/transactors/Offer/CreateOffer.cpp` - Order creation and matching (~854 lines)
- `src/libxrpl/tx/transactors/Offer/CancelOffer.cpp` - Order cancellation

View File

@@ -0,0 +1,36 @@
# PermissionedDomain Transactors Best Practices
## Description
Use when working with permissioned domain transaction types in `src/libxrpl/tx/transactors/PermissionedDomain/`. Covers domain-based access control for the DEX.
## Responsibility
Implements domain-based access control for permissioned DEX operations. Allows creating and deleting permissioned domains that gate who can participate in certain trading activities.
## Key Patterns
### PermissionedDomain Transaction Types
```cpp
// PermissionedDomainSet - Create or update a permissioned domain
// PermissionedDomainDelete - Remove a permissioned domain
```
### Integration with Payments
```cpp
// Payments can reference a domain via sfDomainID field
// The domain gates which accounts can participate
// Used for regulated/permissioned trading environments
```
### Feature Gate
```cpp
ctx.rules.enabled(featurePermissionedDEX)
```
## Common Pitfalls
- Domains are referenced by other transactions (Payments) - deletion must check for references
- Always validate the feature gate before domain operations
- Domain ID matching is exact - no partial matches
## Key Files
- `src/libxrpl/tx/transactors/PermissionedDomain/PermissionedDomainSet.cpp` - Create/update domain
- `src/libxrpl/tx/transactors/PermissionedDomain/PermissionedDomainDelete.cpp` - Remove domain

View File

@@ -0,0 +1,61 @@
# Vault Transactors Best Practices
## Description
Use when working with vault transaction types in `src/libxrpl/tx/transactors/Vault/`. Covers vault creation, configuration, deposits, withdrawals, deletion, and clawback.
## Responsibility
Implements the vault mechanism for asset holding and loan collateral management. Allows creating vaults, depositing/withdrawing assets, configuring vault parameters, and managing vault lifecycle.
## Key Patterns
### Vault Transaction Types
```cpp
// VaultCreate - Create a new vault
// VaultSet - Configure vault parameters
// VaultDelete - Remove an empty vault
// VaultDeposit - Deposit assets into a vault
// VaultWithdraw - Withdraw assets from a vault
// VaultClawback - Issuer clawback from vault
```
### Feature Gate
```cpp
ctx.rules.enabled(featureSingleAssetVault)
```
### Batch Transaction Restriction
```cpp
// Vault transactions are DISABLED in batch transactions
// Listed in Batch::disabledTxTypes alongside Lending
// Cannot be included in atomic batch operations
```
### Depth Limiting for Recursive Operations
```cpp
// Vault operations may involve recursive state checks
// Use depth parameter to prevent infinite recursion
TER checkVaultState(ReadView const& view, AccountID const& id, int depth = 0);
if (depth > maxDepth) return tecINTERNAL;
```
### Integration with Lending
```cpp
// Vaults serve as collateral for the lending protocol
// VaultDeposit/Withdraw affect loan collateralization
// Vault state changes may trigger loan state recalculation
```
## Common Pitfalls
- Vault operations are disabled in batch transactions
- Vaults can only be deleted when empty
- Clawback has different authorization requirements than regular withdrawal
- Always respect depth limits in recursive vault state checks
- Vault operations may interact with lending protocol state
## Key Files
- `src/libxrpl/tx/transactors/Vault/VaultCreate.cpp` - Vault creation
- `src/libxrpl/tx/transactors/Vault/VaultSet.cpp` - Configuration
- `src/libxrpl/tx/transactors/Vault/VaultDelete.cpp` - Deletion
- `src/libxrpl/tx/transactors/Vault/VaultDeposit.cpp` - Asset deposit
- `src/libxrpl/tx/transactors/Vault/VaultWithdraw.cpp` - Asset withdrawal
- `src/libxrpl/tx/transactors/Vault/VaultClawback.cpp` - Issuer clawback

View File

@@ -0,0 +1,57 @@
# App Module Best Practices
## Description
Use when working with the main application layer in `src/xrpld/app/`. Covers the Application singleton, ledger management, consensus adapters, services, and runtime coordination.
## Responsibility
Contains the main application logic and runtime coordination for the rippled server. The Application singleton provides access to all services. Sub-modules handle ledger management, consensus, fee voting, amendments, path finding, and transaction queuing.
## Key Patterns
### Application Singleton
```cpp
// Application is the master interface - access all services through it
class Application {
virtual Config& config() = 0;
virtual Logs& logs() = 0;
virtual JobQueue& getJobQueue() = 0;
virtual LedgerMaster& getLedgerMaster() = 0;
virtual NetworkOPs& getOPs() = 0;
virtual NodeStore::Database& getNodeStore() = 0;
// ... many more service accessors
};
// Implemented by ApplicationImp (hidden in .cpp)
```
### ServiceRegistry Pattern
```cpp
// Services are injected via ServiceRegistry from libxrpl
// Application provides centralized access to all registered services
```
### Master Mutex
```cpp
// Recursive mutex protects shared state:
using MutexType = std::recursive_mutex;
// Protects: open ledger, server state, consensus engine
// Use std::lock_guard<Application::MutexType> for access
```
### Module Interface Pattern
```cpp
// Public interface: Module.h (abstract)
// Implementation: ModuleImp.h/cpp (hidden)
// Factory: make_Module() returns unique_ptr
```
## Common Pitfalls
- Never access Application services before setup() completes
- Always acquire master mutex when modifying open ledger or consensus state
- Use `std::recursive_mutex` (not plain mutex) - multiple services may lock re-entrantly
- Never create a second Application instance
## Key Files
- `src/xrpld/app/main/Application.h` - Core application interface
- `src/xrpld/app/main/Application.cpp` - Implementation (150+ includes)
- `src/xrpld/app/main/BasicApp.h` - Base application services
- `src/xrpld/app/main/GRPCServer.h` - gRPC server integration

View File

@@ -0,0 +1,47 @@
# App Consensus Module Best Practices
## Description
Use when working with RCL consensus adapters in `src/xrpld/app/consensus/`. Bridges the generic consensus algorithm to rippled-specific types.
## Responsibility
Adapts the generic consensus algorithm (in `xrpld/consensus/`) to work with rippled application types. Provides concrete type adapters for transactions, transaction sets, and ledgers.
## Key Patterns
### RCL Adapters
```cpp
// RCLCxTx - Adapts SHAMapItem as a consensus transaction
// RCLCxTxSet - Adapts SHAMap as a consensus transaction set
// RCLCxLedger - Adapts Ledger as a consensus ledger
// RCLConsensus - Glues generic consensus to rippled Application
```
### Adapter Pattern
```cpp
// Generic consensus works with abstract types via CRTP
// RCL adapters provide concrete implementations
class RCLConsensus : public Consensus<RCLConsensus> {
// Implements required methods using rippled types
// e.g., acquireLedger(), proposeTx(), relay()
};
```
### Validation Handling
```cpp
// RCLValidations tracks validation messages from the network
// Maps to the generic Validations<> template
// Handles trusted vs untrusted validators
```
## Common Pitfalls
- Adapter methods must match the CRTP interface exactly - compiler errors are cryptic
- Never import generic consensus types into adapter code - always go through the adapter
- RCLConsensus holds references to Application services - ensure Application outlives it
## Key Files
- `src/xrpld/app/consensus/RCLConsensus.h` - Main consensus orchestrator
- `src/xrpld/app/consensus/RCLConsensus.cpp` - Implementation
- `src/xrpld/app/consensus/RCLValidations.h` - Validation handling
- `src/xrpld/app/consensus/RCLCxTx.h` - Transaction adapter
- `src/xrpld/app/consensus/RCLCxTxSet.h` - Transaction set adapter
- `src/xrpld/app/consensus/RCLCxLedger.h` - Ledger adapter

View File

@@ -0,0 +1,67 @@
# App Ledger Module Best Practices
## Description
Use when working with ledger management in `src/xrpld/app/ledger/`. Covers ledger storage, retrieval, history, and the Ledger class itself.
## Responsibility
Manages the lifecycle of ledger objects: creation, storage, retrieval, history tracking, inbound acquisition from network, and order book caching. The Ledger class is the central data structure.
## Key Patterns
### Ledger Class
```cpp
// Ledger is composed of two SHAMaps:
// 1. State Map - Account roots, order books, ledger entries (STLedgerEntry)
// 2. Transaction Map - Transactions and metadata for that ledger
class Ledger final : public std::enable_shared_from_this<Ledger>,
public CountedObject<Ledger> {
// Can be mutable (sole ownership) or immutable (shared, read-only)
// Genesis ledger has special constructor
};
```
### Mutable vs Immutable
```cpp
// Mutable: Only one owner, can be modified
// Immutable: Shared via shared_ptr, read-only
// Transition: mutable -> immutable when accepted
// Never modify an immutable ledger
```
### LedgerMaster
```cpp
// Manages the chain of validated ledgers
// Tracks: current, validated, closed ledgers
// Handles ledger transitions during consensus
```
### Inbound Ledger Acquisition
```cpp
// InboundLedgers manages acquiring missing ledgers from peers
// InboundTransactions handles transaction set acquisition
// Both use async fetch with timeout and retry
```
### Iterator Adapters
```cpp
// sles_iter_impl - Iterate over SLE (state entries)
// txs_iter_impl - Iterate over transactions
// Efficient iteration without copying
```
## Common Pitfalls
- Never modify an immutable ledger - check mutability first
- Ledger must be shared via shared_ptr (enable_shared_from_this)
- Genesis ledger construction is special - don't use for normal ledgers
- LedgerMaster state transitions must be atomic with consensus
- CountedObject tracking helps detect leaks - don't disable it
## Key Files
- `src/xrpld/app/ledger/Ledger.h` - Core ledger class
- `src/xrpld/app/ledger/LedgerMaster.h` - Ledger chain management
- `src/xrpld/app/ledger/LedgerHistory.h` - Historical tracking
- `src/xrpld/app/ledger/LedgerCleaner.h` - Online deletion
- `src/xrpld/app/ledger/InboundLedgers.h` - Network acquisition
- `src/xrpld/app/ledger/OrderBookDB.h` - Order book cache
- `src/xrpld/app/ledger/TransactionMaster.h` - Transaction lookup

View File

@@ -0,0 +1,18 @@
# App Ledger Detail Module Best Practices
## Description
Use when working with ledger implementation details in `src/xrpld/app/ledger/detail/`. Internal helpers for the ledger module.
## Responsibility
Internal implementation details for the app/ledger module. Contains private helpers for ledger state management, iteration, and storage operations.
## Key Patterns
### Detail Namespace Convention
- Code in `detail/` is internal to the `app/ledger` module
- Never include detail headers from outside `app/ledger`
- If you need functionality, use the public `app/ledger/` headers instead
## Common Pitfalls
- Detail implementations may change without API compatibility
- Never expose detail types in public interfaces

View File

@@ -0,0 +1,54 @@
# App Main Module Best Practices
## Description
Use when working with application initialization and lifecycle in `src/xrpld/app/main/`. Covers Application startup, shutdown, and core services.
## Responsibility
Application initialization, lifecycle management, and core service wiring. Contains the Application interface and its implementation, gRPC server, load management, node identity, and the node store scheduler.
## Key Patterns
### Application Lifecycle
```cpp
// 1. Construct Application (parse config, create services)
// 2. setup() - Initialize all services, open databases
// 3. run() - Main event loop
// 4. signalStop() - Graceful shutdown
// 5. Destructor - Clean up resources
```
### Node Identity
```cpp
// NodeIdentity manages the node's public/private key pair
// Used for peer handshake, session signatures, and cluster membership
// Keys persisted in wallet_db
```
### Load Manager
```cpp
// Tracks server load across all subsystems
// Triggers load-based fee escalation
// Monitors job queue depth and execution time
```
### gRPC Server
```cpp
// Optional gRPC server alongside JSON-RPC
// Uses proto definitions from include/xrpl/proto/
// Separate handler set from JSON-RPC
```
## Common Pitfalls
- setup() must complete before any service is used
- signalStop() should be called for graceful shutdown - avoid hard kills
- Node identity keys must never be logged or exposed
- Load manager affects fee escalation - test under load
## Key Files
- `src/xrpld/app/main/Application.h` - Core interface
- `src/xrpld/app/main/Application.cpp` - Implementation
- `src/xrpld/app/main/BasicApp.h` - Base services
- `src/xrpld/app/main/GRPCServer.h` - gRPC integration
- `src/xrpld/app/main/LoadManager.h` - Load tracking
- `src/xrpld/app/main/NodeIdentity.h` - Node key management
- `src/xrpld/app/main/NodeStoreScheduler.h` - Async DB scheduler

View File

@@ -0,0 +1,75 @@
# App Misc Module Best Practices
## Description
Use when working with application services in `src/xrpld/app/misc/`. Covers fee voting, amendments, SHAMapStore, transaction queue, validator management, and NetworkOPs.
## Responsibility
Collection of application-level services: fee voting system, amendment mechanism, online deletion (SHAMapStore), transaction queue (TxQ), validator key/list management, and NetworkOPs (the central operations coordinator).
## Key Patterns
### Fee Voting
```cpp
// Validators vote on fee schedules every 256 ledgers ("voting ledgers")
// Pseudo-transactions injected to set fees
// Majority vote determines new fee schedule
// FeeVote.h - voting logic
// FeeEscalation.md - escalation documentation
```
### Amendment Mechanism
```cpp
// Network-wide ledger rule changes
// Requires 80% validator approval sustained for 2 weeks
// Tracked as pseudo-transactions in each ledger
// AmendmentTableImpl.h manages tracking and state
```
### SHAMapStore (Online Delete)
```cpp
// Prunes old ledger history automatically
// Uses rotation between two databases
// Configurable deletion intervals
// Must not delete data needed for active operations
```
### Transaction Queue (TxQ)
```cpp
// Queues transactions when ledger is full
// Priority based on fee level
// Handles fee escalation under load
// TxQ.h - queue implementation
```
### Validator Management
```cpp
// ValidatorKeys.h - Node's own validator keys
// ValidatorList.h - Trusted validator list (UNL)
// ValidatorSite.h - Sites serving validator lists
// Keys loaded from config, lists fetched from URLs
```
### NetworkOPs
```cpp
// Central operations coordinator - the "god object"
// Coordinates: consensus, ledger acceptance, transaction submission
// NetworkOPs.cpp is one of the largest files in the codebase
// Access via app.getOPs()
```
## Common Pitfalls
- Fee voting only happens on voting ledgers (every 256) - don't trigger manually
- Amendments require 2-week sustained 80% approval - no fast path
- SHAMapStore deletion must respect the advisory_delete safety window
- TxQ priority depends on current fee escalation level
- NetworkOPs is massive - changes here affect many systems
## Key Files
- `src/xrpld/app/misc/FeeVote.h` - Fee voting system
- `src/xrpld/app/misc/AmendmentTableImpl.h` - Amendment tracking
- `src/xrpld/app/misc/SHAMapStore.h` - Online deletion
- `src/xrpld/app/misc/TxQ.h` - Transaction queue
- `src/xrpld/app/misc/ValidatorKeys.h` - Validator key management
- `src/xrpld/app/misc/ValidatorList.h` - Trusted validator list
- `src/xrpld/app/misc/NetworkOPs.cpp` - Central operations
- `src/xrpld/app/misc/README.md` - Architecture documentation

View File

@@ -0,0 +1,18 @@
# App Misc Detail Module Best Practices
## Description
Use when working with internal service implementation details in `src/xrpld/app/misc/detail/`. Internal helpers for the misc services module.
## Responsibility
Internal implementation details for app/misc services (fee voting internals, amendment table implementation, SHAMapStore internals, etc.).
## Key Patterns
### Detail Namespace Convention
- Code in `detail/` is internal to the `app/misc` module
- Implementation classes (e.g., AmendmentTableImpl) live here
- Never include detail headers from outside `app/misc`
## Common Pitfalls
- Detail implementations may change without API compatibility
- Always use the public `app/misc/` interfaces

View File

@@ -0,0 +1,53 @@
# App Paths Module Best Practices
## Description
Use when working with payment path finding in `src/xrpld/app/paths/`. Covers the path finding algorithm, trust line caching, and AMM liquidity integration.
## Responsibility
Implements the XRP Ledger payment path finding algorithm at the application level. Manages path requests, trust line caching, and integration with Automated Market Maker liquidity.
## Key Patterns
### Path Finding
```cpp
// Pathfinder: Algorithm that finds payment paths between accounts
// Considers: trust lines, order books, AMM pools
// Returns: Set of paths ranked by cost/quality
```
### Path Request Management
```cpp
// PathRequest - Individual path find request
// PathRequests - Manages collection of active requests
// Requests can be one-shot or subscribed (streaming updates)
```
### Trust Line Caching
```cpp
// RippleLineCache caches trust line data
// Avoids repeated ledger lookups during path finding
// Cache is invalidated on ledger close
// TrustLine.h provides the trust line representation
```
### AMM Integration
```cpp
// AMMLiquidity.h - Integrates AMM pools into path finding
// AMMOffer.h - Represents AMM as a synthetic offer
// AMM pools are treated as a special offer type in the path finder
```
## Common Pitfalls
- Path finding is computationally expensive - respect search depth limits
- Trust line cache must be invalidated on ledger close
- AMM liquidity changes with pool state - don't cache AMM offers across ledgers
- Path subscriptions can be memory-intensive with many clients
## Key Files
- `src/xrpld/app/paths/Pathfinder.h` - Path finding algorithm
- `src/xrpld/app/paths/PathRequest.h` - Individual request handling
- `src/xrpld/app/paths/PathRequests.h` - Request collection management
- `src/xrpld/app/paths/RippleLineCache.h` - Trust line caching
- `src/xrpld/app/paths/TrustLine.h` - Trust line representation
- `src/xrpld/app/paths/AMMLiquidity.h` - AMM pool integration
- `src/xrpld/app/paths/AMMOffer.h` - Synthetic AMM offers

View File

@@ -0,0 +1,18 @@
# App Paths Detail Module Best Practices
## Description
Use when working with path finding implementation details in `src/xrpld/app/paths/detail/`. Internal helpers for the path finding module.
## Responsibility
Internal implementation details for the path finding algorithm, including search heuristics, cost calculation helpers, and internal data structures.
## Key Patterns
### Detail Namespace Convention
- Code in `detail/` is internal to the `app/paths` module
- Contains algorithm-specific helpers not needed by callers
- Never include detail headers from outside `app/paths`
## Common Pitfalls
- Path finding internals are performance-sensitive - profile before modifying
- Detail implementations may change without API compatibility

View File

@@ -0,0 +1,39 @@
# App RDB Module Best Practices
## Description
Use when working with application-level database operations in `src/xrpld/app/rdb/`. Covers database abstractions and backend implementations.
## Responsibility
Application-level relational database operations. Provides interfaces for peer finding data storage, SQLite backend implementation, and database operation details.
## Key Patterns
### Interface-Based Design
```cpp
// PeerFinder.h - Abstract interface for peer data storage
// Backend implementations in backend/ subdirectory
// Allows swapping database backends without changing callers
```
### SQLite Backend
```cpp
// SQLiteDatabase.h - Primary backend implementation
// Uses SOCI wrapper from libxrpl/rdb
// Handles: peer data, transaction history, ledger metadata
```
### Backend Abstraction
```cpp
// backend/ directory contains concrete implementations
// backend/detail/ has implementation-specific helpers
// detail/ has shared implementation details
```
## Common Pitfalls
- Always use the abstract interface, not the SQLite backend directly
- Database operations should be off the main thread (use job queue)
- Respect the SOCI wrapper patterns from libxrpl/rdb
## Key Files
- `src/xrpld/app/rdb/PeerFinder.h` - Peer data interface
- `src/xrpld/app/rdb/backend/SQLiteDatabase.h` - SQLite implementation

View File

@@ -0,0 +1,31 @@
# App RDB Backend Module Best Practices
## Description
Use when working with database backend implementations in `src/xrpld/app/rdb/backend/`. Covers concrete database implementations.
## Responsibility
Concrete database backend implementations for the app/rdb module. Primary implementation is SQLiteDatabase.
## Key Patterns
### SQLiteDatabase
```cpp
// Primary backend implementation using SQLite via SOCI
// Handles: peer storage, transaction history, ledger metadata
// Thread-safe via session-per-thread pattern from libxrpl/rdb
```
### Backend Detail
```cpp
// backend/detail/ contains SQLite-specific helpers
// Schema creation, migration, and optimization queries
```
## Common Pitfalls
- Always use parameterized queries via SOCI - never raw string SQL
- Database files can grow large - implement periodic VACUUM
- WAL checkpoint scheduling prevents unbounded WAL growth
## Key Files
- `src/xrpld/app/rdb/backend/SQLiteDatabase.h` - SQLite implementation
- `src/xrpld/app/rdb/backend/detail/` - SQLite-specific helpers

View File

@@ -0,0 +1,11 @@
# App RDB Backend Detail Module Best Practices
## Description
Use when working with database backend implementation details in `src/xrpld/app/rdb/backend/detail/`. SQLite-specific internal helpers.
## Responsibility
SQLite-specific implementation details: schema definitions, migration scripts, query optimization, and SOCI binding helpers.
## Common Pitfalls
- Schema migrations must be backwards-compatible
- Never include these headers from outside the rdb/backend module

View File

@@ -0,0 +1,18 @@
# App RDB Detail Module Best Practices
## Description
Use when working with database implementation details in `src/xrpld/app/rdb/detail/`. Internal helpers for the relational database module.
## Responsibility
Internal implementation details for app-level database operations, including SQL query helpers and schema management.
## Key Patterns
### Detail Namespace Convention
- Code in `detail/` is internal to the `app/rdb` module
- Contains SQL query construction and result parsing helpers
- Never include detail headers from outside `app/rdb`
## Common Pitfalls
- SQL queries must use parameterized bindings (SOCI style) - never string concatenation
- Detail implementations may change without API compatibility

View File

@@ -0,0 +1,34 @@
# App Tx Module Best Practices
## Description
Use when working with application-level transaction handling in `src/xrpld/app/tx/`. Covers transaction submission, validation, and application-layer processing.
## Responsibility
Application-level transaction handling that bridges the protocol-layer transaction processing (libxrpl/tx) with the running server. Handles transaction submission, validation, and integration with the consensus process.
## Key Patterns
### Relationship to libxrpl/tx
```cpp
// libxrpl/tx: Protocol-level transaction processing (Transactor, preflight, preclaim, doApply)
// xrpld/app/tx: Application-level orchestration (submission, queuing, consensus integration)
// This module calls into libxrpl/tx for actual transaction execution
```
### Transaction Submission Flow
```cpp
// 1. Client submits transaction via RPC
// 2. app/tx validates and queues transaction
// 3. Transaction enters TxQ (app/misc/TxQ)
// 4. Consensus selects transactions for next ledger
// 5. libxrpl/tx executes selected transactions
```
## Common Pitfalls
- Don't duplicate transaction validation logic - defer to libxrpl/tx
- Application-level checks (queue depth, fee escalation) happen here, not in libxrpl
- Transaction metadata is generated at this level after execution
## Key Files
- `src/xrpld/app/tx/` - Application transaction handling
- `src/xrpld/app/tx/detail/` - Implementation details

View File

@@ -0,0 +1,11 @@
# App Tx Detail Module Best Practices
## Description
Use when working with application transaction handling details in `src/xrpld/app/tx/detail/`. Internal helpers for transaction submission and processing.
## Responsibility
Internal implementation details for application-level transaction handling, including submission validation, queue integration, and metadata generation.
## Common Pitfalls
- Don't duplicate libxrpl/tx validation logic here
- Detail implementations may change without API compatibility

View File

@@ -0,0 +1,59 @@
# Consensus Module Best Practices
## Description
Use when working with the generic consensus algorithm in `src/xrpld/consensus/`. This is the application-independent consensus implementation.
## Responsibility
Implements the generic consensus algorithm separate from application-specific types. Uses CRTP (Curiously Recurring Template Pattern) to allow the application layer to plug in concrete types without virtual dispatch overhead.
## Key Patterns
### CRTP Design
```cpp
// Generic consensus uses CRTP - derived class provides concrete types
template <class Derived>
class Consensus {
// Calls static_cast<Derived*>(this)->method() for app-specific behavior
// No virtual dispatch overhead
};
// Application adapter:
class RCLConsensus : public Consensus<RCLConsensus> {
// Provides concrete types: RCLCxTx, RCLCxTxSet, RCLCxLedger
};
```
### Consensus Phases
```cpp
// Open -> Establish -> Accept
// Open: Collecting transactions
// Establish: Proposing and voting on transaction set
// Accept: Applying agreed-upon transaction set to ledger
```
### Consensus Parameters (ConsensusParms.h)
```cpp
// Timing parameters for consensus rounds
// These are tuned for network behavior - don't change without careful analysis
```
### Disputed Transactions
```cpp
// DisputedTx tracks transactions where validators disagree
// Votes are collected and transaction is included/excluded based on threshold
```
## Common Pitfalls
- Never modify consensus parameters without understanding network-wide impact
- CRTP means compilation errors from type mismatches appear in template instantiation - read errors carefully
- The generic consensus module should NEVER depend on application-specific types (Ledger, STTx, etc.)
- Always test consensus changes with multi-node simulation
## Key Files
- `src/xrpld/consensus/Consensus.h` - Main consensus class (extensively documented)
- `src/xrpld/consensus/ConsensusParms.h` - Timing parameters
- `src/xrpld/consensus/ConsensusProposal.h` - Proposal structures
- `src/xrpld/consensus/DisputedTx.h` - Transaction dispute tracking
- `src/xrpld/consensus/LedgerTiming.h` - Ledger timing calculations
- `src/xrpld/consensus/LedgerTrie.h` - Transaction set representation
- `src/xrpld/consensus/Validations.h` - Generic validation tracking

View File

@@ -0,0 +1,55 @@
# Core Module Best Practices
## Description
Use when working with core configuration and system services in `src/xrpld/core/`. Covers Config, time keeping, and network identity.
## Responsibility
System-level configuration and core services. The Config class extends BasicConfig from libxrpl with rippled-specific settings. Provides time keeping and network ID management.
## Key Patterns
### Config Class
```cpp
// Config extends BasicConfig from libxrpl
class Config : public BasicConfig {
// SizedItem enum for memory-dependent configuration
enum SizedItem { siSweepInterval, siNodeCacheSize, ... };
// FeeSetup for fee parameters
struct FeeSetup {
XRPAmount reference_fee;
XRPAmount account_reserve;
XRPAmount owner_reserve;
};
// Access sections by name
auto const& section = config["server"];
};
```
### Configuration Sections
```cpp
// Section names defined in ConfigSections.h
static constexpr char const* SECTION_NODE_DB = "node_db";
static constexpr char const* SECTION_VALIDATORS = "validators";
// Always use constants, never string literals
```
### Gradual Refactoring
```cpp
// Legacy config uses mixed patterns - refactoring is ongoing
// New code should follow the Section-based approach
// Deprecated patterns are documented with TODO comments
```
## Common Pitfalls
- Always use `ConfigSections.h` constants for section names
- Config extends BasicConfig - check both for available methods
- SizedItem values scale with node size configuration - don't hardcode sizes
- Never modify Config after Application startup
## Key Files
- `src/xrpld/core/Config.h` - Configuration object
- `src/xrpld/core/ConfigSections.h` - Section name constants
- `src/xrpld/core/TimeKeeper.h` - System time tracking
- `src/xrpld/core/NetworkIDServiceImpl.h` - Network ID implementation

View File

@@ -0,0 +1,11 @@
# Core Detail Module Best Practices
## Description
Use when working with core configuration implementation details in `src/xrpld/core/detail/`. Internal helpers for the Config system.
## Responsibility
Internal implementation details for the core configuration module, including config parsing helpers and platform-specific abstractions.
## Common Pitfalls
- Never include detail headers from outside the core module
- Config parsing must handle all edge cases gracefully (missing sections, invalid values)

View File

@@ -0,0 +1,74 @@
# Overlay Module Best Practices
## Description
Use when working with P2P networking in `src/xrpld/overlay/`. Covers peer connections, protocol negotiation, message relay, and clustering.
## Responsibility
Manages peer-to-peer connections and the overlay network protocol. Handles HTTP/1.1 upgrade handshake, session signatures (MITM prevention), Protocol Buffer message serialization, message compression, and cluster node management.
## Key Patterns
### HTTP/1.1 Upgrade Handshake
```cpp
// Connection starts as HTTP, upgrades to ripple protocol
// Custom headers:
// Connect-As, Public-Key, Session-Signature
// Network-ID, Network-Time
// Closed-Ledger, Previous-Ledger
// Remote-IP, Local-IP, Crawl
```
### Session Signature (MITM Prevention)
```cpp
// Binds SSL/TLS session to node identities
// Each peer signs the shared SSL session data
// Prevents man-in-the-middle attacks at the protocol level
```
### Message Serialization
```cpp
// Google Protocol Buffers for all p2p messages
// Messages are compressed before transmission
// Compression.h handles LZ4/no-compression selection
```
### Peer Management
```cpp
// Overlay manages the set of connected peers
class Overlay {
virtual Peer::ptr findPeerByShortID(Peer::id_t) = 0;
virtual void send(std::shared_ptr<Message> const&) = 0; // Broadcast
virtual void relay(Message const&, uint256 const& suppression) = 0;
};
```
### Clustering
```cpp
// Multiple rippled nodes can form a cluster
// Cluster nodes: share load, distribute crypto operations
// Cluster membership verified via node public keys
```
### Reduce Relay
```cpp
// ReduceRelayCommon.h - Minimize redundant message relay
// Uses HashRouter for message deduplication
// Peers track which messages they've already seen
```
## Common Pitfalls
- Always validate session signatures during handshake - never skip
- Never send uncompressed messages to peers that advertise compression support
- Cluster keys must be pre-configured - no dynamic cluster joining
- Message suppression via HashRouter is critical for network health - never bypass
- Protocol Buffer messages must match the expected schema version
## Key Files
- `src/xrpld/overlay/Overlay.h` - Main overlay manager interface
- `src/xrpld/overlay/Peer.h` - Peer connection representation
- `src/xrpld/overlay/PeerSet.h` - Collection of peers
- `src/xrpld/overlay/Cluster.h` - Cluster management
- `src/xrpld/overlay/Message.h` - Message structure
- `src/xrpld/overlay/Compression.h` - Message compression
- `src/xrpld/overlay/ReduceRelayCommon.h` - Relay optimization
- `src/xrpld/overlay/README.md` - Comprehensive protocol documentation

View File

@@ -0,0 +1,27 @@
# Overlay Detail Module Best Practices
## Description
Use when working with P2P networking implementation details in `src/xrpld/overlay/detail/`. Internal helpers for the overlay module.
## Responsibility
Internal implementation details for the overlay networking layer, including protocol message handling, peer connection state machines, and handshake implementation.
## Key Patterns
### PeerImp
```cpp
// PeerImp is the concrete implementation of the Peer interface
// Manages: SSL connection, protocol state, message queuing
// Uses enable_shared_from_this for async callback safety
```
### OverlayImpl
```cpp
// OverlayImpl is the concrete implementation of Overlay
// Manages: listening sockets, peer lifecycle, broadcast
```
## Common Pitfalls
- Peer connection state machine transitions must be atomic
- Never access PeerImp internals from outside overlay/detail/
- Message queuing must respect back-pressure limits

View File

@@ -0,0 +1,58 @@
# PeerFinder Module Best Practices
## Description
Use when working with network discovery in `src/xrpld/peerfinder/`. Covers peer bootstrap, cache management, and connection slot strategy.
## Responsibility
Bootstraps into the XRP Ledger network and discovers peers. Manages bootcache (persistent addresses ranked by success), livecache (ephemeral recently-seen peers), and connection slot allocation.
## Key Patterns
### Three-Stage Connection Strategy
```cpp
// Stage 1: Connect to fixed peers (configured addresses)
// Stage 2: Try Livecache addresses (recently seen, with open slots)
// Stage 3: Fall back to Bootcache (persistent, ranked by valence)
```
### Bootcache (Persistent)
```cpp
// Persistent store of peer addresses ranked by "valence" (connection success)
// Higher valence = more reliable peer
// Persisted across restarts
// Used as fallback when livecache is empty
```
### Livecache (Ephemeral)
```cpp
// Recently seen peers with available connection slots
// Uses hop counts for distance estimation
// Random distribution for load balancing
// Not persisted - rebuilt on restart via gossip
```
### Slot Management
```cpp
// Slot states: accept, connect, connected, active, closing
// Slot properties: Inbound/Outbound, Fixed, Cluster
// Slots track connection lifecycle from handshake to disconnect
```
### Callback Pattern
```cpp
// Abstract interface for socket operations
// PeerFinder doesn't directly manage sockets
// Delegates I/O to the overlay layer via callbacks
```
## Common Pitfalls
- Fixed peers should always be tried first (Stage 1) - they are trusted
- Bootcache valence can decay over time - implement proper aging
- Livecache entries expire quickly - don't rely on stale data
- Slot limits prevent connection exhaustion - never bypass them
- Always check README.md for algorithm details before modifying
## Key Files
- `src/xrpld/peerfinder/PeerfinderManager.h` - Main manager interface
- `src/xrpld/peerfinder/Slot.h` - Connection slot representation
- `src/xrpld/peerfinder/README.md` - Extensive design documentation

View File

@@ -0,0 +1,21 @@
# PeerFinder Detail Module Best Practices
## Description
Use when working with peer discovery implementation details in `src/xrpld/peerfinder/detail/`. Internal helpers for the peerfinder module.
## Responsibility
Internal implementation details for peer discovery: bootcache persistence, livecache management, slot state machine, and connection strategy implementation.
## Key Patterns
### Logic Class
```cpp
// The main implementation class for peer finding
// Implements the three-stage connection strategy
// Manages bootcache and livecache state
```
## Common Pitfalls
- Bootcache persistence must be atomic to prevent corruption
- Livecache expiration must be checked on every access
- Never include detail headers from outside peerfinder/

View File

@@ -0,0 +1,31 @@
# PerfLog Module Best Practices
## Description
Use when working with performance logging in `src/xrpld/perflog/`. Covers performance instrumentation and metric collection.
## Responsibility
Performance logging and instrumentation for the rippled server. Tracks timing data, throughput metrics, and operational statistics for monitoring and debugging.
## Key Patterns
### Performance Logging Interface
```cpp
// Abstract interface for performance data collection
// Implementations can log to file, export to monitoring systems, etc.
// Enabled/disabled via configuration
```
### Detail Namespace
```cpp
// Implementation details in detail/ subdirectory
// Not part of public API
```
## Common Pitfalls
- Performance logging should have minimal overhead when disabled
- Never log sensitive data (keys, balances) in performance logs
- Ensure timestamps use consistent clock sources
## Key Files
- `src/xrpld/perflog/` - Performance logging implementation
- `src/xrpld/perflog/detail/` - Implementation details

View File

@@ -0,0 +1,11 @@
# PerfLog Detail Module Best Practices
## Description
Use when working with performance logging implementation details in `src/xrpld/perflog/detail/`. Internal helpers for the perflog module.
## Responsibility
Internal implementation details for performance logging, including metric collection, formatting, and output management.
## Common Pitfalls
- Performance logging overhead must be minimal when disabled
- Never include detail headers from outside perflog/

View File

@@ -0,0 +1,91 @@
# RPC Module Best Practices
## Description
Use when working with RPC request handling in `src/xrpld/rpc/`. Covers command dispatch, handler implementation, coroutine suspension, and the gRPC interface.
## Responsibility
HTTP/JSON and gRPC RPC interface to rippled. Dispatches requests to 40+ command handlers, manages request context, supports coroutine-based suspension for async operations, and handles user roles/permissions.
## Key Patterns
### RPC Handler Pattern
```cpp
// Each handler is a function taking context, returning Json::Value
Json::Value doMyCommand(RPC::JsonContext& context) {
// Validate parameters
if (!context.params.isMember("field"))
return RPC::missing_field_error("field");
// Access application services
auto& app = context.app;
// Build response
Json::Value result(Json::objectValue);
result["status"] = "success";
return result;
}
```
### Coroutine Suspension
```cpp
// RPC handlers can suspend for async operations
// Key types:
// Callback - 0-argument function
// Continuation - Takes callback, promises to call it later
// Suspend - Function from coroutine that takes continuation
// Coroutine - Function given suspend to enable suspension
// This allows handlers to yield without blocking threads
```
### Request Context
```cpp
struct JsonContext {
Application& app;
Resource::Charge& loadType;
Json::Value params;
beast::Journal j;
Role role; // User, Admin, Identified, etc.
};
```
### Role-Based Access
```cpp
enum class Role { GUEST, USER, ADMIN, IDENTIFIED, PROXY, FORBID };
// Handlers specify minimum required role
// Admin handlers only accessible from admin IP ranges
```
### Error Handling
```cpp
// Standard error helpers:
RPC::missing_field_error("field_name");
RPC::invalid_field_error("field_name");
RPC::make_error(rpcINVALID_PARAMS, "description");
// Errors injected into JSON response
```
### gRPC Handlers
```cpp
// Separate handler set for gRPC interface
// Defined in GRPCHandlers.h
// Use Protocol Buffer request/response types
// Convert to/from native types at boundary
```
## Common Pitfalls
- Always validate parameters before accessing them
- Check user Role before executing privileged operations
- Use coroutine suspension for any operation that might block
- Never return internal data structures directly - always convert to JSON
- Handler functions are in `handlers/` directory - one file per command or group
- gRPC handlers must convert proto types to native types at the boundary
## Key Files
- `src/xrpld/rpc/RPCHandler.h` - Command dispatcher
- `src/xrpld/rpc/Context.h` - RPC context/state
- `src/xrpld/rpc/Status.h` - RPC status codes
- `src/xrpld/rpc/Role.h` - User role/permissions
- `src/xrpld/rpc/GRPCHandlers.h` - gRPC integration
- `src/xrpld/rpc/handlers/` - Individual command handlers (40+)
- `src/xrpld/rpc/README.md` - Coroutine documentation

View File

@@ -0,0 +1,11 @@
# RPC Detail Module Best Practices
## Description
Use when working with RPC implementation details in `src/xrpld/rpc/detail/`. Internal helpers for the RPC module.
## Responsibility
Internal implementation details for RPC handling, including request parsing, response formatting, coroutine machinery, and middleware.
## Common Pitfalls
- Coroutine state must be carefully managed to prevent leaks
- Never include detail headers from outside rpc/

View File

@@ -0,0 +1,74 @@
# RPC Handlers Module Best Practices
## Description
Use when adding or modifying RPC command handlers in `src/xrpld/rpc/handlers/`. Contains 40+ individual RPC command implementations.
## Responsibility
Individual RPC command handler implementations. Each file implements one or more related RPC commands following the standard handler pattern.
## Key Patterns
### Handler Function Signature
```cpp
// Standard handler pattern
Json::Value doMyCommand(RPC::JsonContext& context) {
// 1. Validate parameters
if (!context.params.isMember("required_field"))
return RPC::missing_field_error("required_field");
// 2. Check permissions
// (Role already verified by dispatcher based on handler metadata)
// 3. Access application services
auto& app = context.app;
auto& ledger = context.ledgerMaster.getValidatedLedger();
// 4. Execute logic
// ...
// 5. Build and return response
Json::Value result(Json::objectValue);
result["status"] = "success";
return result;
}
```
### Parameter Validation
```cpp
// Use standard error helpers
RPC::missing_field_error("field_name"); // Required field missing
RPC::invalid_field_error("field_name"); // Field has wrong type/value
RPC::make_error(rpcINVALID_PARAMS, "description"); // Generic error
```
### Adding a New Handler
1. Create a new .cpp file in `handlers/`
2. Implement the handler function following the pattern above
3. Register the command in the handler dispatch table
4. Document the command parameters and response format
### Common Handler Files
```
AccountInfo.cpp - account_info command
AccountLines.cpp - account_lines (trust lines)
AccountOffers.cpp - account_offers
Submit.cpp - submit (transaction submission)
Subscribe.cpp - subscribe (event streaming)
LedgerData.cpp - ledger_data
ServerInfo.cpp - server_info
Fee1.cpp - fee command
Tx.cpp - tx (transaction lookup)
BookOffers.cpp - book_offers (order book)
```
## Common Pitfalls
- Always validate ALL parameters before using them
- Never return internal data structures - convert to JSON at the boundary
- Respect Role-based access control - admin handlers must check role
- Handlers should be stateless - all state comes from context
- Use coroutine suspension for any blocking operation (DB queries, network)
- Error responses must follow the standard error format
## Key Files
- `src/xrpld/rpc/handlers/` - All handler implementations
- `src/xrpld/rpc/RPCHandler.h` - Dispatch table and registration

View File

@@ -0,0 +1,32 @@
# SHAMap (xrpld) Module Best Practices
## Description
Use when working with application-level SHAMap operations in `src/xrpld/shamap/`. Covers NodeFamily and application integration with the Merkle tree.
## Responsibility
Application-level integration of the SHAMap (Merkle radix tree) with the rippled server. Provides NodeFamily for managing tree node relationships and connecting the generic SHAMap to the node store.
## Key Patterns
### NodeFamily
```cpp
// NodeFamily connects SHAMap to the persistent NodeStore
// Provides: database access, tree node creation, hash verification
// Each SHAMap references a Family for storage operations
```
### Relationship to libxrpl/shamap
```cpp
// libxrpl/shamap: Generic Merkle tree implementation
// xrpld/shamap: Application-specific integration (NodeFamily, storage)
// The generic tree doesn't know about databases - NodeFamily bridges the gap
```
## Common Pitfalls
- Always use NodeFamily to create SHAMap instances connected to storage
- The libxrpl SHAMap is the implementation - this module is the glue layer
- Don't duplicate SHAMap logic here - extend via NodeFamily only
## Key Files
- `src/xrpld/shamap/NodeFamily.h` - Family relationship management
- `src/xrpld/shamap/NodeFamily.cpp` - Implementation