Compare commits

..

4 Commits

Author SHA1 Message Date
Vladislav Vysokikh
df24ee0774 Version 2.6.2 2025-11-19 20:47:46 +00:00
Vladislav Vysokikh
c6aa80b0ef fixed macos build and removed ci flow publishing libxrpl 2025-11-19 20:47:32 +00:00
Bronek Kozicki
283bc3ea39 Remove directory size limit (#5935)
This change introduces the `fixDirectoryLimit` amendment to remove the directory pages limit. We found that the directory size limit is easier to hit than originally assumed, and there is no good reason to keep this limit, since the object reserve provides the necessary incentive to avoid creating unnecessary objects on the ledger.
2025-11-19 18:07:13 +00:00
Jingchen
ebc2a9a625 fix: Skip processing transaction batch if the batch is empty (#5670)
Avoids an assertion failure in NetworkOPsImp::apply in the unlikely event that all incoming transactions are invalid.
2025-11-18 09:17:48 +00:00
1857 changed files with 196088 additions and 89182 deletions

View File

@@ -1,20 +1,4 @@
---
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
@@ -34,10 +18,23 @@ AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true
ColumnLimit: 120
ColumnLimit: 80
CommentPragmas: "^ IWYU pragma:"
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
@@ -69,6 +66,8 @@ IndentFunctionDeclarationAfterType: false
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
@@ -97,7 +96,7 @@ TabWidth: 8
UseTab: Never
QualifierAlignment: Right
---
Language: Proto
BasedOnStyle: Google
ColumnLimit: 0
Language: JavaScript
---
Language: Json
IndentWidth: 2

View File

@@ -1,54 +0,0 @@
# Workflow Orchestration
## 1. Plan Mode Default
- Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
- If something goes sideways, STOP and re-plan immediately - don't keep pushing
- Use plan mode for verification steps, not just building
- Write detailed specs upfront to reduce ambiguity
## 2. Subagent Strategy
- Use subagents liberally to keep main context window clean
- Offload research, exploration, and parallel analysis to subagents
- For complex problems, throw compute at it via parallelizing
- One task per subagent for focused execution
## 3. Self-Improvement Loop
- After ANY correction from the user: update `tasks/lessons.md` with the pattern
- Write rules for yourself that prevent the same mistake
- Ruthlessly iterate on these rules until mistake drops
- Review lessons at session start for relevant project
## 4. Verification Before Done
- Never mark a task complete without proving it works
- Diff behavior between main and your changes when relevant
- Ask yourself: "Would a staff engineer approve this?"
- Run tests, check logs, demonstrate correctness
## 5. Demand Elegance (Balanced)
- For non-trivial changes: pause and ask "is there a more elegant way?"
- If a fix feels hacky: "Know now, do later, implement the elegant solution"
- Skip this for simple, obvious fixes - don't over-engineer
- Challenge your own first solution
## 6. Autonomous Bug Fixing
- When given a bug report: just fix it. Don't ask for hand-holding
- Point at logs, errors, failing tests - then resolve them
- Zero context switching required from the user
- Go fix failing CI tests without being told how
# Task Management
1. **Plan First**: Write plan to `tasks/todo.md` with checkable items
2. **Verify Plans**: Check in before starting implementation
3. **Track Progress**: Mark items complete as you go
4. **Explain Changes**: High-level summary at each step
5. **Document Results**: Add review section to `tasks/todo.md`
6. **Capture Lessons**: Update `tasks/lessons.md` after corrections
# Core Principles
**Simplicity First**: Make every change as simple as possible. Impact minimal code.
**No Boilerplate**: Skip documentation. No README/docs bloat. Test only if requested.
**Minimal Impact**: Changes should only touch what's necessary. Avoid introducing bugs.

View File

@@ -1,530 +0,0 @@
# XRPL Amendment Creation Skill
This skill guides you through creating XRPL amendments, whether for brand new features or fixes/extensions to existing functionality.
## Amendment Types
There are two main types of amendments:
1. **New Feature Amendment** (`feature{Name}`) - Entirely new functionality
2. **Fix/Extension Amendment** (`fix{Name}`) - Modifications to existing functionality
## Step 1: Determine Amendment Type
Ask the user:
- Is this a **brand new feature** (new transaction type, ledger entry, or capability)?
- Or is this a **fix or extension** to existing functionality?
---
## For NEW FEATURE Amendments
### Checklist:
#### 1. Feature Definition in features.macro
**ONLY FILE TO EDIT:** `include/xrpl/protocol/detail/features.macro`
- [ ] Add to TOP of features.macro (reverse chronological order):
```
XRPL_FEATURE(YourFeatureName, Supported::no, VoteBehavior::DefaultNo)
```
- [ ] This creates the variable `featureYourFeatureName` automatically
- [ ] Follow naming convention: Use the feature name WITHOUT the "feature" prefix
- [ ] Examples: `Batch``featureBatch`, `LendingProtocol``featureLendingProtocol`
#### 2. Support Status
- [ ] Start with `Supported::no` during development
- [ ] Change to `Supported::yes` when ready for network voting
- [ ] Use `VoteBehavior::DefaultNo` (validators must explicitly vote for it)
#### 3. Code Implementation
- [ ] Implement new functionality (transaction type, ledger entry, etc.)
- [ ] Add feature gate check in preflight:
```cpp
if (!env.current()->rules().enabled(feature{Name}))
{
return temDISABLED;
}
```
#### 4. Disable Route Handling
- [ ] Ensure transaction returns `temDISABLED` when amendment is disabled
- [ ] Implement early rejection in preflight/preclaim phase
- [ ] Add appropriate error messages
#### 5. Test Implementation
Create comprehensive test suite with this structure:
```cpp
class {FeatureName}_test : public beast::unit_test::suite
{
public:
void testEnable(FeatureBitset features)
{
testcase("enabled");
// Test with feature DISABLED
{
auto const amendNoFeature = features - feature{Name};
Env env{*this, amendNoFeature};
env(transaction, ter(temDISABLED));
}
// Test with feature ENABLED
{
Env env{*this, features};
env(transaction, ter(tesSUCCESS));
// Validate new functionality works
}
}
void testPreflight(FeatureBitset features)
{
testcase("preflight");
// Test malformed transaction validation
}
void testPreclaim(FeatureBitset features)
{
testcase("preclaim");
// Test signature and claim phase validation
}
void testWithFeats(FeatureBitset features)
{
testEnable(features);
testPreflight(features);
testPreclaim(features);
// Add feature-specific tests
}
void run() override
{
using namespace test::jtx;
auto const all = supported_amendments();
testWithFeats(all);
}
};
```
#### 6. Test Coverage Requirements
- [ ] Test amendment DISABLED state (returns `temDISABLED`)
- [ ] Test amendment ENABLED state (returns `tesSUCCESS`)
- [ ] Test malformed transactions
- [ ] Test signature validation
- [ ] Test edge cases specific to feature
- [ ] Test amendment transition behavior
#### 7. Documentation
- [ ] Create specification document (XLS_{NAME}.md)
- [ ] Document new transaction types, ledger entries, or capabilities
- [ ] Create test plan document
- [ ] Document expected behavior when enabled/disabled
---
## For FIX/EXTENSION Amendments
### Checklist:
#### 1. Fix Definition in features.macro
**ONLY FILE TO EDIT:** `include/xrpl/protocol/detail/features.macro`
- [ ] Add to TOP of features.macro (reverse chronological order):
```
XRPL_FIX(YourFixName, Supported::no, VoteBehavior::DefaultNo)
```
- [ ] This creates the variable `fixYourFixName` automatically
- [ ] Follow naming convention: Use the fix name WITHOUT the "fix" prefix (it's added automatically)
- [ ] Examples: `TokenEscrowV1``fixTokenEscrowV1`, `DirectoryLimit``fixDirectoryLimit`
- [ ] Start with `Supported::no` during development, change to `Supported::yes` when ready
#### 2. Backward Compatibility Implementation
**Critical**: Use enable() with if/else to preserve existing functionality
```cpp
// Check if fix is enabled
bool const fix{Name} = env.current()->rules().enabled(fix{Name});
// Conditional logic based on amendment state
if (fix{Name})
{
// NEW behavior with fix applied
// This is the corrected/improved logic
}
else
{
// OLD behavior (legacy path)
// Preserve original functionality for backward compatibility
}
```
**Alternative pattern with ternary operator:**
```cpp
auto& viewToUse = sb.rules().enabled(fix{Name}) ? sb : legacyView;
```
#### 3. Multiple Fix Versions Pattern
For iterative fixes, use version checking:
```cpp
bool const fixV1 = rv.rules().enabled(fixXahauV1);
bool const fixV2 = rv.rules().enabled(fixXahauV2);
switch (transactionType)
{
case TYPE_1:
if (fixV1) {
// Behavior with V1 fix
} else {
// Legacy behavior
}
break;
case TYPE_2:
if (fixV2) {
// Behavior with V2 fix
} else if (fixV1) {
// Behavior with only V1
} else {
// Legacy behavior
}
break;
}
```
#### 4. Test Both Paths
Always test BOTH enabled and disabled states:
```cpp
void testFix(FeatureBitset features)
{
testcase("fix behavior");
for (bool withFix : {false, true})
{
auto const amend = withFix ? features : features - fix{Name};
Env env{*this, amend};
// Setup test scenario
env.fund(XRP(1000), alice);
env.close();
if (!withFix)
{
// Test OLD behavior (before fix)
env(operation, ter(expectedErrorWithoutFix));
// Verify old behavior is preserved
}
else
{
// Test NEW behavior (after fix)
env(operation, ter(expectedErrorWithFix));
// Verify fix works correctly
}
}
}
```
#### 5. Security Fix Pattern
For security-critical fixes (like fixBatchInnerSigs):
```cpp
// Test vulnerability exists WITHOUT fix
{
auto const amendNoFix = features - fix{Name};
Env env{*this, amendNoFix};
// Demonstrate vulnerability
// Expected: Validity::Valid (WRONG - vulnerable!)
BEAST_EXPECT(result == Validity::Valid);
}
// Test vulnerability is FIXED WITH amendment
{
Env env{*this, features};
// Demonstrate fix
// Expected: Validity::SigBad (CORRECT - protected!)
BEAST_EXPECT(result == Validity::SigBad);
}
```
#### 6. Test Coverage Requirements
- [ ] Test fix DISABLED (legacy behavior preserved)
- [ ] Test fix ENABLED (new behavior applied)
- [ ] Test amendment transition
- [ ] For security fixes: demonstrate vulnerability without fix
- [ ] For security fixes: demonstrate protection with fix
- [ ] Test edge cases that triggered the fix
- [ ] Test combinations with other amendments
#### 7. Documentation
- [ ] Document what was broken/suboptimal
- [ ] Document the fix applied
- [ ] Document backward compatibility behavior
- [ ] Create test summary showing both paths
---
## Best Practices for All Amendments
### 1. Naming Conventions
- New features: `feature{DescriptiveName}` (e.g., `featureBatch`, `featureHooks`)
- Fixes: `fix{IssueDescription}` (e.g., `fixBatchInnerSigs`, `fixNSDelete`)
- Use CamelCase without underscores
### 2. Feature Flag Checking
```cpp
// At the point where behavior diverges:
bool const amendmentEnabled = env.current()->rules().enabled(feature{Name});
// Or in view/rules context:
if (!rv.rules().enabled(feature{Name}))
return {}; // or legacy behavior
```
### 3. Error Codes
- New features when disabled: `temDISABLED`
- Fixes may return different validation errors based on state
- Document all error code changes
### 4. Test Structure Template
```cpp
class Amendment_test : public beast::unit_test::suite
{
public:
// Core tests
void testEnable(FeatureBitset features); // Enable/disable states
void testPreflight(FeatureBitset features); // Validation
void testPreclaim(FeatureBitset features); // Claim phase
// Feature-specific tests
void test{SpecificScenario1}(FeatureBitset features);
void test{SpecificScenario2}(FeatureBitset features);
// Master orchestrator
void testWithFeats(FeatureBitset features)
{
testEnable(features);
testPreflight(features);
testPreclaim(features);
test{SpecificScenario1}(features);
test{SpecificScenario2}(features);
}
void run() override
{
using namespace test::jtx;
auto const all = supported_amendments();
testWithFeats(all);
}
};
BEAST_DEFINE_TESTSUITE(Amendment, app, ripple);
```
### 5. Documentation Files
Create these files:
- **Specification**: `XLS_{FEATURE_NAME}.md` - Technical specification
- **Test Plan**: `{FEATURE}_COMPREHENSIVE_TEST_PLAN.md` - Test strategy
- **Test Summary**: `{FEATURE}_TEST_IMPLEMENTATION_SUMMARY.md` - Test results
- **Review Findings**: `{FEATURE}_REVIEW_FINDINGS.md` (if applicable)
### 6. Amendment Transition Testing
Test the moment an amendment activates:
```cpp
void testAmendmentTransition(FeatureBitset features)
{
testcase("amendment transition");
// Start with amendment disabled
auto const amendNoFeature = features - feature{Name};
Env env{*this, amendNoFeature};
// Perform operations in disabled state
env(operation1, ter(temDISABLED));
// Enable amendment mid-test (if testing mechanism supports it)
// Verify state transitions correctly
// Perform operations in enabled state
env(operation2, ter(tesSUCCESS));
}
```
### 7. Cache Behavior
If amendment affects caching (like fixBatchInnerSigs):
- [ ] Test cache behavior without fix
- [ ] Test cache behavior with fix
- [ ] Document cache invalidation requirements
### 8. Multi-Amendment Combinations
Test interactions with other amendments:
```cpp
void testMultipleAmendments(FeatureBitset features)
{
// Test all combinations
for (bool withFeature1 : {false, true})
for (bool withFeature2 : {false, true})
{
auto amend = features;
if (!withFeature1) amend -= feature1;
if (!withFeature2) amend -= feature2;
Env env{*this, amend};
// Test interaction behavior
}
}
```
### 9. Performance Considerations
- [ ] Minimize runtime checks (cache `rules().enabled()` result if used multiple times)
- [ ] Avoid nested feature checks where possible
- [ ] Document performance impact
### 10. Code Review Checklist
- [ ] Both enabled/disabled paths are tested
- [ ] Backward compatibility is preserved (for fixes)
- [ ] Error codes are appropriate
- [ ] Documentation is complete
- [ ] Security implications are considered
- [ ] Cache behavior is correct
- [ ] Edge cases are covered
---
## Common Patterns Reference
### Pattern: New Transaction Type
```cpp
// In transactor code:
TER doApply() override
{
if (!ctx_.view().rules().enabled(feature{Name}))
return temDISABLED;
// New transaction logic here
return tesSUCCESS;
}
```
### Pattern: New Ledger Entry Type
```cpp
// In ledger entry creation:
if (!view.rules().enabled(feature{Name}))
return temDISABLED;
auto const sle = std::make_shared<SLE>(ltNEW_TYPE, keylet);
view.insert(sle);
```
### Pattern: Behavioral Fix
```cpp
// At decision point:
bool const useFix = view.rules().enabled(fix{Name});
if (useFix)
{
// Corrected behavior
return performCorrectValidation();
}
else
{
// Legacy behavior (preserved for compatibility)
return performLegacyValidation();
}
```
### Pattern: View Selection
```cpp
// Select which view to use based on amendment:
auto& applyView = sb.rules().enabled(feature{Name}) ? newView : legacyView;
```
---
## Example Workflows
### Workflow 1: Creating a New Feature Amendment
1. User requests: "Add a new ClaimReward transaction type"
2. Skill asks: "What should the amendment be called? (e.g., BalanceRewards - without 'feature' prefix)"
3. Add to features.macro:
```
XRPL_FEATURE(BalanceRewards, Supported::no, VoteBehavior::DefaultNo)
```
4. Implement transaction with `temDISABLED` gate using `featureBalanceRewards`
5. Create test suite with testEnable, testPreflight, testPreclaim
6. Run tests with amendment enabled and disabled
7. When ready, update to `Supported::yes` in features.macro
8. Create specification document
9. Review checklist
### Workflow 2: Creating a Fix Amendment
1. User requests: "Fix the signature validation bug in batch transactions"
2. Skill asks: "What should the fix be called? (e.g., BatchInnerSigs - without 'fix' prefix)"
3. Add to features.macro:
```
XRPL_FIX(BatchInnerSigs, Supported::no, VoteBehavior::DefaultNo)
```
4. Implement fix with if/else using `fixBatchInnerSigs` to preserve old behavior
5. Create test demonstrating vulnerability without fix
6. Create test showing fix works when enabled
7. When ready, update to `Supported::yes` in features.macro
8. Document both code paths
9. Review checklist
---
## Quick Reference: File Locations
- **Amendment definitions (ONLY place to add)**: `include/xrpl/protocol/detail/features.macro`
- **Feature.h (auto-generated, DO NOT EDIT)**: `include/xrpl/protocol/Feature.h`
- **Feature.cpp (auto-generated, DO NOT EDIT)**: `src/libxrpl/protocol/Feature.cpp`
- **Test files**: `src/test/app/` or `src/test/protocol/`
- **Specifications**: Project root (e.g., `XLS_SMART_CONTRACTS.md`)
- **Test plans**: Project root (e.g., `BATCH_COMPREHENSIVE_TEST_PLAN.md`)
## How the Macro System Works
The amendment system uses C preprocessor macros:
1. **features.macro** - Single source of truth (ONLY file you edit):
```
XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX(TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo)
```
2. **Feature.h** - Auto-generated declarations from macro:
```cpp
extern uint256 const featureBatch;
extern uint256 const fixTokenEscrowV1;
```
3. **Feature.cpp** - Auto-generated registrations from macro:
```cpp
uint256 const featureBatch = registerFeature("Batch", ...);
uint256 const fixTokenEscrowV1 = registerFeature("fixTokenEscrowV1", ...);
```
**DO NOT** modify Feature.h or Feature.cpp directly - they process features.macro automatically.
---
## When to Use This Skill
Invoke this skill when:
- Creating a new XRPL amendment
- Adding a new transaction type or ledger entry
- Fixing existing XRPL functionality
- Need guidance on amendment best practices
- Setting up amendment tests
- Reviewing amendment implementation
The skill will guide you through the appropriate workflow based on amendment type.

View File

@@ -1,99 +0,0 @@
# 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

@@ -1,79 +0,0 @@
# 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

@@ -1,62 +0,0 @@
# 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

@@ -1,33 +0,0 @@
# 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

@@ -1,29 +0,0 @@
# 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

@@ -1,41 +0,0 @@
# 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

@@ -1,46 +0,0 @@
# 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

@@ -1,47 +0,0 @@
# 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

@@ -1,63 +0,0 @@
# 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

@@ -1,61 +0,0 @@
# 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

@@ -1,32 +0,0 @@
# 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

@@ -1,51 +0,0 @@
# 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

@@ -1,68 +0,0 @@
# 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

@@ -1,84 +0,0 @@
# 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

@@ -1,58 +0,0 @@
# 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

@@ -1,24 +0,0 @@
# 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

@@ -1,68 +0,0 @@
# 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

@@ -1,66 +0,0 @@
# 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

@@ -1,35 +0,0 @@
# 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

@@ -1,123 +0,0 @@
# 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

@@ -1,60 +0,0 @@
# 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

@@ -1,64 +0,0 @@
# 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

@@ -1,68 +0,0 @@
# 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

@@ -1,83 +0,0 @@
# 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

@@ -1,137 +0,0 @@
# 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

@@ -1,72 +0,0 @@
# 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

@@ -1,164 +0,0 @@
# 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

@@ -1,68 +0,0 @@
# 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

@@ -1,44 +0,0 @@
# 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

@@ -1,43 +0,0 @@
# 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

@@ -1,69 +0,0 @@
# 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

@@ -1,53 +0,0 @@
# 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

@@ -1,76 +0,0 @@
# 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

@@ -1,56 +0,0 @@
# 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

@@ -1,36 +0,0 @@
# 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

@@ -1,61 +0,0 @@
# 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

@@ -1,228 +0,0 @@
# Merge Conflict Resolution Guide
## Description
Use when resolving merge conflicts after merging `develop` into a feature branch. Covers the key files that commonly conflict, field number allocation, namespace conventions, and the correct resolution strategy for each file type.
## General Principles
### Namespace
- All code uses `namespace xrpl { }` (not `ripple`). If a conflict shows `namespace ripple`, take the `xrpl` version.
- Qualified references: `xrpl::sign(...)`, `xrpl::sha256_hasher`, etc. Never `ripple::`.
### Header Guards
- Always `#pragma once`. Never `#ifndef` include guards. If a conflict shows old-style guards, take the `#pragma once` version.
### Copyright Headers
- The `develop` branch has removed copyright/license comment blocks from source files. If a conflict is just about the copyright header, take `develop`'s version (no header).
### File Moves
- Many files have been moved from `src/xrpld/` to `src/libxrpl/` or from `src/xrpld/` headers to `include/xrpl/`. If git shows a file as "deleted in develop" but it exists at a new path, delete the old-path file (`git rm`) and keep the new-path version.
- Common moves:
- `src/xrpld/app/tx/detail/*.h``include/xrpl/tx/transactors/*.h`
- `src/xrpld/app/tx/detail/*.cpp``src/libxrpl/tx/*.cpp` or `src/libxrpl/tx/transactors/*.cpp`
- `src/xrpld/app/tx/detail/InvariantCheck.cpp``src/libxrpl/tx/invariants/InvariantCheck.cpp`
### Transactor Migration
When merging transactors from `src/xrpld/app/tx/detail/` into `develop`, they must be fully migrated to the new libxrpl structure:
**File locations:**
- Header: `src/xrpld/app/tx/detail/Foo.h``include/xrpl/tx/transactors/Foo.h`
- Source: `src/xrpld/app/tx/detail/Foo.cpp``src/libxrpl/tx/transactors/Foo.cpp`
- Delete the old `.cpp` (both `src/xrpld/` and `src/libxrpl/` are GLOB_RECURSE discovered — duplicates cause linker errors)
- Optionally leave a forwarding header at the old `.h` location: `#include <xrpl/tx/transactors/Foo.h>`
**Header changes:**
- `#pragma once` (not `#ifndef` guards)
- `namespace xrpl` (not `ripple`)
- `#include <xrpl/tx/Transactor.h>` (not `<xrpld/app/tx/detail/Transactor.h>`)
**Source changes:**
- `namespace xrpl` (not `ripple`)
- `#include <xrpl/tx/transactors/Foo.h>` (not `<xrpld/app/tx/detail/Foo.h>`)
- `#include <xrpl/ledger/ApplyView.h>` (not `<xrpld/ledger/ApplyView.h>`)
- `#include <xrpl/ledger/View.h>` for `describeOwnerDir`
**API changes in the new Transactor:**
- `preflight1()` and `preflight2()` are **private** — transactor `preflight()` must NOT call them. The framework calls them automatically.
- Flag checking (`tfUniversalMask`) is handled by the framework via `getFlagsMask()`. Override `getFlagsMask()` only if custom flag handling is needed; otherwise the default handles `tfUniversalMask`.
- A simple `preflight()` that only did flag checks + preflight1/preflight2 should just `return tesSUCCESS;`
- `ctx_.app.journal(...)``ctx_.registry.journal(...)`
- `ctx_.app` does not exist in the new `ApplyContext`; use `ctx_.registry` for service access
**transactions.macro entry:**
Every transactor must have a `#if TRANSACTION_INCLUDE` block:
```cpp
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/Foo.h>
#endif
TRANSACTION(ttFOO, <number>, Foo, ...)
```
### Include Paths
- `develop` uses the new macro-based transactor include system via `transactions.macro` with `TRANSACTION_INCLUDE`. Old-style explicit `#include <xrpld/app/tx/detail/*.h>` lists should be replaced with the macro approach.
## File-Specific Resolution Rules
### `include/xrpl/protocol/detail/features.macro`
New feature amendments go **at the top** of the active list (below the macro guard checks and `// clang-format off`), in reverse chronological order.
```
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.
XRPL_FEATURE(MyNewFeature, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (ExistingFix, Supported::yes, VoteBehavior::DefaultNo)
...
```
Resolution: Keep both sides' new amendments. Place your feature branch's new amendments at the very top.
### `include/xrpl/protocol/detail/sfields.macro`
Fields are grouped by type (UINT32, UINT64, UINT128, etc.) with common and uncommon sections. Each field has a unique **type + field number** pair.
**Resolution strategy:**
1. Keep both sides' new fields.
2. Check for field number collisions within each type. Use the next available number for your feature's fields.
3. Common fields come first, uncommon fields after (there's a comment separator).
To find the next available field number for a type:
```bash
grep "TYPED_SFIELD.*UINT32" include/xrpl/protocol/detail/sfields.macro | sed 's/.*UINT32, *//;s/).*//' | sort -n
```
Similarly for OBJECT and ARRAY types (using `UNTYPED_SFIELD`):
```bash
grep "UNTYPED_SFIELD.*OBJECT" include/xrpl/protocol/detail/sfields.macro | sed 's/.*OBJECT, *//;s/).*//' | sort -n
grep "UNTYPED_SFIELD.*ARRAY" include/xrpl/protocol/detail/sfields.macro | sed 's/.*ARRAY, *//;s/).*//' | sort -n
```
### `include/xrpl/protocol/detail/transactions.macro`
Transaction types have a unique **transaction type number**. New feature transactions go **at the bottom** of the active transaction list (before the system transactions starting at 100+).
**Resolution strategy:**
1. Keep all of `develop`'s transactions.
2. Add your feature's transactions at the bottom with the next available number.
3. Use the new 7-argument `TRANSACTION` macro format:
```cpp
/** Description of the transaction */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/MyTransactor.h>
#endif
TRANSACTION(ttMY_TX, <next_number>, MyTx,
Delegation::delegable,
featureMyFeature,
noPriv, ({
{sfSomeField, soeREQUIRED},
}))
```
To find the next available transaction number:
```bash
grep "^TRANSACTION(" include/xrpl/protocol/detail/transactions.macro | sed 's/.*,\s*\([0-9]*\),.*/\1/' | sort -n
```
Note: Transaction numbers 100+ are reserved for system transactions (amendments, fees, UNL).
### `include/xrpl/protocol/detail/ledger_entries.macro`
Ledger entry types have a unique **ledger type number** (hex). New entries go **at the bottom** of the active list.
**Resolution strategy:**
1. Keep all of `develop`'s entries.
2. Add your feature's entries at the bottom with the next available hex number.
3. Check for collisions:
```bash
grep "^LEDGER_ENTRY(" include/xrpl/protocol/detail/ledger_entries.macro | grep -o '0x[0-9a-fA-F]*' | sort
```
### `src/libxrpl/protocol/Indexes.cpp`
The `LedgerNameSpace` enum assigns a unique single character to each ledger entry type for index hashing.
**Resolution strategy:**
1. Keep both sides' entries.
2. Check for character collisions. Each entry needs a unique char.
3. Find used characters:
```bash
grep -E "^\s+[A-Z_]+ = " src/libxrpl/protocol/Indexes.cpp | sed "s/.*= '//;s/'.*//" | sort | tr -d '\n'
```
Also check the deprecated chars (reserved, cannot reuse):
```bash
grep "deprecated" src/libxrpl/protocol/Indexes.cpp | sed "s/.*= '//;s/'.*//"
```
### `src/libxrpl/protocol/InnerObjectFormats.cpp`
Inner object formats define the fields allowed inside array elements (e.g., `sfSigners`, `sfPasskeys`).
**Resolution:** Keep both sides' `add(...)` calls. No numbering conflicts here — just ensure no duplicate registrations.
### `src/libxrpl/protocol/STTx.cpp`
The `singleSignHelper` function was refactored in `develop`:
- Parameter name: `sigObject` (not `signer`)
- Signature retrieval: `sigObject.getFieldVL(sfTxnSignature)` (not `getSignature(signer)`)
- No `fullyCanonical` parameter — canonical sig checking was simplified
**Resolution:** Take `develop`'s function signatures and patterns. Adapt any feature-specific logic to match.
### `src/libxrpl/protocol/SecretKey.cpp`
**Resolution:** Use `namespace xrpl`. Keep any additional `#include` directives your feature needs (e.g., OpenSSL headers for new key types).
### `src/libxrpl/tx/Transactor.cpp`
The `checkSign` / `checkSingleSign` / `checkMultiSign` functions were refactored in `develop`:
- `checkSingleSign` no longer takes a `Rules` parameter
- `checkSign` has a new overload taking `PreclaimContext`
- `checkBatchSign` uses the simplified `checkSingleSign` call
**Resolution:** Take `develop`'s function signatures. Add any new authentication checks (e.g., passkey verification) into `checkSingleSign` before the final `return tefBAD_AUTH`, using `view.read(...)` to check ledger state.
### `src/libxrpl/tx/applySteps.cpp`
**Resolution:** Always take `develop`'s macro-based include approach:
```cpp
#include <xrpl/tx/applySteps.h>
#pragma push_macro("TRANSACTION")
#undef TRANSACTION
#define TRANSACTION(...)
#define TRANSACTION_INCLUDE 1
#include <xrpl/protocol/detail/transactions.macro>
#undef TRANSACTION
#pragma pop_macro("TRANSACTION")
```
Never use the old explicit `#include <xrpld/app/tx/detail/*.h>` list.
### `src/test/jtx/impl/utility.cpp`
The `sign` function was refactored in `develop`:
- Takes `sigObject` parameter: `sign(Json::Value& jv, Account const& account, Json::Value& sigObject)`
- Has an overload: `sign(Json::Value& jv, Account const& account)` that calls `sign(jv, account, jv)`
- Uses `xrpl::sign(...)` not `ripple::sign(...)`
**Resolution:** Take `develop`'s function signatures. Adapt feature-specific signing logic to the new pattern.
## Conflict Resolution Checklist
1. List all conflicted files: `git diff --name-only --diff-filter=U`
2. Check which have actual conflict markers vs just unmerged: `grep -l "<<<<<<< HEAD" <file>`
3. For files without markers: stage them or `git rm` if they were moved
4. For each file with markers:
- Take `develop`'s structural changes (namespace, function signatures, macro formats)
- Preserve your feature's additions (new fields, entries, transactions, logic)
- Resolve any numbering collisions by incrementing to the next available number
5. Stage resolved files: `git add <file>`
6. Verify no remaining markers: `grep -r "<<<<<<< " --include="*.cpp" --include="*.h" --include="*.macro"`
7. Verify no remaining unmerged: `git diff --name-only --diff-filter=U`

View File

@@ -1,57 +0,0 @@
# 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

@@ -1,47 +0,0 @@
# 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

@@ -1,67 +0,0 @@
# 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

@@ -1,18 +0,0 @@
# 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

@@ -1,54 +0,0 @@
# 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

@@ -1,75 +0,0 @@
# 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

@@ -1,18 +0,0 @@
# 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

@@ -1,53 +0,0 @@
# 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

@@ -1,18 +0,0 @@
# 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

@@ -1,39 +0,0 @@
# 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

@@ -1,31 +0,0 @@
# 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

@@ -1,11 +0,0 @@
# 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

@@ -1,18 +0,0 @@
# 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

@@ -1,34 +0,0 @@
# 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

@@ -1,11 +0,0 @@
# 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

@@ -1,59 +0,0 @@
# 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

@@ -1,55 +0,0 @@
# 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

@@ -1,11 +0,0 @@
# 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

@@ -1,74 +0,0 @@
# 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

@@ -1,27 +0,0 @@
# 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

@@ -1,58 +0,0 @@
# 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

@@ -1,21 +0,0 @@
# 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

@@ -1,31 +0,0 @@
# 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

@@ -1,11 +0,0 @@
# 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

@@ -1,91 +0,0 @@
# 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

@@ -1,11 +0,0 @@
# 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

@@ -1,74 +0,0 @@
# 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

@@ -1,32 +0,0 @@
# 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

View File

@@ -1,247 +0,0 @@
_help_parse: Options affecting listfile parsing
parse:
_help_additional_commands:
- Specify structure for custom cmake functions
additional_commands:
target_protobuf_sources:
pargs:
- target
- prefix
kwargs:
PROTOS: "*"
LANGUAGE: cpp
IMPORT_DIRS: "*"
GENERATE_EXTENSIONS: "*"
PLUGIN: "*"
_help_override_spec:
- Override configurations per-command where available
override_spec: {}
_help_vartags:
- Specify variable tags.
vartags: []
_help_proptags:
- Specify property tags.
proptags: []
_help_format: Options affecting formatting.
format:
_help_disable:
- Disable formatting entirely, making cmake-format a no-op
disable: false
_help_line_width:
- How wide to allow formatted cmake files
line_width: 120
_help_tab_size:
- How many spaces to tab for indent
tab_size: 4
_help_use_tabchars:
- If true, lines are indented using tab characters (utf-8
- 0x09) instead of <tab_size> space characters (utf-8 0x20).
- In cases where the layout would require a fractional tab
- character, the behavior of the fractional indentation is
- governed by <fractional_tab_policy>
use_tabchars: false
_help_fractional_tab_policy:
- If <use_tabchars> is True, then the value of this variable
- indicates how fractional indentions are handled during
- whitespace replacement. If set to 'use-space', fractional
- indentation is left as spaces (utf-8 0x20). If set to
- "`round-up` fractional indentation is replaced with a single"
- tab character (utf-8 0x09) effectively shifting the column
- to the next tabstop
fractional_tab_policy: use-space
_help_max_subgroups_hwrap:
- If an argument group contains more than this many sub-groups
- (parg or kwarg groups) then force it to a vertical layout.
max_subgroups_hwrap: 4
_help_max_pargs_hwrap:
- If a positional argument group contains more than this many
- arguments, then force it to a vertical layout.
max_pargs_hwrap: 5
_help_max_rows_cmdline:
- If a cmdline positional group consumes more than this many
- lines without nesting, then invalidate the layout (and nest)
max_rows_cmdline: 2
_help_separate_ctrl_name_with_space:
- If true, separate flow control names from their parentheses
- with a space
separate_ctrl_name_with_space: true
_help_separate_fn_name_with_space:
- If true, separate function names from parentheses with a
- space
separate_fn_name_with_space: false
_help_dangle_parens:
- If a statement is wrapped to more than one line, than dangle
- the closing parenthesis on its own line.
dangle_parens: false
_help_dangle_align:
- If the trailing parenthesis must be 'dangled' on its on
- "line, then align it to this reference: `prefix`: the start"
- "of the statement, `prefix-indent`: the start of the"
- "statement, plus one indentation level, `child`: align to"
- the column of the arguments
dangle_align: prefix
_help_min_prefix_chars:
- If the statement spelling length (including space and
- parenthesis) is smaller than this amount, then force reject
- nested layouts.
min_prefix_chars: 18
_help_max_prefix_chars:
- If the statement spelling length (including space and
- parenthesis) is larger than the tab width by more than this
- amount, then force reject un-nested layouts.
max_prefix_chars: 10
_help_max_lines_hwrap:
- If a candidate layout is wrapped horizontally but it exceeds
- this many lines, then reject the layout.
max_lines_hwrap: 2
_help_line_ending:
- What style line endings to use in the output.
line_ending: unix
_help_command_case:
- Format command names consistently as 'lower' or 'upper' case
command_case: canonical
_help_keyword_case:
- Format keywords consistently as 'lower' or 'upper' case
keyword_case: unchanged
_help_always_wrap:
- A list of command names which should always be wrapped
always_wrap: []
_help_enable_sort:
- If true, the argument lists which are known to be sortable
- will be sorted lexicographicall
enable_sort: true
_help_autosort:
- If true, the parsers may infer whether or not an argument
- list is sortable (without annotation).
autosort: true
_help_require_valid_layout:
- By default, if cmake-format cannot successfully fit
- everything into the desired linewidth it will apply the
- last, most aggressive attempt that it made. If this flag is
- True, however, cmake-format will print error, exit with non-
- zero status code, and write-out nothing
require_valid_layout: false
_help_layout_passes:
- A dictionary mapping layout nodes to a list of wrap
- decisions. See the documentation for more information.
layout_passes: {}
_help_markup: Options affecting comment reflow and formatting.
markup:
_help_bullet_char:
- What character to use for bulleted lists
bullet_char: "-"
_help_enum_char:
- What character to use as punctuation after numerals in an
- enumerated list
enum_char: .
_help_first_comment_is_literal:
- If comment markup is enabled, don't reflow the first comment
- block in each listfile. Use this to preserve formatting of
- your copyright/license statements.
first_comment_is_literal: false
_help_literal_comment_pattern:
- If comment markup is enabled, don't reflow any comment block
- which matches this (regex) pattern. Default is `None`
- (disabled).
literal_comment_pattern: null
_help_fence_pattern:
- Regular expression to match preformat fences in comments
- default= ``r'^\s*([`~]{3}[`~]*)(.*)$'``
fence_pattern: ^\s*([`~]{3}[`~]*)(.*)$
_help_ruler_pattern:
- Regular expression to match rulers in comments default=
- '``r''^\s*[^\w\s]{3}.*[^\w\s]{3}$''``'
ruler_pattern: ^\s*[^\w\s]{3}.*[^\w\s]{3}$
_help_explicit_trailing_pattern:
- If a comment line matches starts with this pattern then it
- is explicitly a trailing comment for the preceding
- argument. Default is '#<'
explicit_trailing_pattern: "#<"
_help_hashruler_min_length:
- If a comment line starts with at least this many consecutive
- hash characters, then don't lstrip() them off. This allows
- for lazy hash rulers where the first hash char is not
- separated by space
hashruler_min_length: 10
_help_canonicalize_hashrulers:
- If true, then insert a space between the first hash char and
- remaining hash chars in a hash ruler, and normalize its
- length to fill the column
canonicalize_hashrulers: true
_help_enable_markup:
- enable comment markup parsing and reflow
enable_markup: false
_help_lint: Options affecting the linter
lint:
_help_disabled_codes:
- a list of lint codes to disable
disabled_codes: []
_help_function_pattern:
- regular expression pattern describing valid function names
function_pattern: "[0-9a-z_]+"
_help_macro_pattern:
- regular expression pattern describing valid macro names
macro_pattern: "[0-9A-Z_]+"
_help_global_var_pattern:
- regular expression pattern describing valid names for
- variables with global (cache) scope
global_var_pattern: "[A-Z][0-9A-Z_]+"
_help_internal_var_pattern:
- regular expression pattern describing valid names for
- variables with global scope (but internal semantic)
internal_var_pattern: _[A-Z][0-9A-Z_]+
_help_local_var_pattern:
- regular expression pattern describing valid names for
- variables with local scope
local_var_pattern: "[a-z][a-z0-9_]+"
_help_private_var_pattern:
- regular expression pattern describing valid names for
- privatedirectory variables
private_var_pattern: _[0-9a-z_]+
_help_public_var_pattern:
- regular expression pattern describing valid names for public
- directory variables
public_var_pattern: "[A-Z][0-9A-Z_]+"
_help_argument_var_pattern:
- regular expression pattern describing valid names for
- function/macro arguments and loop variables.
argument_var_pattern: "[a-z][a-z0-9_]+"
_help_keyword_pattern:
- regular expression pattern describing valid names for
- keywords used in functions or macros
keyword_pattern: "[A-Z][0-9A-Z_]+"
_help_max_conditionals_custom_parser:
- In the heuristic for C0201, how many conditionals to match
- within a loop in before considering the loop a parser.
max_conditionals_custom_parser: 2
_help_min_statement_spacing:
- Require at least this many newlines between statements
min_statement_spacing: 1
_help_max_statement_spacing:
- Require no more than this many newlines between statements
max_statement_spacing: 2
max_returns: 6
max_branches: 12
max_arguments: 5
max_localvars: 15
max_statements: 50
_help_encode: Options affecting file encoding
encode:
_help_emit_byteorder_mark:
- If true, emit the unicode byte-order mark (BOM) at the start
- of the file
emit_byteorder_mark: false
_help_input_encoding:
- Specify the encoding of the input file. Defaults to utf-8
input_encoding: utf-8
_help_output_encoding:
- Specify the encoding of the output file. Defaults to utf-8.
- Note that cmake only claims to support utf-8 so be careful
- when using anything else
output_encoding: utf-8
_help_misc: Miscellaneous configurations options.
misc:
_help_per_command:
- A dictionary containing any per-command configuration
- overrides. Currently only `command_case` is supported.
per_command: {}

View File

@@ -33,6 +33,5 @@ slack_app: false
ignore:
- "src/test/"
- "src/tests/"
- "include/xrpl/beast/test/"
- "include/xrpl/beast/unit_test/"

View File

@@ -1,290 +0,0 @@
ignorePaths:
- build/**
- src/libxrpl/crypto
- src/test/** # Will be removed in the future
- CMakeUserPresets.json
- Doxyfile
- docs/**/*.puml
- cmake/**
- LICENSE.md
language: en
allowCompoundWords: true
ignoreRandomStrings: true
minWordLength: 5
dictionaries:
- cpp
- en_US
- en_GB
ignoreRegExpList:
- /[rs][1-9A-HJ-NP-Za-km-z]{25,34}/g # addresses and seeds
- /(XRPL|BEAST)_[A-Z_0-9]+_H_INCLUDED+/g # include guards
- /(XRPL|BEAST)_[A-Z_0-9]+_H+/g # include guards
- /::[a-z:_]+/g # things from other namespaces
- /lib[a-z]+/g # libraries
- /[0-9]{4}-[0-9]{2}-[0-9]{2}[,:][A-Za-zÀ-ÖØ-öø-ÿ.\s]+/g # copyright dates
- /[0-9]{4}[,:]?\s*[A-Za-zÀ-ÖØ-öø-ÿ.\s]+/g # copyright years
- /\[[A-Za-z0-9-]+\]\(https:\/\/github.com\/[A-Za-z0-9-]+\)/g # Github usernames
- /-[DWw][a-zA-Z0-9_-]+=/g # compile flags
- /[\['"`]-[DWw][a-zA-Z0-9_-]+['"`\]]/g # compile flags
suggestWords:
- xprl->xrpl
- xprld->xrpld
- unsynched->unsynced
- synched->synced
- synch->sync
words:
- abempty
- AMMID
- amt
- amts
- asnode
- asynchrony
- attestation
- authorises
- autobridge
- autobridged
- autobridging
- bimap
- bindir
- bookdir
- Bougalis
- Britto
- Btrfs
- canonicality
- checkme
- choco
- chrono
- citardauq
- clawback
- clawbacks
- coeffs
- coldwallet
- compr
- conanfile
- conanrun
- confs
- connectability
- coro
- coros
- cowid
- cryptocondition
- cryptoconditional
- cryptoconditions
- csprng
- ctest
- ctid
- currenttxhash
- daria
- dcmake
- dearmor
- deleteme
- demultiplexer
- deserializaton
- desync
- desynced
- determ
- distro
- doxyfile
- dxrpl
- endmacro
- exceptioned
- Falco
- finalizers
- firewalled
- fmtdur
- fsanitize
- funclets
- gcov
- gcovr
- ghead
- Gnutella
- gpgcheck
- gpgkey
- hotwallet
- hwrap
- ifndef
- inequation
- insuf
- insuff
- iou
- ious
- isrdc
- itype
- jemalloc
- jlog
- keylet
- keylets
- keyvadb
- kwarg
- kwargs
- ledgerentry
- ledgerhash
- ledgerindex
- leftw
- legleux
- levelization
- levelized
- libpb
- libxrpl
- llection
- LOCALGOOD
- logwstream
- lseq
- lsmf
- ltype
- mcmodel
- MEMORYSTATUSEX
- Merkle
- Metafuncton
- misprediction
- mptbalance
- mptflags
- mptid
- mptissuance
- mptissuanceid
- mptoken
- mptokenid
- mptokenissuance
- mptokens
- mpts
- multisig
- multisign
- multisigned
- Nakamoto
- nftid
- nftoffer
- nftoken
- nftokenid
- nftokenpages
- nftokens
- nftpage
- nikb
- nonxrp
- noripple
- nudb
- nullptr
- nunl
- Nyffenegger
- ostr
- pargs
- partitioner
- paychan
- paychans
- permdex
- perminute
- permissioned
- pointee
- preauth
- preauthorization
- preauthorize
- preauthorizes
- preclaim
- protobuf
- protos
- ptrs
- pyenv
- qalloc
- queuable
- Raphson
- replayer
- rerere
- retriable
- RIPD
- ripdtop
- rippleci
- rippled
- ripplerpc
- rippletest
- RLUSD
- rngfill
- rocksdb
- Rohrs
- roundings
- sahyadri
- Satoshi
- scons
- secp
- sendq
- seqit
- sf
- SFIELD
- shamap
- shamapitem
- sidechain
- SIGGOOD
- sle
- sles
- soci
- socidb
- sslws
- statsd
- STATSDCOLLECTOR
- stissue
- stnum
- stobj
- stobject
- stpath
- stpathset
- sttx
- stvar
- stvector
- stxchainattestations
- superpeer
- superpeers
- takergets
- takerpays
- ters
- TMEndpointv2
- trixie
- tx
- txid
- txids
- txjson
- txn
- txns
- txs
- UBSAN
- ubsan
- umant
- unacquired
- unambiguity
- unauthorizes
- unauthorizing
- unergonomic
- unfetched
- unflatten
- unfund
- unimpair
- unroutable
- unscalable
- unserviced
- unshareable
- unshares
- unsquelch
- unsquelched
- unsquelching
- unvalidated
- unveto
- unvetoed
- upvotes
- USDB
- variadics
- venv
- vfalco
- vinnie
- wextra
- wptr
- writeme
- wsrch
- wthread
- xbridge
- xchain
- ximinez
- EXPECT_STREQ
- XMACRO
- xrpkuwait
- xrpl
- xrpld
- xrplf
- xxhash
- xxhasher

View File

@@ -12,5 +12,3 @@ fe9a5365b8a52d4acc42eb27369247e6f238a4f9
9a93577314e6a8d4b4a8368cc9d2b15a5d8303e8
552377c76f55b403a1c876df873a23d780fcc81c
97f0747e103f13e26e45b731731059b32f7679ac
b13370ac0d207217354f1fc1c29aef87769fb8a1
896b8c3b54a22b0497cb0d1ce95e1095f9a227ce

5
.gitattributes vendored
View File

@@ -1,6 +1,9 @@
# Set default behaviour, in case users don't have core.autocrlf set.
#* text=auto
# cspell: disable
# These annoying files
rippled.1 binary
LICENSE binary
# Visual Studio
*.sln text eol=crlf

8
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,8 @@
# Allow anyone to review any change by default.
*
# Require the rpc-reviewers team to review changes to the rpc code.
include/xrpl/protocol/ @xrplf/rpc-reviewers
src/libxrpl/protocol/ @xrplf/rpc-reviewers
src/xrpld/rpc/ @xrplf/rpc-reviewers
src/xrpld/app/misc/ @xrplf/rpc-reviewers

View File

@@ -1,7 +1,7 @@
---
name: Bug Report
about: Create a report to help us improve xrpld
title: "[Title with short description] (Version: [xrpld version])"
about: Create a report to help us improve rippled
title: "[Title with short description] (Version: [rippled version])"
labels: ""
assignees: ""
---
@@ -27,7 +27,7 @@ assignees: ""
## Environment
<!--Please describe your environment setup (such as Ubuntu 18.04 with Boost 1.70).-->
<!-- If you are using a formal release, please use the version returned by './xrpld --version' as the version number-->
<!-- If you are using a formal release, please use the version returned by './rippled --version' as the version number-->
<!-- If you are working off of develop, please add the git hash via 'git rev-parse HEAD'-->
## Supporting Files

View File

@@ -1,48 +0,0 @@
name: Build Conan dependencies
description: "Install Conan dependencies, optionally forcing a rebuild of all dependencies."
# Note that actions do not support 'type' and all inputs are strings, see
# https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax#inputs.
inputs:
build_type:
description: 'The build type to use ("Debug", "Release").'
required: true
build_nproc:
description: "The number of processors to use for building."
required: true
force_build:
description: 'Force building of all dependencies ("true", "false").'
required: false
default: "false"
log_verbosity:
description: "The logging verbosity."
required: false
default: "verbose"
sanitizers:
description: "The sanitizers to enable."
required: false
default: ""
runs:
using: composite
steps:
- name: Install Conan dependencies
shell: bash
env:
BUILD_NPROC: ${{ inputs.build_nproc }}
BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }}
BUILD_TYPE: ${{ inputs.build_type }}
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
SANITIZERS: ${{ inputs.sanitizers }}
run: |
echo 'Installing dependencies.'
conan install \
--profile ci \
--build="${BUILD_OPTION}" \
--options:host='&:tests=True' \
--options:host='&:xrpld=True' \
--settings:all build_type="${BUILD_TYPE}" \
--conf:all tools.build:jobs=${BUILD_NPROC} \
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
.

34
.github/actions/build/action.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: build
inputs:
generator:
default: null
configuration:
required: true
cmake-args:
default: null
cmake-target:
default: all
# An implicit input is the environment variable `build_dir`.
runs:
using: composite
steps:
- name: configure
shell: bash
run: |
cd ${build_dir}
cmake \
${{ inputs.generator && format('-G "{0}"', inputs.generator) || '' }} \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \
-Dtests=TRUE \
-Dxrpld=TRUE \
${{ inputs.cmake-args }} \
..
- name: build
shell: bash
run: |
cmake \
--build ${build_dir} \
--config ${{ inputs.configuration }} \
--parallel ${NUM_PROCESSORS:-$(nproc)} \
--target ${{ inputs.cmake-target }}

38
.github/actions/dependencies/action.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: dependencies
inputs:
configuration:
required: true
# Implicit inputs are the environment variables `build_dir`, CONAN_REMOTE_URL,
# CONAN_REMOTE_USERNAME, and CONAN_REMOTE_PASSWORD. The latter two are only
# used to upload newly built dependencies to the Conan remote.
runs:
using: composite
steps:
- name: add Conan remote
if: ${{ env.CONAN_REMOTE_URL != '' }}
shell: bash
run: |
echo "Adding Conan remote 'xrplf' at ${{ env.CONAN_REMOTE_URL }}."
conan remote add --index 0 --force xrplf ${{ env.CONAN_REMOTE_URL }}
echo "Listing Conan remotes."
conan remote list
- name: install dependencies
shell: bash
run: |
mkdir -p ${{ env.build_dir }}
cd ${{ env.build_dir }}
conan install \
--output-folder . \
--build missing \
--options:host "&:tests=True" \
--options:host "&:xrpld=True" \
--settings:all build_type=${{ inputs.configuration }} \
..
- name: upload dependencies
if: ${{ env.CONAN_REMOTE_URL != '' && env.CONAN_REMOTE_USERNAME != '' && env.CONAN_REMOTE_PASSWORD != '' && github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }}
shell: bash
run: |
echo "Logging into Conan remote 'xrplf' at ${{ env.CONAN_REMOTE_URL }}."
conan remote login xrplf "${{ env.CONAN_REMOTE_USERNAME }}" --password "${{ env.CONAN_REMOTE_PASSWORD }}"
echo "Uploading dependencies."
conan upload '*' --confirm --check --remote xrplf

View File

@@ -1,44 +0,0 @@
name: Generate build version number
description: "Generate build version number."
outputs:
version:
description: "The generated build version number."
value: ${{ steps.version.outputs.version }}
runs:
using: composite
steps:
# When a tag is pushed, the version is used as-is.
- name: Generate version for tag event
if: ${{ github.event_name == 'tag' }}
shell: bash
env:
VERSION: ${{ github.ref_name }}
run: echo "VERSION=${VERSION}" >> "${GITHUB_ENV}"
# When a tag is not pushed, then the version (e.g. 1.2.3-b0) is extracted
# from the BuildInfo.cpp file and the shortened commit hash appended to it.
# We use a plus sign instead of a hyphen because Conan recipe versions do
# not support two hyphens.
- name: Generate version for non-tag event
if: ${{ github.event_name != 'tag' }}
shell: bash
run: |
echo 'Extracting version from BuildInfo.cpp.'
VERSION="$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')"
if [[ -z "${VERSION}" ]]; then
echo 'Unable to extract version from BuildInfo.cpp.'
exit 1
fi
echo 'Appending shortened commit hash to version.'
SHA='${{ github.sha }}'
VERSION="${VERSION}+${SHA:0:7}"
echo "VERSION=${VERSION}" >> "${GITHUB_ENV}"
- name: Output version
id: version
shell: bash
run: echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"

View File

@@ -1,43 +0,0 @@
name: Print build environment
description: "Print environment and some tooling versions"
runs:
using: composite
steps:
- name: Check configuration (Windows)
if: ${{ runner.os == 'Windows' }}
shell: bash
run: |
echo 'Checking environment variables.'
set
- name: Check configuration (Linux and macOS)
if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }}
shell: bash
run: |
echo 'Checking path.'
echo ${PATH} | tr ':' '\n'
echo 'Checking environment variables.'
env | sort
echo 'Checking compiler version.'
${{ runner.os == 'Linux' && '${CC}' || 'clang' }} --version
echo 'Checking Ninja version.'
ninja --version
echo 'Checking nproc version.'
nproc --version
- name: Check configuration (all)
shell: bash
run: |
echo 'Checking Ccache version.'
ccache --version
echo 'Checking CMake version.'
cmake --version
echo 'Checking Conan version.'
conan --version

View File

@@ -1,46 +0,0 @@
name: Setup Conan
description: "Set up Conan configuration, profile, and remote."
inputs:
remote_name:
description: "The name of the Conan remote to use."
required: false
default: xrplf
remote_url:
description: "The URL of the Conan endpoint to use."
required: false
default: https://conan.ripplex.io
runs:
using: composite
steps:
- name: Set up Conan configuration
shell: bash
run: |
echo 'Installing configuration.'
cat conan/global.conf ${{ runner.os == 'Linux' && '>>' || '>' }} $(conan config home)/global.conf
echo 'Conan configuration:'
conan config show '*'
- name: Set up Conan profile
shell: bash
run: |
echo 'Installing profile.'
conan config install conan/profiles/ -tf $(conan config home)/profiles/
echo 'Conan profile:'
conan profile show --profile ci
- name: Set up Conan remote
shell: bash
env:
REMOTE_NAME: ${{ inputs.remote_name }}
REMOTE_URL: ${{ inputs.remote_url }}
run: |
echo "Adding Conan remote '${REMOTE_NAME}' at '${REMOTE_URL}'."
conan remote add --index 0 --force "${REMOTE_NAME}" "${REMOTE_URL}"
echo 'Listing Conan remotes.'
conan remote list

View File

@@ -1,47 +0,0 @@
## Renaming ripple(d) to xrpl(d)
In the initial phases of development of the XRPL, the open source codebase was
called "rippled" and it remains with that name even today. Today, over 1000
nodes run the application, and code contributions have been submitted by
developers located around the world. The XRPL community is larger than ever.
In light of the decentralized and diversified nature of XRPL, we will rename any
references to `ripple` and `rippled` to `xrpl` and `xrpld`, when appropriate.
See [here](https://xls.xrpl.org/xls/XLS-0095-rename-rippled-to-xrpld.html) for
more information.
### Scripts
To facilitate this transition, there will be multiple scripts that developers
can run on their own PRs and forks to minimize conflicts. Each script should be
run from the repository root.
1. `.github/scripts/rename/definitions.sh`: This script will rename all
definitions, such as include guards, from `RIPPLE_XXX` and `RIPPLED_XXX` to
`XRPL_XXX`.
2. `.github/scripts/rename/copyright.sh`: This script will remove superfluous
copyright notices.
3. `.github/scripts/rename/cmake.sh`: This script will rename all CMake files
from `RippleXXX.cmake` or `RippledXXX.cmake` to `XrplXXX.cmake`, and any
references to `ripple` and `rippled` (with or without capital letters) to
`xrpl` and `xrpld`, respectively. The name of the binary will remain as-is,
and will only be renamed to `xrpld` by a later script.
4. `.github/scripts/rename/binary.sh`: This script will rename the binary from
`rippled` to `xrpld`, and reverses the symlink so that `rippled` points to
the `xrpld` binary.
5. `.github/scripts/rename/namespace.sh`: This script will rename the C++
namespaces from `ripple` to `xrpl`.
6. `.github/scripts/rename/config.sh`: This script will rename the config from
`rippled.cfg` to `xrpld.cfg`, and updating the code accordingly. The old
filename will still be accepted.
You can run all these scripts from the repository root as follows:
```shell
./.github/scripts/rename/definitions.sh .
./.github/scripts/rename/copyright.sh .
./.github/scripts/rename/cmake.sh .
./.github/scripts/rename/binary.sh .
./.github/scripts/rename/namespace.sh .
./.github/scripts/rename/config.sh .
```

View File

@@ -1,54 +0,0 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1
fi
SED_COMMAND=gsed
fi
# This script changes the binary name from `rippled` to `xrpld`, and reverses
# the symlink that currently points from `xrpld` to `rippled` so that it points
# from `rippled` to `xrpld` instead.
# Usage: .github/scripts/rename/binary.sh <repository directory>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <repository directory>"
exit 1
fi
DIRECTORY=$1
echo "Processing directory: ${DIRECTORY}"
if [ ! -d "${DIRECTORY}" ]; then
echo "Error: Directory '${DIRECTORY}' does not exist."
exit 1
fi
pushd ${DIRECTORY}
# Remove the binary name override added by the cmake.sh script.
${SED_COMMAND} -z -i -E 's@\s+# For the time being.+"rippled"\)@@' cmake/XrplCore.cmake
# Reverse the symlink.
${SED_COMMAND} -i -E 's@create_symbolic_link\(rippled@create_symbolic_link(xrpld@' cmake/XrplInstall.cmake
${SED_COMMAND} -i -E 's@/xrpld\$\{suffix\}@/rippled${suffix}@' cmake/XrplInstall.cmake
# Rename references to the binary.
${SED_COMMAND} -i -E 's@rippled@xrpld@g' BUILD.md
${SED_COMMAND} -i -E 's@rippled@xrpld@g' CONTRIBUTING.md
${SED_COMMAND} -i -E 's@rippled@xrpld@g' .github/ISSUE_TEMPLATE/bug_report.md
# Restore and/or fix certain renames. The pre-commit hook will update the
# formatting upon saving/committing.
${SED_COMMAND} -i -E 's@ripple/xrpld@XRPLF/rippled@g' BUILD.md
${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' BUILD.md
${SED_COMMAND} -i -E 's@xrpld \(`xrpld`\)@xrpld@g' BUILD.md
${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' CONTRIBUTING.md
popd
echo "Processing complete."

View File

@@ -1,92 +0,0 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -e
# On MacOS, ensure that GNU sed and head are installed and available as `gsed`
# and `ghead`, respectively.
SED_COMMAND=sed
HEAD_COMMAND=head
if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1
fi
SED_COMMAND=gsed
if ! command -v ghead &> /dev/null; then
echo "Error: ghead is not installed. Please install it using 'brew install coreutils'."
exit 1
fi
HEAD_COMMAND=ghead
fi
# This script renames CMake files from `RippleXXX.cmake` or `RippledXXX.cmake`
# to `XrplXXX.cmake`, and any references to `ripple` and `rippled` (with or
# without capital letters) to `xrpl` and `xrpld`, respectively. The name of the
# binary will remain as-is, and will only be renamed to `xrpld` in a different
# script, but the proto file will be renamed.
# Usage: .github/scripts/rename/cmake.sh <repository directory>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <repository directory>"
exit 1
fi
DIRECTORY=$1
echo "Processing directory: ${DIRECTORY}"
if [ ! -d "${DIRECTORY}" ]; then
echo "Error: Directory '${DIRECTORY}' does not exist."
exit 1
fi
pushd ${DIRECTORY}
# Rename the files.
find cmake -type f -name 'Rippled*.cmake' -exec bash -c 'mv "${1}" "${1/Rippled/Xrpl}"' - {} \;
find cmake -type f -name 'Ripple*.cmake' -exec bash -c 'mv "${1}" "${1/Ripple/Xrpl}"' - {} \;
if [ -e cmake/xrpl_add_test.cmake ]; then
mv cmake/xrpl_add_test.cmake cmake/XrplAddTest.cmake
fi
if [ -e include/xrpl/proto/ripple.proto ]; then
mv include/xrpl/proto/ripple.proto include/xrpl/proto/xrpl.proto
fi
# Rename inside the files.
find cmake -type f -name '*.cmake' | while read -r FILE; do
echo "Processing file: ${FILE}"
${SED_COMMAND} -i 's/Rippled/Xrpld/g' "${FILE}"
${SED_COMMAND} -i 's/Ripple/Xrpl/g' "${FILE}"
${SED_COMMAND} -i 's/rippled/xrpld/g' "${FILE}"
${SED_COMMAND} -i 's/ripple/xrpl/g' "${FILE}"
done
${SED_COMMAND} -i -E 's/Rippled?/Xrpl/g' CMakeLists.txt
${SED_COMMAND} -i 's/ripple/xrpl/g' CMakeLists.txt
${SED_COMMAND} -i 's/include(xrpl_add_test)/include(XrplAddTest)/' src/tests/libxrpl/CMakeLists.txt
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' include/xrpl/protocol/messages.h
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md
# Restore the name of the validator keys repository.
${SED_COMMAND} -i 's@xrpl/validator-keys-tool@ripple/validator-keys-tool@' cmake/XrplValidatorKeys.cmake
# Ensure the name of the binary and config remain 'rippled' for now.
${SED_COMMAND} -i -E 's/xrpld(-example)?\.cfg/rippled\1.cfg/g' cmake/XrplInstall.cmake
if grep -q '"xrpld"' cmake/XrplCore.cmake; then
# The script has been rerun, so just restore the name of the binary.
${SED_COMMAND} -i 's/"xrpld"/"rippled"/' cmake/XrplCore.cmake
elif ! grep -q '"rippled"' cmake/XrplCore.cmake; then
${HEAD_COMMAND} -n -1 cmake/XrplCore.cmake > cmake.tmp
echo ' # For the time being, we will keep the name of the binary as it was.' >> cmake.tmp
echo ' set_target_properties(xrpld PROPERTIES OUTPUT_NAME "rippled")' >> cmake.tmp
tail -1 cmake/XrplCore.cmake >> cmake.tmp
mv cmake.tmp cmake/XrplCore.cmake
fi
# Restore the symlink from 'xrpld' to 'rippled'.
${SED_COMMAND} -i -E 's@create_symbolic_link\(xrpld@create_symbolic_link(rippled@' cmake/XrplInstall.cmake
# Remove the symlink that previously pointed from 'ripple' to 'xrpl' but now is
# no longer needed.
${SED_COMMAND} -z -i -E 's@install\(CODE.+CMAKE_INSTALL_INCLUDEDIR}/xrpl\)\n"\)\n+@@' cmake/XrplInstall.cmake
popd
echo "Renaming complete."

View File

@@ -1,72 +0,0 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1
fi
SED_COMMAND=gsed
fi
# This script renames the config from `rippled.cfg` to `xrpld.cfg`, and updates
# the code accordingly. The old filename will still be accepted.
# Usage: .github/scripts/rename/config.sh <repository directory>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <repository directory>"
exit 1
fi
DIRECTORY=$1
echo "Processing directory: ${DIRECTORY}"
if [ ! -d "${DIRECTORY}" ]; then
echo "Error: Directory '${DIRECTORY}' does not exist."
exit 1
fi
pushd ${DIRECTORY}
# Add the xrpld.cfg to the .gitignore.
if ! grep -q 'xrpld.cfg' .gitignore; then
${SED_COMMAND} -i '/rippled.cfg/a\
/xrpld.cfg' .gitignore
fi
# Rename the files.
if [ -e rippled.cfg ]; then
mv rippled.cfg xrpld.cfg
fi
if [ -e cfg/rippled-example.cfg ]; then
mv cfg/rippled-example.cfg cfg/xrpld-example.cfg
fi
# Rename inside the files.
DIRECTORIES=("cfg" "cmake" "include" "src")
for DIRECTORY in "${DIRECTORIES[@]}"; do
echo "Processing directory: ${DIRECTORY}"
find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" -o -name "*.cmake" -o -name "*.txt" -o -name "*.cfg" -o -name "*.md" \) | while read -r FILE; do
echo "Processing file: ${FILE}"
${SED_COMMAND} -i -E 's/rippled(-example)?[ .]cfg/xrpld\1.cfg/g' "${FILE}"
done
done
${SED_COMMAND} -i 's/rippled/xrpld/g' cfg/xrpld-example.cfg
${SED_COMMAND} -i 's/rippled/xrpld/g' src/test/core/Config_test.cpp
${SED_COMMAND} -i 's/ripplevalidators/xrplvalidators/g' src/test/core/Config_test.cpp # cspell: disable-line
${SED_COMMAND} -i 's/rippleConfig/xrpldConfig/g' src/test/core/Config_test.cpp
${SED_COMMAND} -i 's@ripple/@xrpld/@g' src/test/core/Config_test.cpp
${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp
# Restore the old config file name in the code that maintains support for now.
${SED_COMMAND} -i 's/configLegacyName = "xrpld.cfg"/configLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
# Restore an URL.
${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg
popd
echo "Renaming complete."

View File

@@ -1,103 +0,0 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1
fi
SED_COMMAND=gsed
fi
# This script removes superfluous copyright notices in source and header files
# in this project. Specifically, it removes all notices referencing Ripple,
# XRPLF, and certain individual contributors upon mutual agreement, so the one
# in the LICENSE.md file applies throughout. Copyright notices referencing
# external contributions, e.g. from Bitcoin, remain as-is.
# Usage: .github/scripts/rename/copyright.sh <repository directory>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <repository directory>"
exit 1
fi
DIRECTORY=$1
echo "Processing directory: ${DIRECTORY}"
if [ ! -d "${DIRECTORY}" ]; then
echo "Error: Directory '${DIRECTORY}' does not exist."
exit 1
fi
pushd ${DIRECTORY}
# Prevent sed and echo from removing newlines and tabs in string literals by
# temporarily replacing them with placeholders. This only affects one file.
PLACEHOLDER_NEWLINE="__NEWLINE__"
PLACEHOLDER_TAB="__TAB__"
${SED_COMMAND} -i -E "s@\\\n@${PLACEHOLDER_NEWLINE}@g" src/test/rpc/ValidatorInfo_test.cpp
${SED_COMMAND} -i -E "s@\\\t@${PLACEHOLDER_TAB}@g" src/test/rpc/ValidatorInfo_test.cpp
# Process the include/ and src/ directories.
DIRECTORIES=("include" "src")
for DIRECTORY in "${DIRECTORIES[@]}"; do
echo "Processing directory: ${DIRECTORY}"
find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" -o -name "*.macro" \) | while read -r FILE; do
echo "Processing file: ${FILE}"
# Handle the cases where the copyright notice is enclosed in /* ... */
# and usually surrounded by //---- and //======.
${SED_COMMAND} -z -i -E 's@^//-------+\n+@@' "${FILE}"
${SED_COMMAND} -z -i -E 's@^.*Copyright.+(Ripple|Bougalis|Falco|Hinnant|Null|Ritchford|XRPLF).+PERFORMANCE OF THIS SOFTWARE\.\n\*/\n+@@' "${FILE}" # cspell: ignore Bougalis Falco Hinnant Ritchford
${SED_COMMAND} -z -i -E 's@^//=======+\n+@@' "${FILE}"
# Handle the cases where the copyright notice is commented out with //.
${SED_COMMAND} -z -i -E 's@^//\n// Copyright.+Falco \(vinnie dot falco at gmail dot com\)\n//\n+@@' "${FILE}" # cspell: ignore Vinnie Falco
done
done
# Restore copyright notices that were removed from specific files, without
# restoring the verbiage that is already present in LICENSE.md. Ensure that if
# the script is run multiple times, duplicate notices are not added.
if ! grep -q 'Raw Material Software' include/xrpl/beast/core/CurrentThreadName.h; then
echo -e "// Portions of this file are from JUCE (http://www.juce.com).\n// Copyright (c) 2013 - Raw Material Software Ltd.\n// Please visit http://www.juce.com\n\n$(cat include/xrpl/beast/core/CurrentThreadName.h)" > include/xrpl/beast/core/CurrentThreadName.h
fi
if ! grep -q 'Dev Null' src/test/app/NetworkID_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/NetworkID_test.cpp)" > src/test/app/NetworkID_test.cpp
fi
if ! grep -q 'Dev Null' src/test/app/tx/apply_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/tx/apply_test.cpp)" > src/test/app/tx/apply_test.cpp
fi
if ! grep -q 'Dev Null' src/test/rpc/ManifestRPC_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ManifestRPC_test.cpp)" > src/test/rpc/ManifestRPC_test.cpp
fi
if ! grep -q 'Dev Null' src/test/rpc/ValidatorInfo_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ValidatorInfo_test.cpp)" > src/test/rpc/ValidatorInfo_test.cpp
fi
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/DoManifest.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/DoManifest.cpp)" > src/xrpld/rpc/handlers/DoManifest.cpp
fi
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/ValidatorInfo.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/ValidatorInfo.cpp
fi
if ! grep -q 'Bougalis' include/xrpl/basics/SlabAllocator.h; then
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/SlabAllocator.h)" > include/xrpl/basics/SlabAllocator.h # cspell: ignore Nikolaos Bougalis nikb
fi
if ! grep -q 'Bougalis' include/xrpl/basics/spinlock.h; then
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/spinlock.h)" > include/xrpl/basics/spinlock.h # cspell: ignore Nikolaos Bougalis nikb
fi
if ! grep -q 'Bougalis' include/xrpl/basics/tagged_integer.h; then
echo -e "// Copyright (c) 2014, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/tagged_integer.h)" > include/xrpl/basics/tagged_integer.h # cspell: ignore Nikolaos Bougalis nikb
fi
if ! grep -q 'Ritchford' include/xrpl/beast/utility/Zero.h; then
echo -e "// Copyright (c) 2014, Tom Ritchford <tom@swirly.com>\n\n$(cat include/xrpl/beast/utility/Zero.h)" > include/xrpl/beast/utility/Zero.h # cspell: ignore Ritchford
fi
# Restore newlines and tabs in string literals in the affected file.
${SED_COMMAND} -i -E "s@${PLACEHOLDER_NEWLINE}@\\\n@g" src/test/rpc/ValidatorInfo_test.cpp
${SED_COMMAND} -i -E "s@${PLACEHOLDER_TAB}@\\\t@g" src/test/rpc/ValidatorInfo_test.cpp
popd
echo "Removal complete."

