mirror of
https://github.com/XRPLF/rippled.git
synced 2026-02-28 09:42:32 +00:00
Compare commits
38 Commits
dangell7/a
...
legleux/tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8585055d6e | ||
|
|
a35308399d | ||
|
|
8068a7b513 | ||
|
|
1a7f824b89 | ||
|
|
b58c681189 | ||
|
|
404f35d556 | ||
|
|
2e595b6031 | ||
|
|
3a8a18c2ca | ||
|
|
65e63ebef3 | ||
|
|
bdd106d992 | ||
|
|
24cbaf76a5 | ||
|
|
3a805cc646 | ||
|
|
0fd237d707 | ||
|
|
3542daa4cc | ||
|
|
fd9f57ec97 | ||
|
|
625becff18 | ||
|
|
4bcbc6e50f | ||
|
|
0bc4a0cfe8 | ||
|
|
cb54adefed | ||
|
|
d03d72bfd5 | ||
|
|
6f35d94b2f | ||
|
|
2c1fad1023 | ||
|
|
25cca46553 | ||
|
|
469ce9f291 | ||
|
|
31302877ab | ||
|
|
0976b2b68b | ||
|
|
36240116a5 | ||
|
|
958d8f3754 | ||
|
|
ac0ad3627f | ||
|
|
cd218346ff | ||
|
|
5edd3566f7 | ||
|
|
11e8d1f8a2 | ||
|
|
9f17d10348 | ||
|
|
ef284692db | ||
|
|
e11f6190b7 | ||
|
|
db2734cbc9 | ||
|
|
bf4674f42b | ||
|
|
f5208fc850 |
@@ -37,7 +37,7 @@ BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
ColumnLimit: 120
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
|
||||
200
.clang-tidy
Normal file
200
.clang-tidy
Normal file
@@ -0,0 +1,200 @@
|
||||
---
|
||||
Checks: "-*,
|
||||
bugprone-argument-comment,
|
||||
bugprone-assert-side-effect,
|
||||
bugprone-bad-signal-to-kill-thread,
|
||||
bugprone-bool-pointer-implicit-conversion,
|
||||
bugprone-casting-through-void,
|
||||
bugprone-chained-comparison,
|
||||
bugprone-compare-pointer-to-member-virtual-function,
|
||||
bugprone-copy-constructor-init,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-dynamic-static-initializers,
|
||||
bugprone-fold-init-type,
|
||||
bugprone-forward-declaration-namespace,
|
||||
bugprone-inaccurate-erase,
|
||||
bugprone-incorrect-enable-if,
|
||||
bugprone-incorrect-roundings,
|
||||
bugprone-infinite-loop,
|
||||
bugprone-integer-division,
|
||||
bugprone-lambda-function-name,
|
||||
bugprone-macro-parentheses,
|
||||
bugprone-macro-repeated-side-effects,
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||
bugprone-misplaced-widening-cast,
|
||||
bugprone-multi-level-implicit-pointer-conversion,
|
||||
bugprone-multiple-new-in-one-expression,
|
||||
bugprone-multiple-statement-macro,
|
||||
bugprone-no-escape,
|
||||
bugprone-non-zero-enum-to-bool-conversion,
|
||||
bugprone-parent-virtual-call,
|
||||
bugprone-posix-return,
|
||||
bugprone-redundant-branch-condition,
|
||||
bugprone-shared-ptr-array-mismatch,
|
||||
bugprone-signal-handler,
|
||||
bugprone-signed-char-misuse,
|
||||
bugprone-sizeof-container,
|
||||
bugprone-spuriously-wake-up-functions,
|
||||
bugprone-standalone-empty,
|
||||
bugprone-string-constructor,
|
||||
bugprone-string-integer-assignment,
|
||||
bugprone-string-literal-with-embedded-nul,
|
||||
bugprone-stringview-nullptr,
|
||||
bugprone-suspicious-enum-usage,
|
||||
bugprone-suspicious-include,
|
||||
bugprone-suspicious-memory-comparison,
|
||||
bugprone-suspicious-memset-usage,
|
||||
bugprone-suspicious-realloc-usage,
|
||||
bugprone-suspicious-semicolon,
|
||||
bugprone-suspicious-string-compare,
|
||||
bugprone-swapped-arguments,
|
||||
bugprone-terminating-continue,
|
||||
bugprone-throw-keyword-missing,
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-undelegated-constructor,
|
||||
bugprone-unhandled-exception-at-new,
|
||||
bugprone-unique-ptr-array-mismatch,
|
||||
bugprone-unsafe-functions,
|
||||
bugprone-virtual-near-miss,
|
||||
cppcoreguidelines-no-suspend-with-lock,
|
||||
cppcoreguidelines-virtual-class-destructor,
|
||||
hicpp-ignored-remove-result,
|
||||
misc-definitions-in-headers,
|
||||
misc-header-include-cycle,
|
||||
misc-misplaced-const,
|
||||
misc-static-assert,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
misc-unused-alias-decls,
|
||||
misc-unused-using-decls,
|
||||
readability-duplicate-include,
|
||||
readability-enum-initial-value,
|
||||
readability-misleading-indentation,
|
||||
readability-non-const-parameter,
|
||||
readability-redundant-declaration,
|
||||
readability-reference-to-constructed-temporary,
|
||||
modernize-deprecated-headers,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
performance-implicit-conversion-in-loop,
|
||||
performance-move-constructor-init,
|
||||
performance-trivially-destructible
|
||||
"
|
||||
# ---
|
||||
# checks that have some issues that need to be resolved:
|
||||
#
|
||||
# bugprone-empty-catch,
|
||||
# bugprone-crtp-constructor-accessibility,
|
||||
# bugprone-inc-dec-in-conditions,
|
||||
# bugprone-reserved-identifier,
|
||||
# bugprone-move-forwarding-reference,
|
||||
# bugprone-unused-local-non-trivial-variable,
|
||||
# bugprone-return-const-ref-from-parameter,
|
||||
# bugprone-switch-missing-default-case,
|
||||
# bugprone-sizeof-expression,
|
||||
# bugprone-suspicious-stringview-data-usage,
|
||||
# bugprone-suspicious-missing-comma,
|
||||
# bugprone-pointer-arithmetic-on-polymorphic-object,
|
||||
# bugprone-optional-value-conversion,
|
||||
# bugprone-too-small-loop-variable,
|
||||
# bugprone-unused-return-value,
|
||||
# bugprone-use-after-move,
|
||||
# bugprone-unhandled-self-assignment,
|
||||
# bugprone-unused-raii,
|
||||
#
|
||||
# cppcoreguidelines-misleading-capture-default-by-value,
|
||||
# cppcoreguidelines-init-variables,
|
||||
# cppcoreguidelines-pro-type-member-init,
|
||||
# cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
# cppcoreguidelines-use-default-member-init,
|
||||
# cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||
#
|
||||
# llvm-namespace-comment,
|
||||
# misc-const-correctness,
|
||||
# misc-include-cleaner,
|
||||
# misc-redundant-expression,
|
||||
#
|
||||
# readability-avoid-nested-conditional-operator,
|
||||
# readability-avoid-return-with-void-value,
|
||||
# readability-braces-around-statements,
|
||||
# readability-container-contains,
|
||||
# readability-container-size-empty,
|
||||
# readability-convert-member-functions-to-static,
|
||||
# readability-const-return-type,
|
||||
# readability-else-after-return,
|
||||
# readability-implicit-bool-conversion,
|
||||
# readability-inconsistent-declaration-parameter-name,
|
||||
# readability-identifier-naming,
|
||||
# readability-make-member-function-const,
|
||||
# readability-math-missing-parentheses,
|
||||
# readability-redundant-inline-specifier,
|
||||
# readability-redundant-member-init,
|
||||
# readability-redundant-casting,
|
||||
# readability-redundant-string-init,
|
||||
# readability-simplify-boolean-expr,
|
||||
# readability-static-definition-in-anonymous-namespace,
|
||||
# readability-suspicious-call-argument,
|
||||
# readability-use-std-min-max,
|
||||
# readability-static-accessed-through-instance,
|
||||
#
|
||||
# modernize-concat-nested-namespaces,
|
||||
# modernize-pass-by-value,
|
||||
# modernize-type-traits,
|
||||
# modernize-use-designated-initializers,
|
||||
# modernize-use-emplace,
|
||||
# modernize-use-equals-default,
|
||||
# modernize-use-equals-delete,
|
||||
# modernize-use-override,
|
||||
# modernize-use-ranges,
|
||||
# modernize-use-starts-ends-with,
|
||||
# modernize-use-std-numbers,
|
||||
# modernize-use-using,
|
||||
#
|
||||
# performance-faster-string-find,
|
||||
# performance-for-range-copy,
|
||||
# performance-inefficient-vector-operation,
|
||||
# performance-move-const-arg,
|
||||
# performance-no-automatic-move,
|
||||
# ---
|
||||
#
|
||||
CheckOptions:
|
||||
# readability-braces-around-statements.ShortStatementLines: 2
|
||||
# readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassCase: CamelCase
|
||||
# readability-identifier-naming.StructCase: CamelCase
|
||||
# readability-identifier-naming.UnionCase: CamelCase
|
||||
# readability-identifier-naming.EnumCase: CamelCase
|
||||
# readability-identifier-naming.EnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.ScopedEnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.GlobalConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.GlobalConstantPrefix: "k"
|
||||
# readability-identifier-naming.GlobalVariableCase: CamelCase
|
||||
# readability-identifier-naming.GlobalVariablePrefix: "g"
|
||||
# readability-identifier-naming.ConstexprFunctionCase: camelBack
|
||||
# readability-identifier-naming.ConstexprMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMemberCase: camelBack
|
||||
# readability-identifier-naming.ClassConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticVariablePrefix: "k"
|
||||
# readability-identifier-naming.ConstexprVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.ConstexprVariablePrefix: "k"
|
||||
# readability-identifier-naming.LocalConstantCase: camelBack
|
||||
# readability-identifier-naming.LocalVariableCase: camelBack
|
||||
# readability-identifier-naming.TemplateParameterCase: CamelCase
|
||||
# readability-identifier-naming.ParameterCase: camelBack
|
||||
# readability-identifier-naming.FunctionCase: camelBack
|
||||
# readability-identifier-naming.MemberCase: camelBack
|
||||
# readability-identifier-naming.PrivateMemberSuffix: _
|
||||
# readability-identifier-naming.ProtectedMemberSuffix: _
|
||||
# readability-identifier-naming.PublicMemberSuffix: ""
|
||||
# readability-identifier-naming.FunctionIgnoredRegexp: ".*tag_invoke.*"
|
||||
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
|
||||
# bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
|
||||
# misc-include-cleaner.IgnoreHeaders: '.*/(detail|impl)/.*;.*(expected|unexpected).*;.*ranges_lower_bound\.h;time.h;stdlib.h;__chrono/.*;fmt/chrono.h;boost/uuid/uuid_hash.hpp'
|
||||
#
|
||||
# HeaderFilterRegex: '^.*/(src|tests)/.*\.(h|hpp)$'
|
||||
WarningsAsErrors: "*"
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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`
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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/
|
||||
@@ -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
|
||||
@@ -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/
|
||||
@@ -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
|
||||
@@ -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/
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -29,7 +29,7 @@ format:
|
||||
disable: false
|
||||
_help_line_width:
|
||||
- How wide to allow formatted cmake files
|
||||
line_width: 120
|
||||
line_width: 100
|
||||
_help_tab_size:
|
||||
- How many spaces to tab for indent
|
||||
tab_size: 4
|
||||
|
||||
56
.github/dependabot.yml
vendored
Normal file
56
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "04:00"
|
||||
timezone: Etc/GMT
|
||||
commit-message:
|
||||
prefix: "ci: [DEPENDABOT] "
|
||||
target-branch: develop
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: .github/actions/build-deps/
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "04:00"
|
||||
timezone: Etc/GMT
|
||||
commit-message:
|
||||
prefix: "ci: [DEPENDABOT] "
|
||||
target-branch: develop
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: .github/actions/generate-version/
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "04:00"
|
||||
timezone: Etc/GMT
|
||||
commit-message:
|
||||
prefix: "ci: [DEPENDABOT] "
|
||||
target-branch: develop
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: .github/actions/print-env/
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "04:00"
|
||||
timezone: Etc/GMT
|
||||
commit-message:
|
||||
prefix: "ci: [DEPENDABOT] "
|
||||
target-branch: develop
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: .github/actions/setup-conan/
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "04:00"
|
||||
timezone: Etc/GMT
|
||||
commit-message:
|
||||
prefix: "ci: [DEPENDABOT] "
|
||||
target-branch: develop
|
||||
@@ -4,14 +4,11 @@ Loop: test.jtx test.toplevel
|
||||
Loop: test.jtx test.unit_test
|
||||
test.unit_test == test.jtx
|
||||
|
||||
Loop: xrpld.app xrpld.core
|
||||
xrpld.app > xrpld.core
|
||||
|
||||
Loop: xrpld.app xrpld.overlay
|
||||
xrpld.overlay > xrpld.app
|
||||
xrpld.overlay ~= xrpld.app
|
||||
|
||||
Loop: xrpld.app xrpld.peerfinder
|
||||
xrpld.peerfinder ~= xrpld.app
|
||||
xrpld.peerfinder == xrpld.app
|
||||
|
||||
Loop: xrpld.app xrpld.rpc
|
||||
xrpld.rpc > xrpld.app
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
libxrpl.basics > xrpl.basics
|
||||
libxrpl.conditions > xrpl.basics
|
||||
libxrpl.conditions > xrpl.conditions
|
||||
libxrpl.core > xrpl.basics
|
||||
libxrpl.core > xrpl.core
|
||||
libxrpl.crypto > xrpl.basics
|
||||
@@ -17,16 +19,27 @@ libxrpl.nodestore > xrpl.protocol
|
||||
libxrpl.protocol > xrpl.basics
|
||||
libxrpl.protocol > xrpl.json
|
||||
libxrpl.protocol > xrpl.protocol
|
||||
libxrpl.rdb > xrpl.basics
|
||||
libxrpl.rdb > xrpl.rdb
|
||||
libxrpl.resource > xrpl.basics
|
||||
libxrpl.resource > xrpl.json
|
||||
libxrpl.resource > xrpl.resource
|
||||
libxrpl.server > xrpl.basics
|
||||
libxrpl.server > xrpl.json
|
||||
libxrpl.server > xrpl.protocol
|
||||
libxrpl.server > xrpl.rdb
|
||||
libxrpl.server > xrpl.server
|
||||
libxrpl.shamap > xrpl.basics
|
||||
libxrpl.shamap > xrpl.protocol
|
||||
libxrpl.shamap > xrpl.shamap
|
||||
libxrpl.tx > xrpl.basics
|
||||
libxrpl.tx > xrpl.conditions
|
||||
libxrpl.tx > xrpl.core
|
||||
libxrpl.tx > xrpl.json
|
||||
libxrpl.tx > xrpl.ledger
|
||||
libxrpl.tx > xrpl.protocol
|
||||
libxrpl.tx > xrpl.server
|
||||
libxrpl.tx > xrpl.tx
|
||||
test.app > test.jtx
|
||||
test.app > test.rpc
|
||||
test.app > test.toplevel
|
||||
@@ -41,7 +54,10 @@ test.app > xrpl.json
|
||||
test.app > xrpl.ledger
|
||||
test.app > xrpl.nodestore
|
||||
test.app > xrpl.protocol
|
||||
test.app > xrpl.rdb
|
||||
test.app > xrpl.resource
|
||||
test.app > xrpl.server
|
||||
test.app > xrpl.tx
|
||||
test.basics > test.jtx
|
||||
test.basics > test.unit_test
|
||||
test.basics > xrpl.basics
|
||||
@@ -51,7 +67,7 @@ test.basics > xrpl.json
|
||||
test.basics > xrpl.protocol
|
||||
test.beast > xrpl.basics
|
||||
test.conditions > xrpl.basics
|
||||
test.conditions > xrpld.conditions
|
||||
test.conditions > xrpl.conditions
|
||||
test.consensus > test.csf
|
||||
test.consensus > test.toplevel
|
||||
test.consensus > test.unit_test
|
||||
@@ -60,6 +76,7 @@ test.consensus > xrpld.app
|
||||
test.consensus > xrpld.consensus
|
||||
test.consensus > xrpl.json
|
||||
test.consensus > xrpl.ledger
|
||||
test.consensus > xrpl.tx
|
||||
test.core > test.jtx
|
||||
test.core > test.toplevel
|
||||
test.core > test.unit_test
|
||||
@@ -67,6 +84,7 @@ test.core > xrpl.basics
|
||||
test.core > xrpl.core
|
||||
test.core > xrpld.core
|
||||
test.core > xrpl.json
|
||||
test.core > xrpl.rdb
|
||||
test.core > xrpl.server
|
||||
test.csf > xrpl.basics
|
||||
test.csf > xrpld.consensus
|
||||
@@ -75,6 +93,7 @@ test.csf > xrpl.protocol
|
||||
test.json > test.jtx
|
||||
test.json > xrpl.json
|
||||
test.jtx > xrpl.basics
|
||||
test.jtx > xrpl.core
|
||||
test.jtx > xrpld.app
|
||||
test.jtx > xrpld.core
|
||||
test.jtx > xrpld.rpc
|
||||
@@ -84,6 +103,7 @@ test.jtx > xrpl.net
|
||||
test.jtx > xrpl.protocol
|
||||
test.jtx > xrpl.resource
|
||||
test.jtx > xrpl.server
|
||||
test.jtx > xrpl.tx
|
||||
test.ledger > test.jtx
|
||||
test.ledger > test.toplevel
|
||||
test.ledger > xrpl.basics
|
||||
@@ -95,8 +115,8 @@ test.nodestore > test.jtx
|
||||
test.nodestore > test.toplevel
|
||||
test.nodestore > test.unit_test
|
||||
test.nodestore > xrpl.basics
|
||||
test.nodestore > xrpld.core
|
||||
test.nodestore > xrpl.nodestore
|
||||
test.nodestore > xrpl.rdb
|
||||
test.overlay > test.jtx
|
||||
test.overlay > test.toplevel
|
||||
test.overlay > test.unit_test
|
||||
@@ -129,8 +149,11 @@ test.rpc > xrpld.core
|
||||
test.rpc > xrpld.overlay
|
||||
test.rpc > xrpld.rpc
|
||||
test.rpc > xrpl.json
|
||||
test.rpc > xrpl.ledger
|
||||
test.rpc > xrpl.protocol
|
||||
test.rpc > xrpl.resource
|
||||
test.rpc > xrpl.server
|
||||
test.rpc > xrpl.tx
|
||||
test.server > test.jtx
|
||||
test.server > test.toplevel
|
||||
test.server > test.unit_test
|
||||
@@ -151,40 +174,57 @@ test.unit_test > xrpl.basics
|
||||
tests.libxrpl > xrpl.basics
|
||||
tests.libxrpl > xrpl.json
|
||||
tests.libxrpl > xrpl.net
|
||||
xrpl.conditions > xrpl.basics
|
||||
xrpl.conditions > xrpl.protocol
|
||||
xrpl.core > xrpl.basics
|
||||
xrpl.core > xrpl.json
|
||||
xrpl.core > xrpl.ledger
|
||||
xrpl.core > xrpl.protocol
|
||||
xrpl.json > xrpl.basics
|
||||
xrpl.ledger > xrpl.basics
|
||||
xrpl.ledger > xrpl.protocol
|
||||
xrpl.ledger > xrpl.server
|
||||
xrpl.ledger > xrpl.shamap
|
||||
xrpl.net > xrpl.basics
|
||||
xrpl.nodestore > xrpl.basics
|
||||
xrpl.nodestore > xrpl.protocol
|
||||
xrpl.protocol > xrpl.basics
|
||||
xrpl.protocol > xrpl.json
|
||||
xrpl.rdb > xrpl.basics
|
||||
xrpl.rdb > xrpl.core
|
||||
xrpl.rdb > xrpl.protocol
|
||||
xrpl.resource > xrpl.basics
|
||||
xrpl.resource > xrpl.json
|
||||
xrpl.resource > xrpl.protocol
|
||||
xrpl.server > xrpl.basics
|
||||
xrpl.server > xrpl.core
|
||||
xrpl.server > xrpl.json
|
||||
xrpl.server > xrpl.protocol
|
||||
xrpl.server > xrpl.rdb
|
||||
xrpl.server > xrpl.resource
|
||||
xrpl.server > xrpl.shamap
|
||||
xrpl.shamap > xrpl.basics
|
||||
xrpl.shamap > xrpl.nodestore
|
||||
xrpl.shamap > xrpl.protocol
|
||||
xrpl.tx > xrpl.basics
|
||||
xrpl.tx > xrpl.core
|
||||
xrpl.tx > xrpl.ledger
|
||||
xrpl.tx > xrpl.protocol
|
||||
xrpld.app > test.unit_test
|
||||
xrpld.app > xrpl.basics
|
||||
xrpld.app > xrpl.core
|
||||
xrpld.app > xrpld.conditions
|
||||
xrpld.app > xrpld.consensus
|
||||
xrpld.app > xrpld.core
|
||||
xrpld.app > xrpl.json
|
||||
xrpld.app > xrpl.ledger
|
||||
xrpld.app > xrpl.net
|
||||
xrpld.app > xrpl.nodestore
|
||||
xrpld.app > xrpl.protocol
|
||||
xrpld.app > xrpl.rdb
|
||||
xrpld.app > xrpl.resource
|
||||
xrpld.app > xrpl.server
|
||||
xrpld.app > xrpl.shamap
|
||||
xrpld.conditions > xrpl.basics
|
||||
xrpld.conditions > xrpl.protocol
|
||||
xrpld.app > xrpl.tx
|
||||
xrpld.consensus > xrpl.basics
|
||||
xrpld.consensus > xrpl.json
|
||||
xrpld.consensus > xrpl.protocol
|
||||
@@ -193,17 +233,21 @@ xrpld.core > xrpl.core
|
||||
xrpld.core > xrpl.json
|
||||
xrpld.core > xrpl.net
|
||||
xrpld.core > xrpl.protocol
|
||||
xrpld.core > xrpl.rdb
|
||||
xrpld.overlay > xrpl.basics
|
||||
xrpld.overlay > xrpl.core
|
||||
xrpld.overlay > xrpld.core
|
||||
xrpld.overlay > xrpld.peerfinder
|
||||
xrpld.overlay > xrpl.json
|
||||
xrpld.overlay > xrpl.protocol
|
||||
xrpld.overlay > xrpl.rdb
|
||||
xrpld.overlay > xrpl.resource
|
||||
xrpld.overlay > xrpl.server
|
||||
xrpld.overlay > xrpl.tx
|
||||
xrpld.peerfinder > xrpl.basics
|
||||
xrpld.peerfinder > xrpld.core
|
||||
xrpld.peerfinder > xrpl.protocol
|
||||
xrpld.peerfinder > xrpl.rdb
|
||||
xrpld.perflog > xrpl.basics
|
||||
xrpld.perflog > xrpl.core
|
||||
xrpld.perflog > xrpld.rpc
|
||||
@@ -216,6 +260,8 @@ xrpld.rpc > xrpl.ledger
|
||||
xrpld.rpc > xrpl.net
|
||||
xrpld.rpc > xrpl.nodestore
|
||||
xrpld.rpc > xrpl.protocol
|
||||
xrpld.rpc > xrpl.rdb
|
||||
xrpld.rpc > xrpl.resource
|
||||
xrpld.rpc > xrpl.server
|
||||
xrpld.rpc > xrpl.tx
|
||||
xrpld.shamap > xrpl.shamap
|
||||
|
||||
28
.github/scripts/strategy-matrix/generate.py
vendored
28
.github/scripts/strategy-matrix/generate.py
vendored
@@ -32,10 +32,13 @@ We will further set additional CMake arguments as follows:
|
||||
"""
|
||||
|
||||
|
||||
def generate_strategy_matrix(all: bool, config: Config) -> list:
|
||||
def generate_strategy_matrix(all: bool, config: Config, distro: str = "") -> list:
|
||||
configurations = []
|
||||
os_entries = config.os
|
||||
if distro:
|
||||
os_entries = [o for o in os_entries if o["distro_name"] == distro]
|
||||
for architecture, os, build_type, cmake_args in itertools.product(
|
||||
config.architecture, config.os, config.build_type, config.cmake_args
|
||||
config.architecture, os_entries, 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.
|
||||
@@ -223,7 +226,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
|
||||
if (n := os["compiler_version"]) != "":
|
||||
config_name += f"-{n}"
|
||||
config_name += (
|
||||
f"-{architecture['platform'][architecture['platform'].find('/')+1:]}"
|
||||
f"-{architecture['platform'][architecture['platform'].find('/') + 1 :]}"
|
||||
)
|
||||
config_name += f"-{build_type.lower()}"
|
||||
if "-Dcoverage=ON" in cmake_args:
|
||||
@@ -313,21 +316,32 @@ if __name__ == "__main__":
|
||||
required=False,
|
||||
type=Path,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--distro",
|
||||
help="Filter OS entries to only include those with this distro_name (e.g. 'debian', 'rhel', 'ubuntu').",
|
||||
required=False,
|
||||
type=str,
|
||||
default="",
|
||||
)
|
||||
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")
|
||||
args.all, read_config(THIS_DIR / "linux.json"), args.distro
|
||||
)
|
||||
matrix += generate_strategy_matrix(
|
||||
args.all, read_config(THIS_DIR / "macos.json")
|
||||
args.all, read_config(THIS_DIR / "macos.json"), args.distro
|
||||
)
|
||||
matrix += generate_strategy_matrix(
|
||||
args.all, read_config(THIS_DIR / "windows.json")
|
||||
args.all, read_config(THIS_DIR / "windows.json"), args.distro
|
||||
)
|
||||
else:
|
||||
matrix += generate_strategy_matrix(args.all, read_config(args.config))
|
||||
matrix += generate_strategy_matrix(
|
||||
args.all, read_config(args.config), args.distro
|
||||
)
|
||||
|
||||
# Generate the strategy matrix.
|
||||
print(f"matrix={json.dumps({'include': matrix})}")
|
||||
# print(json.dumps(matrix, indent=2))
|
||||
|
||||
32
.github/workflows/on-pr.yml
vendored
32
.github/workflows/on-pr.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
# 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
|
||||
uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4
|
||||
with:
|
||||
files: |
|
||||
# These paths are unique to `on-pr.yml`.
|
||||
@@ -65,9 +65,12 @@ jobs:
|
||||
.github/workflows/reusable-build.yml
|
||||
.github/workflows/reusable-build-test-config.yml
|
||||
.github/workflows/reusable-build-test.yml
|
||||
.github/workflows/reusable-clang-tidy.yml
|
||||
.github/workflows/reusable-clang-tidy-files.yml
|
||||
.github/workflows/reusable-strategy-matrix.yml
|
||||
.github/workflows/reusable-test.yml
|
||||
.github/workflows/reusable-upload-recipe.yml
|
||||
.clang-tidy
|
||||
.codecov.yml
|
||||
cmake/**
|
||||
conan/**
|
||||
@@ -107,6 +110,17 @@ jobs:
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
uses: ./.github/workflows/reusable-check-rename.yml
|
||||
|
||||
clang-tidy:
|
||||
needs: should-run
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
uses: ./.github/workflows/reusable-clang-tidy.yml
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
with:
|
||||
check_only_changed: true
|
||||
create_issue_on_failure: false
|
||||
|
||||
build-test:
|
||||
needs: should-run
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
@@ -114,12 +128,23 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [linux, macos, windows]
|
||||
include:
|
||||
- os: linux
|
||||
distro: debian
|
||||
- os: linux
|
||||
distro: rhel
|
||||
- os: linux
|
||||
distro: ubuntu
|
||||
- os: macos
|
||||
distro: ""
|
||||
- os: windows
|
||||
distro: ""
|
||||
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 }}
|
||||
distro: ${{ matrix.distro }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -156,6 +181,7 @@ jobs:
|
||||
needs:
|
||||
- check-levelization
|
||||
- check-rename
|
||||
- clang-tidy
|
||||
- build-test
|
||||
- upload-recipe
|
||||
- notify-clio
|
||||
|
||||
25
.github/workflows/on-trigger.yml
vendored
25
.github/workflows/on-trigger.yml
vendored
@@ -22,9 +22,12 @@ on:
|
||||
- ".github/workflows/reusable-build.yml"
|
||||
- ".github/workflows/reusable-build-test-config.yml"
|
||||
- ".github/workflows/reusable-build-test.yml"
|
||||
- ".github/workflows/reusable-clang-tidy.yml"
|
||||
- ".github/workflows/reusable-clang-tidy-files.yml"
|
||||
- ".github/workflows/reusable-strategy-matrix.yml"
|
||||
- ".github/workflows/reusable-test.yml"
|
||||
- ".github/workflows/reusable-upload-recipe.yml"
|
||||
- ".clang-tidy"
|
||||
- ".codecov.yml"
|
||||
- "cmake/**"
|
||||
- "conan/**"
|
||||
@@ -60,12 +63,31 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
clang-tidy:
|
||||
uses: ./.github/workflows/reusable-clang-tidy.yml
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
with:
|
||||
check_only_changed: false
|
||||
create_issue_on_failure: ${{ github.event_name == 'schedule' }}
|
||||
|
||||
build-test:
|
||||
uses: ./.github/workflows/reusable-build-test.yml
|
||||
strategy:
|
||||
fail-fast: ${{ github.event_name == 'merge_group' }}
|
||||
matrix:
|
||||
os: [linux, macos, windows]
|
||||
include:
|
||||
- os: linux
|
||||
distro: debian
|
||||
- os: linux
|
||||
distro: rhel
|
||||
- os: linux
|
||||
distro: ubuntu
|
||||
- os: macos
|
||||
distro: ""
|
||||
- os: windows
|
||||
distro: ""
|
||||
with:
|
||||
# Enable ccache only for events targeting the XRPLF repository, since
|
||||
# other accounts will not have access to our remote cache storage.
|
||||
@@ -74,6 +96,7 @@ jobs:
|
||||
# not identical to a regular compilation.
|
||||
ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release') }}
|
||||
os: ${{ matrix.os }}
|
||||
distro: ${{ matrix.distro }}
|
||||
strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
4
.github/workflows/pre-commit.yml
vendored
4
.github/workflows/pre-commit.yml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
|
||||
run-hooks:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@320be44621ca2a080f05aeb15817c44b84518108
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@56de1bdf19639e009639a50b8d17c28ca954f267
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-ab4d1f0" }'
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }'
|
||||
|
||||
20
.github/workflows/publish-docs.yml
vendored
20
.github/workflows/publish-docs.yml
vendored
@@ -4,6 +4,18 @@ name: Build and publish documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "release*"
|
||||
paths:
|
||||
- ".github/workflows/publish-docs.yml"
|
||||
- "*.md"
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
- "include/**"
|
||||
- "src/libxrpl/**"
|
||||
- "src/xrpld/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/publish-docs.yml"
|
||||
- "*.md"
|
||||
@@ -23,7 +35,9 @@ defaults:
|
||||
|
||||
env:
|
||||
BUILD_DIR: build
|
||||
NPROC_SUBTRACT: 2
|
||||
# ubuntu-latest has only 2 CPUs for private repositories
|
||||
# https://docs.github.com/en/actions/reference/runners/github-hosted-runners#standard-github-hosted-runners-for--private-repositories
|
||||
NPROC_SUBTRACT: ${{ github.event.repository.private && '1' || '2' }}
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
@@ -33,7 +47,7 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
@@ -65,7 +79,7 @@ jobs:
|
||||
cmake --build . --target docs --parallel ${BUILD_NPROC}
|
||||
|
||||
- name: Publish documentation
|
||||
if: ${{ github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }}
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
23
.github/workflows/reusable-build-test-config.yml
vendored
23
.github/workflows/reusable-build-test-config.yml
vendored
@@ -101,10 +101,10 @@ jobs:
|
||||
steps:
|
||||
- name: Cleanup workspace (macOS and Windows)
|
||||
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
||||
uses: XRPLF/actions/cleanup-workspace@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d
|
||||
@@ -177,7 +177,7 @@ jobs:
|
||||
|
||||
- name: Upload the binary (Linux)
|
||||
if: ${{ github.repository_owner == 'XRPLF' && runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: xrpld-${{ inputs.config_name }}
|
||||
path: ${{ env.BUILD_DIR }}/xrpld
|
||||
@@ -229,8 +229,21 @@ jobs:
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
run: |
|
||||
./xrpld --unittest --unittest-jobs "${BUILD_NPROC}"
|
||||
set -o pipefail
|
||||
./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
|
||||
|
||||
- name: Show test failure summary
|
||||
if: ${{ failure() && !inputs.build_only }}
|
||||
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
|
||||
run: |
|
||||
if [ ! -f unittest.log ]; then
|
||||
echo "unittest.log not found; embedded tests may not have run."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! grep -E "failed" unittest.log; then
|
||||
echo "Log present but no failure lines found in unittest.log."
|
||||
fi
|
||||
- name: Debug failure (Linux)
|
||||
if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }}
|
||||
run: |
|
||||
@@ -254,7 +267,7 @@ jobs:
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
|
||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
||||
with:
|
||||
disable_search: true
|
||||
disable_telem: true
|
||||
|
||||
8
.github/workflows/reusable-build-test.yml
vendored
8
.github/workflows/reusable-build-test.yml
vendored
@@ -26,6 +26,12 @@ on:
|
||||
type: string
|
||||
default: "minimal"
|
||||
|
||||
distro:
|
||||
description: 'Filter to only include configs for this distro (e.g. "debian", "rhel", "ubuntu"). Leave empty for no filtering.'
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
secrets:
|
||||
CODECOV_TOKEN:
|
||||
description: "The Codecov token to use for uploading coverage reports."
|
||||
@@ -38,9 +44,11 @@ jobs:
|
||||
with:
|
||||
os: ${{ inputs.os }}
|
||||
strategy_matrix: ${{ inputs.strategy_matrix }}
|
||||
distro: ${{ inputs.distro }}
|
||||
|
||||
# Build and test the binary for each configuration.
|
||||
build-test-config:
|
||||
name: ${{ matrix.config_name }}
|
||||
needs:
|
||||
- generate-matrix
|
||||
uses: ./.github/workflows/reusable-build-test-config.yml
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Check levelization
|
||||
run: .github/scripts/levelization/generate.sh
|
||||
- name: Check for differences
|
||||
|
||||
2
.github/workflows/reusable-check-rename.yml
vendored
2
.github/workflows/reusable-check-rename.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Check definitions
|
||||
run: .github/scripts/rename/definitions.sh .
|
||||
- name: Check copyright notices
|
||||
|
||||
162
.github/workflows/reusable-clang-tidy-files.yml
vendored
Normal file
162
.github/workflows/reusable-clang-tidy-files.yml
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
name: Run clang-tidy on files
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
files:
|
||||
description: "List of files to check (empty means check all files)"
|
||||
type: string
|
||||
default: ""
|
||||
create_issue_on_failure:
|
||||
description: "Whether to create an issue if the check failed"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
# Conan installs the generators in the build/generators directory, see the
|
||||
# layout() method in conanfile.py. We then run CMake from the build directory.
|
||||
BUILD_DIR: build
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
run-clang-tidy:
|
||||
name: Run clang tidy
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/ci/debian-trixie:clang-21-sha-53033a2"
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
- name: Print build environment
|
||||
uses: ./.github/actions/print-env
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
id: nproc
|
||||
|
||||
- name: Setup Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
|
||||
- name: Build dependencies
|
||||
uses: ./.github/actions/build-deps
|
||||
with:
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ env.BUILD_TYPE }}
|
||||
log_verbosity: verbose
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
cmake \
|
||||
-G 'Ninja' \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||
-Dtests=ON \
|
||||
-Dwerr=ON \
|
||||
-Dxrpld=ON \
|
||||
..
|
||||
|
||||
# clang-tidy needs headers generated from proto files
|
||||
- name: Build libxrpl.libpb
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
ninja -j ${{ steps.nproc.outputs.nproc }} xrpl.libpb
|
||||
|
||||
- name: Run clang tidy
|
||||
id: run_clang_tidy
|
||||
continue-on-error: true
|
||||
env:
|
||||
TARGETS: ${{ inputs.files != '' && inputs.files || 'src tests' }}
|
||||
run: |
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" ${TARGETS} 2>&1 | tee clang-tidy-output.txt
|
||||
|
||||
- name: Upload clang-tidy output
|
||||
if: steps.run_clang_tidy.outcome != 'success'
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: clang-tidy-results
|
||||
path: clang-tidy-output.txt
|
||||
retention-days: 30
|
||||
|
||||
- name: Create an issue
|
||||
if: steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure
|
||||
id: create_issue
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
# Prepare issue body with clang-tidy output
|
||||
cat > issue.md <<EOF
|
||||
## Clang-tidy Check Failed
|
||||
|
||||
**Workflow:** ${{ github.workflow }}
|
||||
**Run ID:** ${{ github.run_id }}
|
||||
**Commit:** ${{ github.sha }}
|
||||
**Branch/Ref:** ${{ github.ref }}
|
||||
**Triggered by:** ${{ github.actor }}
|
||||
|
||||
### Clang-tidy Output:
|
||||
\`\`\`
|
||||
EOF
|
||||
|
||||
# Append clang-tidy output (filter for errors and warnings)
|
||||
if [ -f clang-tidy-output.txt ]; then
|
||||
# Extract lines containing 'error:', 'warning:', or 'note:'
|
||||
grep -E '(error:|warning:|note:)' clang-tidy-output.txt > filtered-output.txt || true
|
||||
|
||||
# If filtered output is empty, use original (might be a different error format)
|
||||
if [ ! -s filtered-output.txt ]; then
|
||||
cp clang-tidy-output.txt filtered-output.txt
|
||||
fi
|
||||
|
||||
# Truncate if too large
|
||||
head -c 60000 filtered-output.txt >> issue.md
|
||||
if [ "$(wc -c < filtered-output.txt)" -gt 60000 ]; then
|
||||
echo "" >> issue.md
|
||||
echo "... (output truncated, see artifacts for full output)" >> issue.md
|
||||
fi
|
||||
|
||||
rm filtered-output.txt
|
||||
else
|
||||
echo "No output file found" >> issue.md
|
||||
fi
|
||||
|
||||
cat >> issue.md <<EOF
|
||||
\`\`\`
|
||||
|
||||
**Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
|
||||
---
|
||||
*This issue was automatically created by the clang-tidy workflow.*
|
||||
EOF
|
||||
|
||||
# Create the issue
|
||||
gh issue create \
|
||||
--label "Bug,Clang-tidy" \
|
||||
--title "Clang-tidy check failed" \
|
||||
--body-file ./issue.md \
|
||||
> create_issue.log
|
||||
|
||||
created_issue="$(sed 's|.*/||' create_issue.log)"
|
||||
echo "created_issue=$created_issue" >> $GITHUB_OUTPUT
|
||||
echo "Created issue #$created_issue"
|
||||
|
||||
rm -f create_issue.log issue.md clang-tidy-output.txt
|
||||
|
||||
- name: Fail the workflow if clang-tidy failed
|
||||
if: steps.run_clang_tidy.outcome != 'success'
|
||||
run: |
|
||||
echo "Clang-tidy check failed!"
|
||||
exit 1
|
||||
55
.github/workflows/reusable-clang-tidy.yml
vendored
Normal file
55
.github/workflows/reusable-clang-tidy.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: Clang-tidy check
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
check_only_changed:
|
||||
description: "Check only changed files in PR. If false, checks all files in the repository."
|
||||
type: boolean
|
||||
default: false
|
||||
create_issue_on_failure:
|
||||
description: "Whether to create an issue if the check failed"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
determine-files:
|
||||
name: Determine files to check
|
||||
if: ${{ inputs.check_only_changed }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
clang_tidy_config_changed: ${{ steps.changed_clang_tidy.outputs.any_changed }}
|
||||
any_cpp_changed: ${{ steps.changed_files.outputs.any_changed }}
|
||||
all_changed_files: ${{ steps.changed_files.outputs.all_changed_files }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Get changed C++ files
|
||||
id: changed_files
|
||||
uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4
|
||||
with:
|
||||
files: |
|
||||
**/*.cpp
|
||||
**/*.h
|
||||
**/*.ipp
|
||||
separator: " "
|
||||
|
||||
- name: Get changed clang-tidy configuration
|
||||
id: changed_clang_tidy
|
||||
uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4
|
||||
with:
|
||||
files: |
|
||||
.clang-tidy
|
||||
|
||||
run-clang-tidy:
|
||||
needs: [determine-files]
|
||||
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
|
||||
uses: ./.github/workflows/reusable-clang-tidy-files.yml
|
||||
with:
|
||||
files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '') || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }}
|
||||
create_issue_on_failure: ${{ inputs.create_issue_on_failure }}
|
||||
12
.github/workflows/reusable-strategy-matrix.yml
vendored
12
.github/workflows/reusable-strategy-matrix.yml
vendored
@@ -13,6 +13,11 @@ on:
|
||||
required: false
|
||||
type: string
|
||||
default: "minimal"
|
||||
distro:
|
||||
description: 'Filter to only include configs for this distro (e.g. "debian", "rhel", "ubuntu"). Leave empty for no filtering.'
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
outputs:
|
||||
matrix:
|
||||
description: "The generated strategy matrix."
|
||||
@@ -29,10 +34,10 @@ jobs:
|
||||
matrix: ${{ steps.generate.outputs.matrix }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: 3.13
|
||||
|
||||
@@ -42,4 +47,5 @@ jobs:
|
||||
env:
|
||||
GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }}
|
||||
GENERATE_OPTION: ${{ inputs.strategy_matrix == 'all' && '--all' || '' }}
|
||||
run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} >> "${GITHUB_OUTPUT}"
|
||||
GENERATE_DISTRO: ${{ inputs.distro != '' && format('--distro={0}', inputs.distro) || '' }}
|
||||
run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} ${GENERATE_DISTRO} >> "${GITHUB_OUTPUT}"
|
||||
|
||||
2
.github/workflows/reusable-upload-recipe.yml
vendored
2
.github/workflows/reusable-upload-recipe.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Generate build version number
|
||||
id: version
|
||||
|
||||
4
.github/workflows/upload-conan-deps.yml
vendored
4
.github/workflows/upload-conan-deps.yml
vendored
@@ -64,10 +64,10 @@ jobs:
|
||||
steps:
|
||||
- name: Cleanup workspace (macOS and Windows)
|
||||
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
||||
uses: XRPLF/actions/cleanup-workspace@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d
|
||||
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -42,6 +42,9 @@ gmon.out
|
||||
# Locally patched Conan recipes
|
||||
external/conan-center-index/
|
||||
|
||||
# Local conan directory
|
||||
.conan
|
||||
|
||||
# XCode IDE.
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
@@ -69,3 +72,11 @@ DerivedData
|
||||
|
||||
# AI tools.
|
||||
/.augment
|
||||
/.claude
|
||||
/CLAUDE.md
|
||||
|
||||
# Direnv's directory
|
||||
/.direnv
|
||||
|
||||
# clangd cache
|
||||
/.cache
|
||||
|
||||
@@ -20,7 +20,7 @@ repos:
|
||||
args: [--assume-in-merge]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: 7d85583be209cb547946c82fbe51f4bc5dd1d017 # frozen: v18.1.8
|
||||
rev: 75ca4ad908dc4a99f57921f29b7e6c1521e10b26 # frozen: v21.1.8
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [--style=file]
|
||||
@@ -57,6 +57,24 @@ repos:
|
||||
- .git/COMMIT_EDITMSG
|
||||
stages: [commit-msg]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: nix-fmt
|
||||
name: Format Nix files
|
||||
entry: |
|
||||
bash -c '
|
||||
if command -v nix &> /dev/null || [ "$GITHUB_ACTIONS" = "true" ]; then
|
||||
nix --extra-experimental-features "nix-command flakes" fmt "$@"
|
||||
else
|
||||
echo "Skipping nix-fmt: nix not installed and not in GitHub Actions"
|
||||
exit 0
|
||||
fi
|
||||
' --
|
||||
language: system
|
||||
types:
|
||||
- nix
|
||||
pass_filenames: true
|
||||
|
||||
exclude: |
|
||||
(?x)^(
|
||||
external/.*|
|
||||
|
||||
@@ -17,6 +17,7 @@ project(xrpl)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
include(CompilationEnv)
|
||||
|
||||
@@ -38,16 +39,16 @@ include(Ccache)
|
||||
# make GIT_COMMIT_HASH define available to all sources
|
||||
find_package(Git)
|
||||
if (Git_FOUND)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse HEAD
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse
|
||||
HEAD OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch)
|
||||
if (gch)
|
||||
set(GIT_COMMIT_HASH "${gch}")
|
||||
message(STATUS gch: ${GIT_COMMIT_HASH})
|
||||
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
|
||||
endif ()
|
||||
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse --abbrev-ref HEAD
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse
|
||||
--abbrev-ref HEAD OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb)
|
||||
if (gb)
|
||||
set(GIT_BRANCH "${gb}")
|
||||
message(STATUS gb: ${GIT_BRANCH})
|
||||
@@ -67,7 +68,8 @@ include(FetchContent)
|
||||
include(ExternalProject)
|
||||
include(CMakeFuncs) # must come *after* ExternalProject b/c it overrides one function in EP
|
||||
if (target)
|
||||
message(FATAL_ERROR "The target option has been removed - use native cmake options to control build")
|
||||
message(FATAL_ERROR "The target option has been removed - use native cmake options to control build"
|
||||
)
|
||||
endif ()
|
||||
|
||||
include(XrplSanity)
|
||||
@@ -76,7 +78,8 @@ include(XrplSettings)
|
||||
# this check has to remain in the top-level cmake because of the early return statement
|
||||
if (packages_only)
|
||||
if (NOT TARGET rpm)
|
||||
message(FATAL_ERROR "packages_only requested, but targets were not created - is docker installed?")
|
||||
message(FATAL_ERROR "packages_only requested, but targets were not created - is docker installed?"
|
||||
)
|
||||
endif ()
|
||||
return()
|
||||
endif ()
|
||||
@@ -118,7 +121,8 @@ target_link_libraries(
|
||||
option(rocksdb "Enable RocksDB" ON)
|
||||
if (rocksdb)
|
||||
find_package(RocksDB REQUIRED)
|
||||
set_target_properties(RocksDB::rocksdb PROPERTIES INTERFACE_COMPILE_DEFINITIONS XRPL_ROCKSDB_AVAILABLE=1)
|
||||
set_target_properties(RocksDB::rocksdb PROPERTIES INTERFACE_COMPILE_DEFINITIONS
|
||||
XRPL_ROCKSDB_AVAILABLE=1)
|
||||
target_link_libraries(xrpl_libs INTERFACE RocksDB::rocksdb)
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ coherent rather than a set of _thou shalt not_ commandments.
|
||||
|
||||
## Formatting
|
||||
|
||||
All code must conform to `clang-format` version 18,
|
||||
All code must conform to `clang-format` version 21,
|
||||
according to the settings in [`.clang-format`](./.clang-format),
|
||||
unless the result would be unreasonably difficult to read or maintain.
|
||||
To demarcate lines that should be left as-is, surround them with comments like
|
||||
@@ -251,6 +251,29 @@ pip3 install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
## Clang-tidy
|
||||
|
||||
All code must pass `clang-tidy` checks according to the settings in [`.clang-tidy`](./.clang-tidy).
|
||||
|
||||
There is a Continuous Integration job that runs clang-tidy on pull requests. The CI will check:
|
||||
|
||||
- All changed C++ files (`.cpp`, `.h`, `.ipp`) when only code files are modified
|
||||
- **All files in the repository** when the `.clang-tidy` configuration file is changed
|
||||
|
||||
This ensures that configuration changes don't introduce new warnings across the codebase.
|
||||
|
||||
### Running clang-tidy locally
|
||||
|
||||
Before running clang-tidy, you must build the project to generate required files (particularly protobuf headers). Refer to [`BUILD.md`](./BUILD.md) for build instructions.
|
||||
|
||||
Then run clang-tidy on your local changes:
|
||||
|
||||
```
|
||||
run-clang-tidy -p build src tests
|
||||
```
|
||||
|
||||
This will check all source files in the `src` and `tests` directories using the compile commands from your `build` directory.
|
||||
|
||||
## Contracts and instrumentation
|
||||
|
||||
We are using [Antithesis](https://antithesis.com/) for continuous fuzzing,
|
||||
|
||||
@@ -43,7 +43,8 @@ set(CMAKE_VS_GLOBALS "CLToolExe=cl.exe" "CLToolPath=${CMAKE_BINARY_DIR}" "TrackF
|
||||
# By default Visual Studio generators will use /Zi to capture debug information, which is not compatible with ccache, so
|
||||
# tell it to use /Z7 instead.
|
||||
if (MSVC)
|
||||
foreach (var_ CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE)
|
||||
foreach (var_ CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_RELEASE)
|
||||
string(REPLACE "/Zi" "/Z7" ${var_} "${${var_}}")
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
@@ -180,7 +180,8 @@ elseif (DEFINED ENV{CODE_COVERAGE_GCOV_TOOL})
|
||||
set(GCOV_TOOL "$ENV{CODE_COVERAGE_GCOV_TOOL}")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||
if (APPLE)
|
||||
execute_process(COMMAND xcrun -f llvm-cov OUTPUT_VARIABLE LLVMCOV_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND xcrun -f llvm-cov OUTPUT_VARIABLE LLVMCOV_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
else ()
|
||||
find_program(LLVMCOV_PATH llvm-cov)
|
||||
endif ()
|
||||
@@ -199,8 +200,8 @@ foreach (LANG ${LANGUAGES})
|
||||
if ("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
|
||||
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
||||
endif ()
|
||||
elseif (NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU" AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES
|
||||
"(LLVM)?[Ff]lang")
|
||||
elseif (NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU" AND NOT "${CMAKE_${LANG}_COMPILER_ID}"
|
||||
MATCHES "(LLVM)?[Ff]lang")
|
||||
message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...")
|
||||
endif ()
|
||||
endforeach ()
|
||||
@@ -321,14 +322,16 @@ function (setup_target_for_coverage_gcovr)
|
||||
endif ()
|
||||
|
||||
if ("--output" IN_LIST GCOVR_ADDITIONAL_ARGS)
|
||||
message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting...")
|
||||
message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting..."
|
||||
)
|
||||
else ()
|
||||
if ((Coverage_FORMAT STREQUAL "html-details") OR (Coverage_FORMAT STREQUAL "html-nested"))
|
||||
set(GCOVR_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html)
|
||||
set(GCOVR_CREATE_FOLDER ${PROJECT_BINARY_DIR}/${Coverage_NAME})
|
||||
elseif (Coverage_FORMAT STREQUAL "html-single")
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.html)
|
||||
elseif ((Coverage_FORMAT STREQUAL "json-summary") OR (Coverage_FORMAT STREQUAL "json-details")
|
||||
elseif ((Coverage_FORMAT STREQUAL "json-summary") OR (Coverage_FORMAT STREQUAL
|
||||
"json-details")
|
||||
OR (Coverage_FORMAT STREQUAL "coveralls"))
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.json)
|
||||
elseif (Coverage_FORMAT STREQUAL "txt")
|
||||
@@ -452,8 +455,10 @@ function (setup_target_for_coverage_gcovr)
|
||||
COMMENT "Running gcovr to produce code coverage report.")
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD COMMAND echo
|
||||
COMMENT "Code coverage report saved in ${GCOVR_OUTPUT_FILE} formatted as ${Coverage_FORMAT}")
|
||||
add_custom_command(
|
||||
TARGET ${Coverage_NAME} POST_BUILD COMMAND echo
|
||||
COMMENT "Code coverage report saved in ${GCOVR_OUTPUT_FILE} formatted as ${Coverage_FORMAT}"
|
||||
)
|
||||
endfunction () # setup_target_for_coverage_gcovr
|
||||
|
||||
function (add_code_coverage_to_target name scope)
|
||||
@@ -463,14 +468,10 @@ function (add_code_coverage_to_target name scope)
|
||||
separate_arguments(COVERAGE_C_LINKER_FLAGS NATIVE_COMMAND "${COVERAGE_C_LINKER_FLAGS}")
|
||||
|
||||
# Add compiler options to the target
|
||||
target_compile_options(${name} ${scope} $<$<COMPILE_LANGUAGE:CXX>:${COVERAGE_CXX_COMPILER_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:C>:${COVERAGE_C_COMPILER_FLAGS}>)
|
||||
target_compile_options(
|
||||
${name} ${scope} $<$<COMPILE_LANGUAGE:CXX>:${COVERAGE_CXX_COMPILER_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:C>:${COVERAGE_C_COMPILER_FLAGS}>)
|
||||
|
||||
target_link_libraries(
|
||||
${name}
|
||||
${scope}
|
||||
$<$<LINK_LANGUAGE:CXX>:${COVERAGE_CXX_LINKER_FLAGS}
|
||||
gcov>
|
||||
$<$<LINK_LANGUAGE:C>:${COVERAGE_C_LINKER_FLAGS}
|
||||
gcov>)
|
||||
target_link_libraries(${name} ${scope} $<$<LINK_LANGUAGE:CXX>:${COVERAGE_CXX_LINKER_FLAGS}>
|
||||
$<$<LINK_LANGUAGE:C>:${COVERAGE_C_LINKER_FLAGS}>)
|
||||
endfunction () # add_code_coverage_to_target
|
||||
|
||||
@@ -17,7 +17,8 @@ link_libraries(Xrpl::common)
|
||||
if (NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif ()
|
||||
set_target_properties(common PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE})
|
||||
set_target_properties(common PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE
|
||||
${CMAKE_POSITION_INDEPENDENT_CODE})
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
target_compile_definitions(
|
||||
common
|
||||
@@ -37,7 +38,8 @@ if (MSVC)
|
||||
# remove existing exception flag since we set it to -EHa
|
||||
string(REGEX REPLACE "[-/]EH[a-z]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
foreach (var_ CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE)
|
||||
foreach (var_ CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_RELEASE)
|
||||
|
||||
# also remove dynamic runtime
|
||||
string(REGEX REPLACE "[-/]MD[d]*" " " ${var_} "${${var_}}")
|
||||
@@ -143,20 +145,23 @@ if (voidstar)
|
||||
elseif (NOT is_linux)
|
||||
message(FATAL_ERROR "Antithesis instrumentation requires Linux, aborting...")
|
||||
elseif (NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0))
|
||||
message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting...")
|
||||
message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting..."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (use_mold)
|
||||
# use mold linker if available
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=mold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=mold -Wl,--version ERROR_QUIET
|
||||
OUTPUT_VARIABLE LD_VERSION)
|
||||
if ("${LD_VERSION}" MATCHES "mold")
|
||||
target_link_libraries(common INTERFACE -fuse-ld=mold)
|
||||
endif ()
|
||||
unset(LD_VERSION)
|
||||
elseif (use_gold AND is_gcc)
|
||||
# use gold linker if available
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET
|
||||
OUTPUT_VARIABLE LD_VERSION)
|
||||
#[=========================================================[
|
||||
NOTE: THE gold linker inserts -rpath as DT_RUNPATH by
|
||||
default instead of DT_RPATH, so you might have slightly
|
||||
@@ -186,7 +191,8 @@ elseif (use_gold AND is_gcc)
|
||||
unset(LD_VERSION)
|
||||
elseif (use_lld)
|
||||
# use lld linker if available
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=lld -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=lld -Wl,--version ERROR_QUIET
|
||||
OUTPUT_VARIABLE LD_VERSION)
|
||||
if ("${LD_VERSION}" MATCHES "LLD")
|
||||
target_link_libraries(common INTERFACE -fuse-ld=lld)
|
||||
endif ()
|
||||
|
||||
@@ -14,7 +14,8 @@ target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp IMPORT_DIRS include/x
|
||||
PROTOS include/xrpl/proto/xrpl.proto)
|
||||
|
||||
file(GLOB_RECURSE protos "include/xrpl/proto/org/*.proto")
|
||||
target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp IMPORT_DIRS include/xrpl/proto PROTOS "${protos}")
|
||||
target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp IMPORT_DIRS include/xrpl/proto
|
||||
PROTOS "${protos}")
|
||||
target_protobuf_sources(
|
||||
xrpl.libpb xrpl/proto
|
||||
LANGUAGE grpc
|
||||
@@ -24,8 +25,9 @@ target_protobuf_sources(
|
||||
GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc)
|
||||
|
||||
target_compile_options(
|
||||
xrpl.libpb PUBLIC $<$<BOOL:${is_msvc}>:-wd4996> $<$<BOOL:${is_xcode}>: --system-header-prefix="google/protobuf"
|
||||
-Wno-deprecated-dynamic-exception-spec >
|
||||
xrpl.libpb
|
||||
PUBLIC $<$<BOOL:${is_msvc}>:-wd4996> $<$<BOOL:${is_xcode}>:
|
||||
--system-header-prefix="google/protobuf" -Wno-deprecated-dynamic-exception-spec >
|
||||
PRIVATE $<$<BOOL:${is_msvc}>:-wd4065> $<$<NOT:$<BOOL:${is_msvc}>>:-Wno-deprecated-declarations>)
|
||||
|
||||
target_link_libraries(xrpl.libpb PUBLIC protobuf::libprotobuf gRPC::grpc++)
|
||||
@@ -73,7 +75,8 @@ target_link_libraries(xrpl.libxrpl.protocol PUBLIC xrpl.libxrpl.crypto xrpl.libx
|
||||
|
||||
# Level 05
|
||||
add_module(xrpl core)
|
||||
target_link_libraries(xrpl.libxrpl.core PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol)
|
||||
target_link_libraries(xrpl.libxrpl.core PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol)
|
||||
|
||||
# Level 06
|
||||
add_module(xrpl resource)
|
||||
@@ -81,21 +84,40 @@ target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol)
|
||||
|
||||
# Level 07
|
||||
add_module(xrpl net)
|
||||
target_link_libraries(xrpl.libxrpl.net PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.resource)
|
||||
|
||||
add_module(xrpl server)
|
||||
target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol)
|
||||
target_link_libraries(xrpl.libxrpl.net PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol xrpl.libxrpl.resource)
|
||||
|
||||
add_module(xrpl nodestore)
|
||||
target_link_libraries(xrpl.libxrpl.nodestore PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol)
|
||||
target_link_libraries(xrpl.libxrpl.nodestore PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol)
|
||||
|
||||
add_module(xrpl shamap)
|
||||
target_link_libraries(xrpl.libxrpl.shamap PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.crypto xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.nodestore)
|
||||
target_link_libraries(xrpl.libxrpl.shamap PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.crypto
|
||||
xrpl.libxrpl.protocol xrpl.libxrpl.nodestore)
|
||||
|
||||
add_module(xrpl rdb)
|
||||
target_link_libraries(xrpl.libxrpl.rdb PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.core)
|
||||
|
||||
add_module(xrpl server)
|
||||
target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol xrpl.libxrpl.core
|
||||
xrpl.libxrpl.rdb xrpl.libxrpl.resource)
|
||||
|
||||
add_module(xrpl conditions)
|
||||
target_link_libraries(xrpl.libxrpl.conditions PUBLIC xrpl.libxrpl.server)
|
||||
|
||||
add_module(xrpl ledger)
|
||||
target_link_libraries(xrpl.libxrpl.ledger PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol)
|
||||
target_link_libraries(
|
||||
xrpl.libxrpl.ledger
|
||||
PUBLIC xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.rdb
|
||||
xrpl.libxrpl.server
|
||||
xrpl.libxrpl.shamap
|
||||
xrpl.libxrpl.conditions)
|
||||
|
||||
add_module(xrpl tx)
|
||||
target_link_libraries(xrpl.libxrpl.tx PUBLIC xrpl.libxrpl.ledger)
|
||||
|
||||
add_library(xrpl.libxrpl)
|
||||
set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl)
|
||||
@@ -110,16 +132,19 @@ target_link_modules(
|
||||
PUBLIC
|
||||
basics
|
||||
beast
|
||||
conditions
|
||||
core
|
||||
crypto
|
||||
json
|
||||
ledger
|
||||
net
|
||||
nodestore
|
||||
protocol
|
||||
rdb
|
||||
resource
|
||||
server
|
||||
nodestore
|
||||
shamap
|
||||
net
|
||||
ledger)
|
||||
tx)
|
||||
|
||||
# All headers in libxrpl are in modules.
|
||||
# Uncomment this stanza if you have not yet moved new headers into a module.
|
||||
|
||||
@@ -65,8 +65,8 @@ add_custom_command(
|
||||
OUTPUT "${doxygen_index_file}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E env "DOXYGEN_OUTPUT_DIRECTORY=${doxygen_output_directory}"
|
||||
"DOXYGEN_INCLUDE_PATH=${doxygen_include_path}" "DOXYGEN_TAGFILES=${doxygen_tagfiles}"
|
||||
"DOXYGEN_PLANTUML_JAR_PATH=${doxygen_plantuml_jar_path}" "DOXYGEN_DOT_PATH=${doxygen_dot_path}"
|
||||
"${DOXYGEN_EXECUTABLE}" "${doxyfile}"
|
||||
"DOXYGEN_PLANTUML_JAR_PATH=${doxygen_plantuml_jar_path}"
|
||||
"DOXYGEN_DOT_PATH=${doxygen_dot_path}" "${DOXYGEN_EXECUTABLE}" "${doxyfile}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
DEPENDS "${dependencies}" "${tagfile}")
|
||||
add_custom_target(docs DEPENDS "${doxygen_index_file}" SOURCES "${dependencies}")
|
||||
|
||||
@@ -20,9 +20,11 @@ install(TARGETS common
|
||||
xrpl.libxrpl
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.beast
|
||||
xrpl.libxrpl.conditions
|
||||
xrpl.libxrpl.core
|
||||
xrpl.libxrpl.crypto
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.rdb
|
||||
xrpl.libxrpl.ledger
|
||||
xrpl.libxrpl.net
|
||||
xrpl.libxrpl.nodestore
|
||||
@@ -30,6 +32,7 @@ install(TARGETS common
|
||||
xrpl.libxrpl.resource
|
||||
xrpl.libxrpl.server
|
||||
xrpl.libxrpl.shamap
|
||||
xrpl.libxrpl.tx
|
||||
antithesis-sdk-cpp
|
||||
EXPORT XrplExports
|
||||
LIBRARY DESTINATION lib
|
||||
@@ -38,11 +41,13 @@ install(TARGETS common
|
||||
INCLUDES
|
||||
DESTINATION include)
|
||||
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
install(EXPORT XrplExports FILE XrplTargets.cmake NAMESPACE Xrpl:: DESTINATION lib/cmake/xrpl)
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(XrplConfigVersion.cmake VERSION ${xrpld_version} COMPATIBILITY SameMajorVersion)
|
||||
write_basic_package_version_file(XrplConfigVersion.cmake VERSION ${xrpld_version}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
if (is_root_project AND TARGET xrpld)
|
||||
install(TARGETS xrpld RUNTIME DESTINATION bin)
|
||||
@@ -69,5 +74,5 @@ if (is_root_project AND TARGET xrpld)
|
||||
")
|
||||
endif ()
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/XrplConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/XrplConfigVersion.cmake
|
||||
DESTINATION lib/cmake/xrpl)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/XrplConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/XrplConfigVersion.cmake DESTINATION lib/cmake/xrpl)
|
||||
|
||||
@@ -33,10 +33,13 @@ target_compile_definitions(
|
||||
target_compile_options(
|
||||
opts
|
||||
INTERFACE $<$<AND:$<BOOL:${is_gcc}>,$<COMPILE_LANGUAGE:CXX>>:-Wsuggest-override>
|
||||
$<$<BOOL:${is_gcc}>:-Wno-maybe-uninitialized> $<$<BOOL:${perf}>:-fno-omit-frame-pointer>
|
||||
$<$<BOOL:${profile}>:-pg> $<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${profile}>>:-p>)
|
||||
$<$<BOOL:${is_gcc}>:-Wno-maybe-uninitialized>
|
||||
$<$<BOOL:${perf}>:-fno-omit-frame-pointer>
|
||||
$<$<BOOL:${profile}>:-pg>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${profile}>>:-p>)
|
||||
|
||||
target_link_libraries(opts INTERFACE $<$<BOOL:${profile}>:-pg> $<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${profile}>>:-p>)
|
||||
target_link_libraries(opts INTERFACE $<$<BOOL:${profile}>:-pg>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${profile}>>:-p>)
|
||||
|
||||
if (jemalloc)
|
||||
find_package(jemalloc REQUIRED)
|
||||
|
||||
@@ -19,7 +19,8 @@ if (NOT is_multiconfig)
|
||||
endif ()
|
||||
|
||||
if (is_clang) # both Clang and AppleClang
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS
|
||||
16.0)
|
||||
message(FATAL_ERROR "This project requires clang 16 or later")
|
||||
endif ()
|
||||
elseif (is_gcc)
|
||||
@@ -32,7 +33,8 @@ endif ()
|
||||
if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
|
||||
message(FATAL_ERROR "Builds (in-source) are not allowed in "
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}. Please remove CMakeCache.txt and the CMakeFiles "
|
||||
"directory from ${CMAKE_CURRENT_SOURCE_DIR} and try building in a separate directory.")
|
||||
"directory from ${CMAKE_CURRENT_SOURCE_DIR} and try building in a separate directory."
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (MSVC AND CMAKE_GENERATOR_PLATFORM STREQUAL "Win32")
|
||||
|
||||
@@ -70,7 +70,8 @@ if (is_linux AND NOT SANITIZER)
|
||||
else ()
|
||||
set(TRUNCATED_LOGS_DEFAULT OFF)
|
||||
endif ()
|
||||
option(TRUNCATED_THREAD_NAME_LOGS "Show warnings about truncated thread names on Linux." ${TRUNCATED_LOGS_DEFAULT})
|
||||
option(TRUNCATED_THREAD_NAME_LOGS "Show warnings about truncated thread names on Linux."
|
||||
${TRUNCATED_LOGS_DEFAULT})
|
||||
if (TRUNCATED_THREAD_NAME_LOGS)
|
||||
add_compile_definitions(TRUNCATED_THREAD_NAME_LOGS)
|
||||
endif ()
|
||||
@@ -92,11 +93,13 @@ endif ()
|
||||
|
||||
option(jemalloc "Enables jemalloc for heap profiling" OFF)
|
||||
option(werr "treat warnings as errors" OFF)
|
||||
option(local_protobuf "Force a local build of protobuf instead of looking for an installed version." OFF)
|
||||
option(local_protobuf
|
||||
"Force a local build of protobuf instead of looking for an installed version." OFF)
|
||||
option(local_grpc "Force a local build of gRPC instead of looking for an installed version." OFF)
|
||||
|
||||
# the remaining options are obscure and rarely used
|
||||
option(beast_no_unit_test_inline "Prevents unit test definitions from being inserted into global table" OFF)
|
||||
option(beast_no_unit_test_inline
|
||||
"Prevents unit test definitions from being inserted into global table" OFF)
|
||||
option(single_io_service_thread "Restricts the number of threads calling io_context::run to one. \
|
||||
This can be useful when debugging." OFF)
|
||||
option(boost_show_deprecated "Allow boost to fail on deprecated usage. Only useful if you're trying\
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
option(validator_keys "Enables building of validator-keys tool as a separate target (imported via FetchContent)" OFF)
|
||||
option(validator_keys
|
||||
"Enables building of validator-keys tool as a separate target (imported via FetchContent)"
|
||||
OFF)
|
||||
|
||||
if (validator_keys)
|
||||
git_branch(current_branch)
|
||||
@@ -8,8 +10,9 @@ if (validator_keys)
|
||||
endif ()
|
||||
message(STATUS "Tracking ValidatorKeys branch: ${current_branch}")
|
||||
|
||||
FetchContent_Declare(validator_keys GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git
|
||||
GIT_TAG "${current_branch}")
|
||||
FetchContent_Declare(
|
||||
validator_keys GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git
|
||||
GIT_TAG "${current_branch}")
|
||||
FetchContent_MakeAvailable(validator_keys)
|
||||
set_target_properties(validator-keys PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
install(TARGETS validator-keys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user