-
Notifications
You must be signed in to change notification settings - Fork 1.6k
perf: Replace node ID by depth in TMLedgerNode
#6353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new fix amendment (fixLedgerNodeDepth) intended to reduce TMLedgerNode message size by replacing the serialized SHAMapNodeID (nodeid) with a smaller nodedepth field, and it relocates a leaf-position integrity check from SHAMapSync::addKnownNode to the peer-ingress paths.
Changes:
- Add
fixLedgerNodeDepthamendment and extendTMLedgerNodeproto withnodedepth(deprecatingnodeid). - Update ledger-node send/receive paths to populate/consume
nodedepthinstead ofnodeid(gated by amendment table checks). - Remove the leaf position mismatch check from
SHAMap::addKnownNode(moving validation to message ingress).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/xrpld/overlay/detail/PeerImp.cpp | Sends nodedepth instead of nodeid in TMLedgerNode replies when the amendment is considered supported. |
| src/xrpld/app/ledger/detail/InboundTransactions.cpp | Validates incoming TMLedgerNode fields and reconstructs node IDs (attempts to use nodedepth). |
| src/xrpld/app/ledger/detail/InboundLedgers.cpp | Applies new field-completeness checks when caching stale fetch-pack data. |
| src/xrpld/app/ledger/detail/InboundLedger.cpp | Validates incoming nodes and reconstructs node IDs (attempts to use nodedepth) before inserting into SHAMaps. |
| src/libxrpl/shamap/SHAMapSync.cpp | Removes the additional leaf-position consistency check inside addKnownNode. |
| include/xrpl/protocol/detail/features.macro | Adds the new fix amendment definition entry. |
| include/xrpl/proto/xrpl.proto | Deprecates nodeid and adds nodedepth to TMLedgerNode. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #6353 +/- ##
=========================================
- Coverage 79.9% 79.8% -0.1%
=========================================
Files 840 840
Lines 65513 65557 +44
Branches 7256 7295 +39
=========================================
- Hits 52347 52341 -6
- Misses 13166 13216 +50
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (app_.getAmendmentTable().isEnabled(fixLedgerNodeDepth)) | ||
| { | ||
| san += map.addRootNode(rootHash, makeSlice(node.nodedata()), f); | ||
| nodeID = SHAMapNodeID(ledgerNode.nodedepth(), treeNode->getHash().as_uint256()); |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the fixLedgerNodeDepth amendment is enabled, the nodedepth value from the peer is used directly to construct a SHAMapNodeID without validating that it's within valid bounds (0-64). The SHAMapNodeID constructor has an assertion that depth <= 64, but assertions are only active in debug builds. A malicious peer could send a nodedepth > 64 which could lead to undefined behavior in release builds. Add validation to ensure nodedepth <= 64 before constructing the SHAMapNodeID, and charge the peer with feeInvalidData and call san.incInvalid() if the check fails.
| nodeID = SHAMapNodeID(ledgerNode.nodedepth(), treeNode->getHash().as_uint256()); | |
| auto const depth = ledgerNode.nodedepth(); | |
| // Validate node depth before constructing SHAMapNodeID to avoid undefined behavior. | |
| // Valid depths are in the range [0, 64]. | |
| if (depth > 64) | |
| { | |
| JLOG(journal_.warn()) << "Got invalid node depth: " << depth; | |
| peer->charge(resource::feeInvalidData); | |
| san.incInvalid(); | |
| return; | |
| } | |
| nodeID = SHAMapNodeID(depth, treeNode->getHash().as_uint256()); |
| auto const nid = deserializeSHAMapNodeID(ledgerNode.nodeid()); | ||
| if (!nid) | ||
| { | ||
| JLOG(journal_.warn()) << "Got unexpected node id"; |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message "Got unexpected node id" is inconsistent with the similar error message at line 867 which says "Got invalid node id" and with the error message at line 164 in InboundTransactions.cpp which says "Got invalid node id". For consistency, this should be "Got invalid node id".
| JLOG(journal_.warn()) << "Got unexpected node id"; | |
| JLOG(journal_.warn()) << "Got invalid node id"; |
| // For leaf nodes, verify that the node ID is actually the same as what the node ID | ||
| // should be, given the position of the node in the SHAMap. | ||
| if (treeNode->isLeaf()) | ||
| { | ||
| auto const nodeKey = dynamic_cast<SHAMapLeafNode const*>(treeNode.get())->peekItem()->key(); | ||
| auto const expectedID = SHAMapNodeID::createID(static_cast<int>(nodeID.getDepth()), nodeKey); | ||
| if (nodeID.getNodeID() != expectedID.getNodeID()) | ||
| { | ||
| JLOG(journal_.warn()) << "Got invalid node id"; | ||
| san.incInvalid(); | ||
| return; | ||
| } | ||
| } |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validation logic for checking node IDs (lines 859-871) is duplicated in InboundTransactions.cpp (lines 171-183) and appears very similar. This code duplication makes maintenance harder and increases the risk of inconsistencies. Consider extracting this validation into a shared helper function that can be reused across these files.
High Level Overview of Change
This change introduces a new fix amendment,
fixLedgerNodeDepth, which replaces the 32-byte node ID in theTMLedgerNodeproto message by a 2-byte node depth instead (1 byte for the field tag, 1 byte for the depth as it won't exceed 127).Context of Change
An earlier bug allowed a compromised UNL validator to send a maliciously crafted
TMLedgerNodemessage with a node ID that didn't match the actual node ID corresponding to where the node data was located in the SHAMap. That bug was fixed by adding an extra check, which reconstructs the node ID from the node data and its depth. Hence, we don't actually need the node ID, and the much smaller node depth suffices. The extra check is now moved to the places where the messages are received from a peer, avoiding an expensiveSHAMapTreeNode::makeFromWirecall inSHAMapSync.Although this change marks the
nodeidfield as deprecated, we cannot just ignore it as nodes running older releases won't be able to understand the new field. This change therefore requires an amendment, namedfixLedgerNodeDepth.Type of Change
.gitignore, formatting, dropping support for older tooling)API Impact
libxrplchange (any change that may affectlibxrplor dependents oflibxrpl)Test Plan
As none of these files ever had tests, they need to be added.