View File

@@ -1,42 +0,0 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1
fi
SED_COMMAND=gsed
fi
# This script renames definitions, such as include guards, in this project.
# Specifically, it renames "RIPPLED_XXX" and "RIPPLE_XXX" to "XRPL_XXX" by
# scanning all cmake, header, and source files in the specified directory and
# its subdirectories.
# Usage: .github/scripts/rename/definitions.sh <repository directory>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <repository directory>"
exit 1
fi
DIRECTORY=$1
echo "Processing directory: ${DIRECTORY}"
if [ ! -d "${DIRECTORY}" ]; then
echo "Error: Directory '${DIRECTORY}' does not exist."
exit 1
fi
find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" \) | while read -r FILE; do
echo "Processing file: ${FILE}"
${SED_COMMAND} -i -E 's@#(define|endif|if|ifdef|ifndef)(.*)(RIPPLED_|RIPPLE_)([A-Z0-9_]+)@#\1\2XRPL_\4@g' "${FILE}"
done
find "${DIRECTORY}" -type f \( -name "*.cmake" -o -name "*.txt" \) | while read -r FILE; do
echo "Processing file: ${FILE}"
${SED_COMMAND} -i -E 's@(RIPPLED_|RIPPLE_)([A-Z0-9_]+)@XRPL_\2@g' "${FILE}"
done
echo "Renaming complete."

