Skip to content

Commit 2d78d41

Browse files
committed
perf: Replace node ID by depth in TMLedgerNode
1 parent 9f17d10 commit 2d78d41

File tree

7 files changed

+107
-48
lines changed

7 files changed

+107
-48
lines changed

include/xrpl/proto/xrpl.proto

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ message TMGetObjectByHash {
244244

245245
message TMLedgerNode {
246246
required bytes nodedata = 1;
247-
optional bytes nodeid = 2; // missing for ledger base data
247+
optional bytes nodeid = 2 [deprecated = true];
248+
optional uint32 nodedepth = 3; // missing for ledger base data
248249
}
249250

250251
enum TMLedgerInfoType {

include/xrpl/protocol/detail/features.macro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
// Add new amendments to the top of this list.
1717
// Keep it sorted in reverse chronological order.
18+
XRPL_FIX (LedgerNodeDepth, Supported::yes, VoteBehavior::DefaultNo)
1819
XRPL_FIX (PermissionedDomainInvariant, Supported::yes, VoteBehavior::DefaultNo)
1920
XRPL_FIX (ExpiredNFTokenOfferRemoval, Supported::yes, VoteBehavior::DefaultNo)
2021
XRPL_FIX (BatchInnerSigs, Supported::yes, VoteBehavior::DefaultNo)

src/libxrpl/shamap/SHAMapSync.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -547,25 +547,6 @@ SHAMap::addKnownNode(SHAMapNodeID const& node, Slice const& rawNode, SHAMapSyncF
547547
return SHAMapAddNode::invalid();
548548
}
549549

550-
// In rare cases, a node can still be corrupt even after hash
551-
// validation. For leaf nodes, we perform an additional check to
552-
// ensure the node's position in the tree is consistent with its
553-
// content to prevent inconsistencies that could
554-
// propagate further down the line.
555-
if (newNode->isLeaf())
556-
{
557-
auto const& actualKey = static_cast<SHAMapLeafNode const*>(newNode.get())->peekItem()->key();
558-
559-
// Validate that this leaf belongs at the target position
560-
auto const expectedNodeID = SHAMapNodeID::createID(node.getDepth(), actualKey);
561-
if (expectedNodeID.getNodeID() != node.getNodeID())
562-
{
563-
JLOG(journal_.debug()) << "Leaf node position mismatch: "
564-
<< "expected=" << expectedNodeID.getNodeID() << ", actual=" << node.getNodeID();
565-
return SHAMapAddNode::invalid();
566-
}
567-
}
568-
569550
// Inner nodes must be at a level strictly less than 64
570551
// but leaf nodes (while notionally at level 64) can be
571552
// at any depth up to and including 64:

src/xrpld/app/ledger/detail/InboundLedger.cpp

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <xrpld/app/ledger/LedgerMaster.h>
55
#include <xrpld/app/ledger/TransactionStateSF.h>
66
#include <xrpld/app/main/Application.h>
7+
#include <xrpld/app/misc/AmendmentTable.h>
78
#include <xrpld/overlay/Overlay.h>
89

910
#include <xrpl/basics/Log.h>
@@ -819,22 +820,54 @@ InboundLedger::receiveNode(protocol::TMLedgerData& packet, SHAMapAddNode& san)
819820
{
820821
auto const f = filter.get();
821822

822-
for (auto const& node : packet.nodes())
823+
for (auto const& ledgerNode : packet.nodes())
823824
{
824-
auto const nodeID = deserializeSHAMapNodeID(node.nodeid());
825-
826-
if (!nodeID)
827-
throw std::runtime_error("data does not properly deserialize");
825+
auto nodeSlice = makeSlice(ledgerNode.nodedata());
826+
auto treeNode = SHAMapTreeNode::makeFromWire(nodeSlice);
827+
if (!treeNode)
828+
{
829+
JLOG(journal_.warn()) << "Got invalid node data";
830+
san.incInvalid();
831+
return;
832+
}
833+
auto const nodeKey = static_cast<SHAMapLeafNode const*>(treeNode.get())->peekItem()->key();
828834

829-
if (nodeID->isRoot())
835+
SHAMapNodeID nodeID;
836+
if (app_.getAmendmentTable().isSupported(fixLedgerNodeDepth))
830837
{
831-
san += map.addRootNode(rootHash, makeSlice(node.nodedata()), f);
838+
nodeID = SHAMapNodeID::createID(ledgerNode.nodedepth(), nodeKey);
832839
}
833840
else
834841
{
835-
san += map.addKnownNode(*nodeID, makeSlice(node.nodedata()), f);
842+
auto const nid = deserializeSHAMapNodeID(ledgerNode.nodeid());
843+
if (!nid)
844+
{
845+
JLOG(journal_.warn()) << "Got invalid node id";
846+
san.incInvalid();
847+
return;
848+
}
849+
nodeID = *nid;
850+
851+
// For leaf nodes, verify that the passed-in node ID is actually
852+
// the same as what the node ID should be, given the position of
853+
// the node in the SHAMap.
854+
if (treeNode->isLeaf())
855+
{
856+
auto const expectedID = SHAMapNodeID::createID(nodeID.getDepth(), nodeKey);
857+
if (nodeID.getNodeID() != expectedID.getNodeID())
858+
{
859+
JLOG(journal_.warn()) << "Got invalid node id";
860+
san.incInvalid();
861+
return;
862+
}
863+
}
836864
}
837865

866+
if (nodeID.isRoot())
867+
san += map.addRootNode(rootHash, nodeSlice, f);
868+
else
869+
san += map.addKnownNode(nodeID, nodeSlice, f);
870+
838871
if (!san.isGood())
839872
{
840873
JLOG(journal_.warn()) << "Received bad node data";
@@ -1044,13 +1077,15 @@ InboundLedger::processData(std::shared_ptr<Peer> peer, protocol::TMLedgerData& p
10441077

10451078
ScopedLockType sl(mtx_);
10461079

1047-
// Verify node IDs and data are complete
1048-
for (auto const& node : packet.nodes())
1080+
// Verify nodes are complete
1081+
for (auto const& ledgerNode : packet.nodes())
10491082
{
1050-
if (!node.has_nodeid() || !node.has_nodedata())
1083+
if (!ledgerNode.has_nodedata() ||
1084+
(app_.getAmendmentTable().isSupported(fixLedgerNodeDepth) && !ledgerNode.has_nodedepth()) ||
1085+
(!app_.getAmendmentTable().isSupported(fixLedgerNodeDepth) && !ledgerNode.has_nodeid()))
10511086
{
1052-
JLOG(journal_.warn()) << "Got bad node";
1053-
peer->charge(Resource::feeMalformedRequest, "ledger_data bad node");
1087+
JLOG(journal_.warn()) << "Got malformed ledger node";
1088+
peer->charge(Resource::feeMalformedRequest, "ledger_node");
10541089
return -1;
10551090
}
10561091
}

src/xrpld/app/ledger/detail/InboundLedgers.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <xrpld/app/ledger/InboundLedgers.h>
22
#include <xrpld/app/ledger/LedgerMaster.h>
33
#include <xrpld/app/main/Application.h>
4+
#include <xrpld/app/misc/AmendmentTable.h>
45
#include <xrpld/app/misc/NetworkOPs.h>
56

67
#include <xrpl/basics/DecayingSample.h>
@@ -217,21 +218,22 @@ class InboundLedgersImp : public InboundLedgers
217218
{
218219
for (int i = 0; i < packet_ptr->nodes().size(); ++i)
219220
{
220-
auto const& node = packet_ptr->nodes(i);
221+
auto const& ledgerNode = packet_ptr->nodes(i);
221222

222-
if (!node.has_nodeid() || !node.has_nodedata())
223+
if (!ledgerNode.has_nodedata() ||
224+
(app_.getAmendmentTable().isSupported(fixLedgerNodeDepth) && !ledgerNode.has_nodedepth()) ||
225+
(!app_.getAmendmentTable().isSupported(fixLedgerNodeDepth) && !ledgerNode.has_nodeid()))
223226
return;
224227

225-
auto newNode = SHAMapTreeNode::makeFromWire(makeSlice(node.nodedata()));
226-
227-
if (!newNode)
228+
auto treeNode = SHAMapTreeNode::makeFromWire(makeSlice(ledgerNode.nodedata()));
229+
if (!treeNode)
228230
return;
229231

230232
s.erase();
231-
newNode->serializeWithPrefix(s);
233+
treeNode->serializeWithPrefix(s);
232234

233235
app_.getLedgerMaster().addFetchPack(
234-
newNode->getHash().as_uint256(), std::make_shared<Blob>(s.begin(), s.end()));
236+
treeNode->getHash().as_uint256(), std::make_shared<Blob>(s.begin(), s.end()));
235237
}
236238
}
237239
catch (std::exception const&)

src/xrpld/app/ledger/detail/InboundTransactions.cpp

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <xrpld/app/ledger/InboundTransactions.h>
33
#include <xrpld/app/ledger/detail/TransactionAcquire.h>
44
#include <xrpld/app/main/Application.h>
5+
#include <xrpld/app/misc/AmendmentTable.h>
56
#include <xrpld/app/misc/NetworkOPs.h>
67

78
#include <xrpl/basics/Log.h>
@@ -130,23 +131,57 @@ class InboundTransactionsImp : public InboundTransactions
130131
std::vector<std::pair<SHAMapNodeID, Slice>> data;
131132
data.reserve(packet.nodes().size());
132133

133-
for (auto const& node : packet.nodes())
134+
for (auto const& ledgerNode : packet.nodes())
134135
{
135-
if (!node.has_nodeid() || !node.has_nodedata())
136+
if (!ledgerNode.has_nodedata() ||
137+
(app_.getAmendmentTable().isSupported(fixLedgerNodeDepth) && !ledgerNode.has_nodedepth()) ||
138+
(!app_.getAmendmentTable().isSupported(fixLedgerNodeDepth) && !ledgerNode.has_nodeid()))
136139
{
137-
peer->charge(Resource::feeMalformedRequest, "ledger_data");
140+
JLOG(j_.warn()) << "Got malformed ledger node";
141+
peer->charge(Resource::feeMalformedRequest, "ledger_node");
138142
return;
139143
}
140144

141-
auto const id = deserializeSHAMapNodeID(node.nodeid());
142-
143-
if (!id)
145+
auto nodeSlice = makeSlice(ledgerNode.nodedata());
146+
auto treeNode = SHAMapTreeNode::makeFromWire(nodeSlice);
147+
if (!treeNode)
144148
{
149+
JLOG(j_.warn()) << "Got invalid node data";
145150
peer->charge(Resource::feeInvalidData, "ledger_data");
146151
return;
147152
}
153+
auto const nodeKey = static_cast<SHAMapLeafNode const*>(treeNode.get())->peekItem()->key();
154+
155+
SHAMapNodeID nodeID;
156+
if (app_.getAmendmentTable().isSupported(fixLedgerNodeDepth))
157+
{
158+
nodeID = SHAMapNodeID::createID(ledgerNode.nodedepth(), nodeKey);
159+
}
160+
else
161+
{
162+
auto const nid = deserializeSHAMapNodeID(ledgerNode.nodeid());
163+
if (!nid)
164+
{
165+
peer->charge(Resource::feeInvalidData, "ledger_id");
166+
return;
167+
}
168+
nodeID = *nid;
169+
170+
// For leaf nodes, verify that the passed-in node ID is actually
171+
// the same as what the node ID should be, given the position of
172+
// the node in the SHAMap.
173+
if (treeNode->isLeaf())
174+
{
175+
auto const expectedID = SHAMapNodeID::createID(nodeID.getDepth(), nodeKey);
176+
if (nodeID.getNodeID() != expectedID.getNodeID())
177+
{
178+
peer->charge(Resource::feeInvalidData, "ledger_id");
179+
return;
180+
}
181+
}
182+
}
148183

149-
data.emplace_back(std::make_pair(*id, makeSlice(node.nodedata())));
184+
data.emplace_back(std::make_pair(nodeID, nodeSlice));
150185
}
151186

152187
if (!ta->takeNodes(data, peer).isUseful())

src/xrpld/overlay/detail/PeerImp.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <xrpld/app/ledger/InboundTransactions.h>
44
#include <xrpld/app/ledger/LedgerMaster.h>
55
#include <xrpld/app/ledger/TransactionMaster.h>
6+
#include <xrpld/app/misc/AmendmentTable.h>
67
#include <xrpld/app/misc/HashRouter.h>
78
#include <xrpld/app/misc/LoadFeeTrack.h>
89
#include <xrpld/app/misc/NetworkOPs.h>
@@ -3152,8 +3153,11 @@ PeerImp::processLedgerRequest(std::shared_ptr<protocol::TMGetLedger> const& m)
31523153
if (ledgerData.nodes_size() >= Tuning::hardMaxReplyNodes)
31533154
break;
31543155
protocol::TMLedgerNode* node{ledgerData.add_nodes()};
3155-
node->set_nodeid(d.first.getRawString());
31563156
node->set_nodedata(d.second.data(), d.second.size());
3157+
if (app_.getAmendmentTable().isSupported(fixLedgerNodeDepth))
3158+
node->set_nodedepth(d.first.getDepth());
3159+
else
3160+
node->set_nodeid(d.first.getRawString());
31573161
}
31583162
}
31593163
else

0 commit comments

Comments
 (0)