View File

@@ -1,30 +0,0 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -e
# This script checks whether there are no new include guards introduced by a new
# PR, as header files should use "#pragma once" instead. The script assumes any
# include guards will use "XRPL_" as prefix.
# Usage: .github/scripts/rename/include.sh <repository directory>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <repository directory>"
exit 1
fi
DIRECTORY=$1
echo "Processing directory: ${DIRECTORY}"
if [ ! -d "${DIRECTORY}" ]; then
echo "Error: Directory '${DIRECTORY}' does not exist."
exit 1
fi
find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" \) | while read -r FILE; do
echo "Processing file: ${FILE}"
if grep -q "#ifndef XRPL_" "${FILE}"; then
echo "Please replace all include guards by #pragma once."
exit 1
fi
done
echo "Checking complete."

View File

@@ -1,58 +0,0 @@
#!/bin/bash
# Exit the script as soon as an error occurs.
set -e
# On MacOS, ensure that GNU sed is installed and available as `gsed`.
SED_COMMAND=sed
if [[ "${OSTYPE}" == 'darwin'* ]]; then
if ! command -v gsed &> /dev/null; then
echo "Error: gsed is not installed. Please install it using 'brew install gnu-sed'."
exit 1
fi
SED_COMMAND=gsed
fi
# This script renames the `ripple` namespace to `xrpl` in this project.
# Specifically, it renames all occurrences of `namespace ripple` and `ripple::`
# to `namespace xrpl` and `xrpl::`, respectively, by scanning all header and
# source files in the specified directory and its subdirectories, as well as any
# occurrences in the documentation. It also renames them in the test suites.
# Usage: .github/scripts/rename/namespace.sh <repository directory>
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <repository directory>"
exit 1
fi
DIRECTORY=$1
echo "Processing directory: ${DIRECTORY}"
if [ ! -d "${DIRECTORY}" ]; then
echo "Error: Directory '${DIRECTORY}' does not exist."
exit 1
fi
pushd ${DIRECTORY}
DIRECTORIES=("include" "src" "tests")
for DIRECTORY in "${DIRECTORIES[@]}"; do
echo "Processing directory: ${DIRECTORY}"
find "${DIRECTORY}" -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.ipp" -o -name "*.cpp" \) | while read -r FILE; do
echo "Processing file: ${FILE}"
${SED_COMMAND} -i 's/namespace ripple/namespace xrpl/g' "${FILE}"
${SED_COMMAND} -i 's/ripple::/xrpl::/g' "${FILE}"
${SED_COMMAND} -i -E 's/(BEAST_DEFINE_TESTSUITE.+)ripple(.+)/\1xrpl\2/g' "${FILE}"
done
done
# Special case for NuDBFactory that has ripple twice in the test suite name.
${SED_COMMAND} -i -E 's/(BEAST_DEFINE_TESTSUITE.+)ripple(.+)/\1xrpl\2/g' src/test/nodestore/NuDBFactory_test.cpp
DIRECTORY=$1
find "${DIRECTORY}" -type f -name "*.md" | while read -r FILE; do
echo "Processing file: ${FILE}"
${SED_COMMAND} -i 's/ripple::/xrpl::/g' "${FILE}"
done
popd
echo "Renaming complete."

View File

@@ -1,333 +0,0 @@
#!/usr/bin/env python3
import argparse
import itertools
import json
from dataclasses import dataclass
from pathlib import Path
THIS_DIR = Path(__file__).parent.resolve()
@dataclass
class Config:
architecture: list[dict]
os: list[dict]
build_type: list[str]
cmake_args: list[str]
"""
Generate a strategy matrix for GitHub Actions CI.
On each PR commit we will build a selection of Debian, RHEL, Ubuntu, MacOS, and
Windows configurations, while upon merge into the develop or release branches,
we will build all configurations, and test most of them.
We will further set additional CMake arguments as follows:
- All builds will have the `tests`, `werr`, and `xrpld` options.
- All builds will have the `wextra` option except for GCC 12 and Clang 16.
- All release builds will have the `assert` option.
- Certain Debian Bookworm configurations will change the reference fee, enable
codecov, and enable voidstar in PRs.
"""
def generate_strategy_matrix(all: bool, config: Config) -> list:
configurations = []
for architecture, os, build_type, cmake_args in itertools.product(
config.architecture, config.os, config.build_type, config.cmake_args
):
# The default CMake target is 'all' for Linux and MacOS and 'install'
# for Windows, but it can get overridden for certain configurations.
cmake_target = "install" if os["distro_name"] == "windows" else "all"
# We build and test all configurations by default, except for Windows in
# Debug, because it is too slow, as well as when code coverage is
# enabled as that mode already runs the tests.
build_only = False
if os["distro_name"] == "windows" and build_type == "Debug":
build_only = True
# Only generate a subset of configurations in PRs.
if not all:
# Debian:
# - Bookworm using GCC 13: Release on linux/amd64, set the reference
# fee to 500.
# - Bookworm using GCC 15: Debug on linux/amd64, enable code
# coverage (which will be done below).
# - Bookworm using Clang 16: Debug on linux/arm64, enable voidstar.
# - Bookworm using Clang 17: Release on linux/amd64, set the
# reference fee to 1000.
# - Bookworm using Clang 20: Debug on linux/amd64.
if os["distro_name"] == "debian":
skip = True
if os["distro_version"] == "bookworm":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}"
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-16"
and build_type == "Debug"
and architecture["platform"] == "linux/arm64"
):
cmake_args = f"-Dvoidstar=ON {cmake_args}"
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-17"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}"
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
if skip:
continue
# RHEL:
# - 9 using GCC 12: Debug on linux/amd64.
# - 10 using Clang: Release on linux/amd64.
if os["distro_name"] == "rhel":
skip = True
if os["distro_version"] == "9":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
elif os["distro_version"] == "10":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-any"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
skip = False
if skip:
continue
# Ubuntu:
# - Jammy using GCC 12: Debug on linux/arm64.
# - Noble using GCC 14: Release on linux/amd64.
# - Noble using Clang 18: Debug on linux/amd64.
# - Noble using Clang 19: Release on linux/arm64.
if os["distro_name"] == "ubuntu":
skip = True
if os["distro_version"] == "jammy":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and architecture["platform"] == "linux/arm64"
):
skip = False
elif os["distro_version"] == "noble":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-18"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-19"
and build_type == "Release"
and architecture["platform"] == "linux/arm64"
):
skip = False
if skip:
continue
# MacOS:
# - Debug on macos/arm64.
if os["distro_name"] == "macos" and not (
build_type == "Debug" and architecture["platform"] == "macos/arm64"
):
continue
# Windows:
# - Release on windows/amd64.
if os["distro_name"] == "windows" and not (
build_type == "Release" and architecture["platform"] == "windows/amd64"
):
continue
# Additional CMake arguments.
cmake_args = f"{cmake_args} -Dtests=ON -Dwerr=ON -Dxrpld=ON"
if not f"{os['compiler_name']}-{os['compiler_version']}" in [
"gcc-12",
"clang-16",
]:
cmake_args = f"{cmake_args} -Dwextra=ON"
if build_type == "Release":
cmake_args = f"{cmake_args} -Dassert=ON"
# We skip all RHEL on arm64 due to a build failure that needs further
# investigation.
if os["distro_name"] == "rhel" and architecture["platform"] == "linux/arm64":
continue
# We skip all clang 20+ on arm64 due to Boost build error.
if (
f"{os['compiler_name']}-{os['compiler_version']}"
in ["clang-20", "clang-21"]
and architecture["platform"] == "linux/arm64"
):
continue
# Enable code coverage for Debian Bookworm using GCC 15 in Debug on
# linux/amd64
if (
f"{os['distro_name']}-{os['distro_version']}" == "debian-bookworm"
and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"{cmake_args} -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0"
# Enable unity build for Ubuntu Jammy using GCC 12 in Debug on
# linux/amd64.
if (
f"{os['distro_name']}-{os['distro_version']}" == "ubuntu-jammy"
and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"{cmake_args} -Dunity=ON"
# Generate a unique name for the configuration, e.g. macos-arm64-debug
# or debian-bookworm-gcc-12-amd64-release.
config_name = os["distro_name"]
if (n := os["distro_version"]) != "":
config_name += f"-{n}"
if (n := os["compiler_name"]) != "":
config_name += f"-{n}"
if (n := os["compiler_version"]) != "":
config_name += f"-{n}"
config_name += (
f"-{architecture['platform'][architecture['platform'].find('/')+1:]}"
)
config_name += f"-{build_type.lower()}"
if "-Dcoverage=ON" in cmake_args:
config_name += "-coverage"
if "-Dunity=ON" in cmake_args:
config_name += "-unity"
# Add the configuration to the list, with the most unique fields first,
# so that they are easier to identify in the GitHub Actions UI, as long
# names get truncated.
# Add Address and Thread (both coupled with UB) sanitizers for specific bookworm distros.
# GCC-Asan rippled-embedded tests are failing because of https://github.com/google/sanitizers/issues/856
if (
os["distro_version"] == "bookworm"
and f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20"
):
# Add ASAN + UBSAN configuration.
configurations.append(
{
"config_name": config_name + "-asan-ubsan",
"cmake_args": cmake_args,
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type,
"os": os,
"architecture": architecture,
"sanitizers": "address,undefinedbehavior",
}
)
# TSAN is deactivated due to seg faults with latest compilers.
activate_tsan = False
if activate_tsan:
configurations.append(
{
"config_name": config_name + "-tsan-ubsan",
"cmake_args": cmake_args,
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type,
"os": os,
"architecture": architecture,
"sanitizers": "thread,undefinedbehavior",
}
)
else:
configurations.append(
{
"config_name": config_name,
"cmake_args": cmake_args,
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type,
"os": os,
"architecture": architecture,
"sanitizers": "",
}
)
return configurations
def read_config(file: Path) -> Config:
config = json.loads(file.read_text())
if (
config["architecture"] is None
or config["os"] is None
or config["build_type"] is None
or config["cmake_args"] is None
):
raise Exception("Invalid configuration file.")
return Config(**config)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"-a",
"--all",
help="Set to generate all configurations (generally used when merging a PR) or leave unset to generate a subset of configurations (generally used when committing to a PR).",
action="store_true",
)
parser.add_argument(
"-c",
"--config",
help="Path to the JSON file containing the strategy matrix configurations.",
required=False,
type=Path,
)
args = parser.parse_args()
matrix = []
if args.config is None or args.config == "":
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "linux.json")
)
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "macos.json")
)
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "windows.json")
)
else:
matrix += generate_strategy_matrix(args.all, read_config(args.config))
# Generate the strategy matrix.
print(f"matrix={json.dumps({'include': matrix})}")

View File

@@ -1,212 +0,0 @@
{
"architecture": [
{
"platform": "linux/amd64",
"runner": ["self-hosted", "Linux", "X64", "heavy"]
},
{
"platform": "linux/arm64",
"runner": ["self-hosted", "Linux", "ARM64", "heavy-arm64"]
}
],
"os": [
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "15",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "16",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "17",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "18",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "19",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "20",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "gcc",
"compiler_version": "15",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "20",
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "21",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "jammy",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "16",
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "17",
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "18",
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "19",
"image_sha": "ab4d1f0"
}
],
"build_type": ["Debug", "Release"],
"cmake_args": [""]
}

View File

@@ -1,19 +0,0 @@
{
"architecture": [
{
"platform": "macos/arm64",
"runner": ["self-hosted", "macOS", "ARM64", "mac-runner-m1"]
}
],
"os": [
{
"distro_name": "macos",
"distro_version": "",
"compiler_name": "",
"compiler_version": "",
"image_sha": ""
}
],
"build_type": ["Debug", "Release"],
"cmake_args": ["-DCMAKE_POLICY_VERSION_MINIMUM=3.5"]
}

View File

@@ -1,19 +0,0 @@
{
"architecture": [
{
"platform": "windows/amd64",
"runner": ["self-hosted", "Windows", "devbox"]
}
],
"os": [
{
"distro_name": "windows",
"distro_version": "",
"compiler_name": "",
"compiler_version": "",
"image_sha": ""
}
],
"build_type": ["Debug", "Release"],
"cmake_args": [""]
}

64
.github/workflows/clang-format.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: clang-format
on:
push:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
jobs:
check:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
runs-on: ubuntu-24.04
container: ghcr.io/xrplf/ci/tools-rippled-clang-format
steps:
# For jobs running in containers, $GITHUB_WORKSPACE and ${{ github.workspace }} might not be the
# same directory. The actions/checkout step is *supposed* to checkout into $GITHUB_WORKSPACE and
# then add it to safe.directory (see instructions at https://github.com/actions/checkout)
# but that's apparently not happening for some container images. We can't be sure what is actually
# happening, so let's pre-emptively add both directories to safe.directory. There's a
# Github issue opened in 2022 and not resolved in 2025 https://github.com/actions/runner/issues/2058 ¯\_(ツ)_/¯
- run: |
git config --global --add safe.directory $GITHUB_WORKSPACE
git config --global --add safe.directory ${{ github.workspace }}
- uses: actions/checkout@v4
- name: Format first-party sources
run: |
clang-format --version
find include src tests -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format -i {} +
- name: Check for differences
id: assert
shell: bash
run: |
set -o pipefail
git diff --exit-code | tee "clang-format.patch"
- name: Upload patch
if: failure() && steps.assert.outcome == 'failure'
uses: actions/upload-artifact@v4
continue-on-error: true
with:
name: clang-format.patch
if-no-files-found: ignore
path: clang-format.patch
- name: What happened?
if: failure() && steps.assert.outcome == 'failure'
env:
PREAMBLE: |
If you are reading this, you are looking at a failed Github Actions
job. That means you pushed one or more files that did not conform
to the formatting specified in .clang-format. That may be because
you neglected to run 'git clang-format' or 'clang-format' before
committing, or that your version of clang-format has an
incompatibility with the one on this
machine, which is:
SUGGESTION: |
To fix it, you can do one of two things:
1. Download and apply the patch generated as an artifact of this
job to your repo, commit, and push.
2. Run 'git-clang-format --extensions cpp,h,hpp,ipp develop'
in your repo, commit, and push.
run: |
echo "${PREAMBLE}"
clang-format --version
echo "${SUGGESTION}"
exit 1

37
.github/workflows/doxygen.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Build and publish Doxygen documentation
# To test this workflow, push your changes to your fork's `develop` branch.
on:
push:
branches:
- develop
- doxygen
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
documentation:
runs-on: ubuntu-latest
permissions:
contents: write
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
steps:
- name: checkout
uses: actions/checkout@v4
- name: check environment
run: |
echo ${PATH} | tr ':' '\n'
cmake --version
doxygen --version
env | sort
- name: build
run: |
mkdir build
cd build
cmake -Donly_docs=TRUE ..
cmake --build . --target docs --parallel $(nproc)
- name: publish
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: build/docs/html

53
.github/workflows/levelization.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: levelization
on:
push:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
jobs:
check:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
runs-on: ubuntu-latest
env:
CLANG_VERSION: 10
steps:
- uses: actions/checkout@v4
- name: Check levelization
run: Builds/levelization/levelization.sh
- name: Check for differences
id: assert
run: |
set -o pipefail
git diff --exit-code | tee "levelization.patch"
- name: Upload patch
if: failure() && steps.assert.outcome == 'failure'
uses: actions/upload-artifact@v4
continue-on-error: true
with:
name: levelization.patch
if-no-files-found: ignore
path: levelization.patch
- name: What happened?
if: failure() && steps.assert.outcome == 'failure'
env:
MESSAGE: |
If you are reading this, you are looking at a failed Github
Actions job. That means you changed the dependency relationships
between the modules in rippled. That may be an improvement or a
regression. This check doesn't judge.
A rule of thumb, though, is that if your changes caused
something to be removed from loops.txt, that's probably an
improvement. If something was added, it's probably a regression.
To fix it, you can do one of two things:
1. Download and apply the patch generated as an artifact of this
job to your repo, commit, and push.
2. Run './Builds/levelization/levelization.sh' in your repo,
commit, and push.
See Builds/levelization/README.md for more info.
run: |
echo "${MESSAGE}"
exit 1

117
.github/workflows/macos.yml vendored Normal file
View File

@@ -0,0 +1,117 @@
name: macos
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
push:
# If the branches list is ever changed, be sure to change it on all
# build/test jobs (nix, macos, windows, instrumentation)
branches:
# Always build the package branches
- develop
- release
- master
# Branches that opt-in to running
- "ci/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# This part of Conan configuration is specific to this workflow only; we do not want
# to pollute conan/profiles directory with settings which might not work for others
env:
CONAN_REMOTE_URL: https://conan.ripplex.io
CONAN_REMOTE_USERNAME: ${{ secrets.CONAN_REMOTE_USERNAME }}
CONAN_REMOTE_PASSWORD: ${{ secrets.CONAN_REMOTE_PASSWORD }}
# This part of the Conan configuration is specific to this workflow only; we
# do not want to pollute the 'conan/profiles' directory with settings that
# might not work for other workflows.
CONAN_GLOBAL_CONF: |
core.download:parallel={{os.cpu_count()}}
core.upload:parallel={{os.cpu_count()}}
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose
jobs:
test:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
strategy:
matrix:
platform:
- macos
generator:
- Ninja
configuration:
- Release
runs-on: [self-hosted, macOS, mac-runner-m1]
env:
# The `build` action requires these variables.
build_dir: .build
NUM_PROCESSORS: 12
steps:
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Delete old build tools installed using Homebrew
run: |
brew uninstall --force \
cmake \
conan
- name: Install build tools using Homebrew
run: |
brew install --quiet \
ca-certificates \
ninja \
python@3.14
- name: Remove old fmt using Homebrew
run: |
brew unlink fmt
brew cleanup
brew link fmt
- name: List software installed using Homebrew
run: brew list --version
- name: Install build tools using pip
shell: bash
run: |
pip3 install --break-system-packages --upgrade pip
pip3 install --break-system-packages \
cmake==4.1.2 \
conan==2.22.1
- name: check environment
run: |
env | sort
echo ${PATH} | tr ':' '\n'
python --version
conan --version
cmake --version
nproc --version
echo -n "nproc returns: "
nproc
system_profiler SPHardwareDataType
sysctl -n hw.logicalcpu
clang --version
- name: configure Conan
run: |
echo "${CONAN_GLOBAL_CONF}" > $(conan config home)/global.conf
conan config install conan/profiles/ -tf $(conan config home)/profiles/
conan profile show
- name: build dependencies
uses: ./.github/actions/dependencies
with:
configuration: ${{ matrix.configuration }}
- name: build
uses: ./.github/actions/build
with:
generator: ${{ matrix.generator }}
configuration: ${{ matrix.configuration }}
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
- name: test
run: |
n=$(nproc)
echo "Using $n test jobs"
cd ${build_dir}
./rippled --unittest --unittest-jobs $n
ctest -j $n --output-on-failure

60
.github/workflows/missing-commits.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: missing-commits
on:
push:
branches:
# Only check that the branches are up to date when updating the
# relevant branches.
- develop
- release
jobs:
up_to_date:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for missing commits
id: commits
env:
SUGGESTION: |
If you are reading this, then the commits indicated above are
missing from "develop" and/or "release". Do a reverse-merge
as soon as possible. See CONTRIBUTING.md for instructions.
run: |
set -o pipefail
# Branches ordered by how "canonical" they are. Every commit in
# one branch should be in all the branches behind it
order=( master release develop )
branches=()
for branch in "${order[@]}"
do
# Check that the branches exist so that this job will work on
# forked repos, which don't necessarily have master and
# release branches.
if git ls-remote --exit-code --heads origin \
refs/heads/${branch} > /dev/null
then
branches+=( origin/${branch} )
fi
done
prior=()
for branch in "${branches[@]}"
do
if [[ ${#prior[@]} -ne 0 ]]
then
echo "Checking ${prior[@]} for commits missing from ${branch}"
git log --oneline --no-merges "${prior[@]}" \
^$branch | tee -a "missing-commits.txt"
echo
fi
prior+=( "${branch}" )
done
if [[ $( cat missing-commits.txt | wc -l ) -ne 0 ]]
then
echo "${SUGGESTION}"
exit 1
fi

422
.github/workflows/nix.yml vendored Normal file
View File

@@ -0,0 +1,422 @@
name: nix
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
push:
# If the branches list is ever changed, be sure to change it on all
# build/test jobs (nix, macos, windows)
branches:
# Always build the package branches
- develop
- release
- master
# Branches that opt-in to running
- "ci/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CONAN_REMOTE_URL: https://conan.ripplex.io
CONAN_REMOTE_USERNAME: ${{ secrets.CONAN_REMOTE_USERNAME }}
CONAN_REMOTE_PASSWORD: ${{ secrets.CONAN_REMOTE_PASSWORD }}
# This part of the Conan configuration is specific to this workflow only; we
# do not want to pollute the 'conan/profiles' directory with settings that
# might not work for other workflows.
CONAN_GLOBAL_CONF: |
core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }}
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose
# This workflow has multiple job matrixes.
# They can be considered phases because most of the matrices ("test",
# "coverage", "conan", ) depend on the first ("dependencies").
#
# The first phase has a job in the matrix for each combination of
# variables that affects dependency ABI:
# platform, compiler, and configuration.
# It creates a GitHub artifact holding the Conan profile,
# and builds and caches binaries for all the dependencies.
# If an Artifactory remote is configured, they are cached there.
# If not, they are added to the GitHub artifact.
# GitHub's "cache" action has a size limit (10 GB) that is too small
# to hold the binaries if they are built locally.
# We must use the "{upload,download}-artifact" actions instead.
#
# The remaining phases have a job in the matrix for each test
# configuration. They install dependency binaries from the cache,
# whichever was used, and build and test rippled.
#
# "instrumentation" is independent, but is included here because it also
# builds on linux in the same "on:" conditions.
jobs:
dependencies:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
strategy:
fail-fast: false
matrix:
platform:
- linux
compiler:
- gcc
- clang
configuration:
- Debug
- Release
include:
- compiler: gcc
compiler_version: 12
distro: ubuntu
codename: jammy
- compiler: clang
compiler_version: 16
distro: debian
codename: bookworm
runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }}
env:
build_dir: .build
steps:
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: check environment
run: |
echo ${PATH} | tr ':' '\n'
lsb_release -a || true
${{ matrix.compiler }}-${{ matrix.compiler_version }} --version
conan --version
cmake --version
env | sort
- name: configure Conan
run: |
echo "${CONAN_GLOBAL_CONF}" >> $(conan config home)/global.conf
conan config install conan/profiles/ -tf $(conan config home)/profiles/
conan profile show
- name: archive profile
# Create this archive before dependencies are added to the local cache.
run: tar -czf conan.tar.gz -C ${CONAN_HOME} .
- name: build dependencies
uses: ./.github/actions/dependencies
with:
configuration: ${{ matrix.configuration }}
- name: upload archive
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
path: conan.tar.gz
if-no-files-found: error
test:
strategy:
fail-fast: false
matrix:
platform:
- linux
compiler:
- gcc
- clang
configuration:
- Debug
- Release
include:
- compiler: gcc
compiler_version: 12
distro: ubuntu
codename: jammy
- compiler: clang
compiler_version: 16
distro: debian
codename: bookworm
cmake-args:
-
- "-Dunity=ON"
needs: dependencies
runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }}
env:
build_dir: .build
steps:
- name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
- name: extract cache
run: |
mkdir -p ${CONAN_HOME}
tar -xzf conan.tar.gz -C ${CONAN_HOME}
- name: check environment
run: |
env | sort
echo ${PATH} | tr ':' '\n'
conan --version
cmake --version
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: dependencies
uses: ./.github/actions/dependencies
with:
configuration: ${{ matrix.configuration }}
- name: build
uses: ./.github/actions/build
with:
generator: Ninja
configuration: ${{ matrix.configuration }}
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
- name: check linking
run: |
cd ${build_dir}
ldd ./rippled
if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
echo 'The binary is statically linked.'
else
echo 'The binary is dynamically linked.'
exit 1
fi
- name: test
run: |
cd ${build_dir}
./rippled --unittest --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure
reference-fee-test:
strategy:
fail-fast: false
matrix:
platform:
- linux
compiler:
- gcc
configuration:
- Debug
cmake-args:
- "-DUNIT_TEST_REFERENCE_FEE=200"
- "-DUNIT_TEST_REFERENCE_FEE=1000"
needs: dependencies
runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
env:
build_dir: .build
steps:
- name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
- name: extract cache
run: |
mkdir -p ${CONAN_HOME}
tar -xzf conan.tar.gz -C ${CONAN_HOME}
- name: check environment
run: |
env | sort
echo ${PATH} | tr ':' '\n'
conan --version
cmake --version
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: dependencies
uses: ./.github/actions/dependencies
with:
configuration: ${{ matrix.configuration }}
- name: build
uses: ./.github/actions/build
with:
generator: Ninja
configuration: ${{ matrix.configuration }}
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
- name: test
run: |
cd ${build_dir}
./rippled --unittest --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure
coverage:
strategy:
fail-fast: false
matrix:
platform:
- linux
compiler:
- gcc
configuration:
- Debug
needs: dependencies
runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
env:
build_dir: .build
steps:
- name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
- name: extract cache
run: |
mkdir -p ${CONAN_HOME}
tar -xzf conan.tar.gz -C ${CONAN_HOME}
- name: check environment
run: |
echo ${PATH} | tr ':' '\n'
conan --version
cmake --version
gcovr --version
env | sort
ls ${CONAN_HOME}
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: dependencies
uses: ./.github/actions/dependencies
with:
configuration: ${{ matrix.configuration }}
- name: build
uses: ./.github/actions/build
with:
generator: Ninja
configuration: ${{ matrix.configuration }}
cmake-args: >-
-Dassert=TRUE
-Dwerr=TRUE
-Dcoverage=ON
-Dcoverage_format=xml
-DCODE_COVERAGE_VERBOSE=ON
-DCMAKE_CXX_FLAGS="-O0"
-DCMAKE_C_FLAGS="-O0"
cmake-target: coverage
- name: move coverage report
shell: bash
run: |
mv "${build_dir}/coverage.xml" ./
- name: archive coverage report
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: coverage.xml
path: coverage.xml
retention-days: 30
- name: upload coverage report
uses: wandalen/wretry.action@v1.4.10
with:
action: codecov/codecov-action@v4.5.0
with: |
files: coverage.xml
fail_ci_if_error: true
disable_search: true
verbose: true
plugin: noop
token: ${{ secrets.CODECOV_TOKEN }}
attempt_limit: 5
attempt_delay: 210000 # in milliseconds
conan:
needs: dependencies
runs-on: [self-hosted, heavy]
container:
image: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
env:
build_dir: .build
platform: linux
compiler: gcc
compiler_version: 12
configuration: Release
steps:
- name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: ${{ env.platform }}-${{ env.compiler }}-${{ env.configuration }}
- name: extract cache
run: |
mkdir -p ${CONAN_HOME}
tar -xzf conan.tar.gz -C ${CONAN_HOME}
- name: check environment
run: |
env | sort
echo ${PATH} | tr ':' '\n'
conan --version
cmake --version
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: dependencies
uses: ./.github/actions/dependencies
with:
configuration: ${{ env.configuration }}
- name: export
run: |
conan export . --version head
- name: build
run: |
cd tests/conan
mkdir ${build_dir} && cd ${build_dir}
conan install .. \
--settings:all build_type=${configuration} \
--output-folder . \
--build missing
cmake .. \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=./build/${configuration}/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=${configuration}
cmake --build .
./example | grep '^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+'
instrumentation-build:
needs: dependencies
runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/debian-bookworm:clang-16
env:
build_dir: .build
steps:
- name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: linux-clang-Debug
- name: extract cache
run: |
mkdir -p ${CONAN_HOME}
tar -xzf conan.tar.gz -C ${CONAN_HOME}
- name: check environment
run: |
echo ${PATH} | tr ':' '\n'
conan --version
cmake --version
env | sort
ls ${CONAN_HOME}
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: dependencies
uses: ./.github/actions/dependencies
with:
configuration: Debug
- name: prepare environment
run: |
mkdir -p ${build_dir}
echo "SOURCE_DIR=$(pwd)" >> $GITHUB_ENV
echo "BUILD_DIR=$(pwd)/${build_dir}" >> $GITHUB_ENV
- name: build with instrumentation
run: |
cd ${BUILD_DIR}
cmake -S ${SOURCE_DIR} -B ${BUILD_DIR} \
-Dvoidstar=ON \
-Dtests=ON \
-Dxrpld=ON \
-DCMAKE_BUILD_TYPE=Debug \
-DSECP256K1_BUILD_BENCHMARK=OFF \
-DSECP256K1_BUILD_TESTS=OFF \
-DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \
-DCMAKE_TOOLCHAIN_FILE=${BUILD_DIR}/build/generators/conan_toolchain.cmake
cmake --build . --parallel $(nproc)
- name: verify instrumentation enabled
run: |
cd ${BUILD_DIR}
./rippled --version | grep libvoidstar
- name: run unit tests
run: |
cd ${BUILD_DIR}
./rippled -u --unittest-jobs $(( $(nproc)/4 ))
ctest -j $(nproc) --output-on-failure

View File

@@ -1,165 +0,0 @@
# This workflow runs all workflows to check, build and test the project on
# various Linux flavors, as well as on MacOS and Windows, on every push to a
# user branch. However, it will not run if the pull request is a draft unless it
# has the 'DraftRunCI' label. For commits to PRs that target a release branch,
# it also uploads the libxrpl recipe to the Conan remote.
name: PR
on:
merge_group:
types:
- checks_requested
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
# This job determines whether the rest of the workflow should run. It runs
# when the PR is not a draft (which should also cover merge-group) or
# has the 'DraftRunCI' label.
should-run:
if: ${{ !github.event.pull_request.draft || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Determine changed files
# This step checks whether any files have changed that should
# cause the next jobs to run. We do it this way rather than
# using `paths` in the `on:` section, because all required
# checks must pass, even for changes that do not modify anything
# that affects those checks. We would therefore like to make the
# checks required only if the job runs, but GitHub does not
# support that directly. By always executing the workflow on new
# commits and by using the changed-files action below, we ensure
# that Github considers any skipped jobs to have passed, and in
# turn the required checks as well.
id: changes
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
with:
files: |
# These paths are unique to `on-pr.yml`.
.github/scripts/levelization/**
.github/scripts/rename/**
.github/workflows/reusable-check-levelization.yml
.github/workflows/reusable-check-rename.yml
.github/workflows/on-pr.yml
# Keep the paths below in sync with those in `on-trigger.yml`.
.github/actions/build-deps/**
.github/actions/build-test/**
.github/actions/generate-version/**
.github/actions/setup-conan/**
.github/scripts/strategy-matrix/**
.github/workflows/reusable-build.yml
.github/workflows/reusable-build-test-config.yml
.github/workflows/reusable-build-test.yml
.github/workflows/reusable-strategy-matrix.yml
.github/workflows/reusable-test.yml
.github/workflows/reusable-upload-recipe.yml
.codecov.yml
cmake/**
conan/**
external/**
include/**
src/**
tests/**
CMakeLists.txt
conanfile.py
conan.lock
- name: Check whether to run
# This step determines whether the rest of the workflow should
# run. The rest of the workflow will run if this job runs AND at
# least one of:
# * Any of the files checked in the `changes` step were modified
# * The PR is NOT a draft and is labeled "Ready to merge"
# * The workflow is running from the merge queue
id: go
env:
FILES: ${{ steps.changes.outputs.any_changed }}
DRAFT: ${{ github.event.pull_request.draft }}
READY: ${{ contains(github.event.pull_request.labels.*.name, 'Ready to merge') }}
MERGE: ${{ github.event_name == 'merge_group' }}
run: |
echo "go=${{ (env.DRAFT != 'true' && env.READY == 'true') || env.FILES == 'true' || env.MERGE == 'true' }}" >> "${GITHUB_OUTPUT}"
cat "${GITHUB_OUTPUT}"
outputs:
go: ${{ steps.go.outputs.go == 'true' }}
check-levelization:
needs: should-run
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-check-levelization.yml
check-rename:
needs: should-run
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-check-rename.yml
build-test:
needs: should-run
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-build-test.yml
strategy:
fail-fast: false
matrix:
os: [linux, macos, windows]
with:
# Enable ccache only for events targeting the XRPLF repository, since
# other accounts will not have access to our remote cache storage.
ccache_enabled: ${{ github.repository_owner == 'XRPLF' }}
os: ${{ matrix.os }}
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
upload-recipe:
needs:
- should-run
- build-test
# Only run when committing to a PR that targets a release branch in the
# XRPLF repository.
if: ${{ github.repository_owner == 'XRPLF' && needs.should-run.outputs.go == 'true' && startsWith(github.ref, 'refs/heads/release') }}
uses: ./.github/workflows/reusable-upload-recipe.yml
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
notify-clio:
needs: upload-recipe
runs-on: ubuntu-latest
steps:
# Notify the Clio repository about the newly proposed release version, so
# it can be checked for compatibility before the release is actually made.
- name: Notify Clio
env:
GH_TOKEN: ${{ secrets.CLIO_NOTIFY_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \
/repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \
-F "client_payload[ref]=${{ needs.upload-recipe.outputs.recipe_ref }}" \
-F "client_payload[pr_url]=${PR_URL}"
passed:
if: failure() || cancelled()
needs:
- check-levelization
- check-rename
- build-test
- upload-recipe
- notify-clio
runs-on: ubuntu-latest
steps:
- name: Fail
run: false

Some files were not shown because too many files have changed in this diff Show More