xrpld
Loading...
Searching...
No Matches
LedgerNodeHelpers_test.cpp
1#include <xrpld/app/ledger/LedgerNodeHelpers.h>
2
3#include <xrpl/basics/IntrusivePointer.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/beast/unit_test/suite.h>
6#include <xrpl/protocol/Serializer.h>
7#include <xrpl/shamap/SHAMap.h>
8#include <xrpl/shamap/SHAMapAccountStateLeafNode.h>
9#include <xrpl/shamap/SHAMapInnerNode.h>
10#include <xrpl/shamap/SHAMapItem.h>
11#include <xrpl/shamap/SHAMapTreeNode.h>
12
13#include <boost/smart_ptr/intrusive_ptr.hpp>
14
15#include <xrpl.pb.h>
16
17#include <cstdint>
18#include <string>
19
20namespace xrpl::tests {
21
23{
24 static boost::intrusive_ptr<SHAMapItem>
26 {
27 Serializer s;
28 s.add32(seed);
29 s.add32(seed + 1);
30 s.add32(seed + 2);
31 return makeShamapitem(s.getSHA512Half(), s.slice());
32 }
33
34 static std::string
36 {
37 Serializer s;
38 node->serializeForWire(s);
39 auto const slice = s.slice();
40 return std::string(slice.begin(), slice.end());
41 }
42
43 void
45 {
46 testcase("getTreeNode");
47
48 // Valid: inner node. It must have at least one child for `serializeNode` to work.
49 {
50 auto const innerNode = intr_ptr::makeShared<SHAMapInnerNode>(1);
51 auto const childNode = intr_ptr::makeShared<SHAMapInnerNode>(1);
52 innerNode->setChild(0, childNode);
53 auto const innerData = serializeNode(innerNode);
54 auto const result = getTreeNode(innerData);
55 BEAST_EXPECT(result && result->isInner());
56 }
57
58 // Valid: leaf node.
59 {
60 auto const leafItem = makeTestItem(12345);
61 auto const leafNode = intr_ptr::makeShared<SHAMapAccountStateLeafNode>(leafItem, 1);
62 auto const leafData = serializeNode(leafNode);
63 auto const result = getTreeNode(leafData);
64 BEAST_EXPECT(result && result->isLeaf());
65 }
66
67 // Invalid: empty data.
68 {
69 auto const result = getTreeNode("");
70 BEAST_EXPECT(!result);
71 }
72
73 // Invalid: garbage data.
74 {
75 auto const result = getTreeNode("invalid");
76 BEAST_EXPECT(!result);
77 }
78
79 // Invalid: truncated data.
80 {
81 auto const leafItem = makeTestItem(54321);
82 auto const leafNode = intr_ptr::makeShared<SHAMapAccountStateLeafNode>(leafItem, 1);
83 // Truncate the data to trigger an exception in SHAMapTreeNode::makeAccountState when
84 // the data is used to deserialize the node.
85 uint256 const tag;
86 auto const leafData = serializeNode(leafNode).substr(0, tag.kBytes - 1);
87 auto const result = getTreeNode(leafData);
88 BEAST_EXPECT(!result);
89 }
90 }
91
92 void
94 {
95 testcase("getSHAMapNodeID");
96
97 {
98 // Tests using inner nodes at various depths.
99 auto const innerNode = intr_ptr::makeShared<SHAMapInnerNode>(1);
100 auto const childNode = intr_ptr::makeShared<SHAMapInnerNode>(1);
101 innerNode->setChild(0, childNode);
102 auto const innerData = serializeNode(innerNode);
103
104 // Valid: legacy `nodeid` field at arbitrary depth.
105 {
106 auto const innerDepth = 3;
107 auto const innerID = SHAMapNodeID::createID(innerDepth, uint256{});
108
109 protocol::TMLedgerNode ledgerNode;
110 ledgerNode.set_nodedata(innerData);
111 ledgerNode.set_nodeid(innerID.getRawString());
112 auto const result = getSHAMapNodeID(ledgerNode, *innerNode);
113 BEAST_EXPECT(result == innerID);
114 }
115
116 // Valid: new `id` field at minimum depth.
117 {
118 auto const innerDepth = 0;
119 auto const innerID = SHAMapNodeID::createID(innerDepth, uint256{});
120
121 protocol::TMLedgerNode ledgerNode;
122 ledgerNode.set_nodedata(innerData);
123 ledgerNode.set_id(innerID.getRawString());
124 auto const result = getSHAMapNodeID(ledgerNode, *innerNode);
125 BEAST_EXPECT(result == innerID);
126 }
127
128 // Invalid: new `depth` field should not be used for inner nodes.
129 {
130 protocol::TMLedgerNode ledgerNode;
131 ledgerNode.set_nodedata(innerData);
132 ledgerNode.set_depth(10);
133 auto const result = getSHAMapNodeID(ledgerNode, *innerNode);
134 BEAST_EXPECT(!result);
135 }
136
137 // Invalid: both legacy `nodeid` and new `id` fields set for an inner node.
138 {
139 auto const innerDepth = 9;
140 auto const innerID = SHAMapNodeID::createID(innerDepth, uint256{});
141
142 protocol::TMLedgerNode ledgerNode;
143 ledgerNode.set_nodedata(innerData);
144 ledgerNode.set_nodeid(innerID.getRawString());
145 ledgerNode.set_id(innerID.getRawString());
146 auto const result = getSHAMapNodeID(ledgerNode, *innerNode);
147 BEAST_EXPECT(!result);
148 }
149 }
150
151 {
152 // Tests using leaf nodes at various depths.
153 auto const leafItem = makeTestItem(12345);
154 auto const leafNode = intr_ptr::makeShared<SHAMapAccountStateLeafNode>(leafItem, 1);
155 auto const leafData = serializeNode(leafNode);
156 auto const leafKey = leafItem->key();
157
158 // Valid: legacy `nodeid` field at arbitrary depth.
159 {
160 auto const kLeafDepth = 5;
161 auto const leafID = SHAMapNodeID::createID(kLeafDepth, leafKey);
162
163 protocol::TMLedgerNode ledgerNode;
164 ledgerNode.set_nodedata(leafData);
165 ledgerNode.set_nodeid(leafID.getRawString());
166 auto const result = getSHAMapNodeID(ledgerNode, *leafNode);
167 BEAST_EXPECT(result == leafID);
168 }
169
170 // Invalid: new `id` field should not be used for leaf nodes.
171 {
172 auto const kLeafDepth = 5;
173 auto const leafID = SHAMapNodeID::createID(kLeafDepth, leafKey);
174
175 protocol::TMLedgerNode ledgerNode;
176 ledgerNode.set_nodedata(leafData);
177 ledgerNode.set_id(leafID.getRawString());
178 auto const result = getSHAMapNodeID(ledgerNode, *leafNode);
179 BEAST_EXPECT(!result);
180 }
181
182 // Valid: new `depth` field at minimum depth.
183 {
184 auto const kLeafDepth = 0;
185 auto const leafID = SHAMapNodeID::createID(kLeafDepth, leafKey);
186
187 protocol::TMLedgerNode ledgerNode;
188 ledgerNode.set_nodedata(leafData);
189 ledgerNode.set_depth(kLeafDepth);
190 auto const result = getSHAMapNodeID(ledgerNode, *leafNode);
191 BEAST_EXPECT(result == leafID);
192 }
193
194 // Valid: new `depth` field at arbitrary depth between minimum and maximum.
195 {
196 auto const kLeafDepth = 10;
197 auto const leafID = SHAMapNodeID::createID(kLeafDepth, leafKey);
198
199 protocol::TMLedgerNode ledgerNode;
200 ledgerNode.set_nodedata(leafData);
201 ledgerNode.set_depth(kLeafDepth);
202 auto const result = getSHAMapNodeID(ledgerNode, *leafNode);
203 BEAST_EXPECT(result == leafID);
204 }
205
206 // Valid: new `depth` field at maximum depth.
207 // Note that we do not test a depth greater than the maximum depth, because the proto
208 // message is assumed to have been validated by the time the getSHAMapNodeID function is
209 // called.
210 {
211 auto const kLeafDepth = SHAMap::kLeafDepth;
212 auto const leafID = SHAMapNodeID::createID(kLeafDepth, leafKey);
213
214 protocol::TMLedgerNode ledgerNode;
215 ledgerNode.set_nodedata(leafData);
216 ledgerNode.set_depth(kLeafDepth);
217 auto const result = getSHAMapNodeID(ledgerNode, *leafNode);
218 BEAST_EXPECT(result == leafID);
219 }
220
221 // Invalid: legacy `nodeid` field where the node ID is inconsistent with the key.
222 {
223 auto const otherItem = makeTestItem(54321);
224 auto const otherNode =
226 auto const otherData = serializeNode(otherNode);
227 auto const otherKey = otherItem->key();
228 auto const otherDepth = 1;
229 auto const otherID = SHAMapNodeID::createID(otherDepth, otherKey);
230
231 protocol::TMLedgerNode ledgerNode;
232 ledgerNode.set_nodedata(otherData);
233 ledgerNode.set_nodeid(otherID.getRawString());
234 auto const result = getSHAMapNodeID(ledgerNode, *leafNode);
235 BEAST_EXPECT(!result);
236 }
237 }
238
239 // Invalid: no field set.
240 {
241 auto const innerNode = intr_ptr::makeShared<SHAMapInnerNode>(1);
242 protocol::TMLedgerNode ledgerNode;
243 ledgerNode.set_nodedata("test_data");
244 auto const result = getSHAMapNodeID(ledgerNode, *innerNode);
245 BEAST_EXPECT(!result);
246 }
247 }
248
249public:
250 void
251 run() override
252 {
255 }
256};
257
258BEAST_DEFINE_TESTSUITE(LedgerNodeHelpers, app, xrpl);
259
260} // namespace xrpl::tests
A testsuite class.
Definition suite.h:52
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
static constexpr std::size_t kBytes
Definition base_uint.h:100
static SHAMapNodeID createID(int depth, uint256 const &key)
Create a SHAMapNodeID of a node with the depth of the node and the key of a leaf.
static constexpr unsigned int kLeafDepth
The depth of the hash map: data is only present in the leaves.
Definition SHAMap.h:144
Slice slice() const noexcept
Definition Serializer.h:45
static boost::intrusive_ptr< SHAMapItem > makeTestItem(std::uint32_t seed)
static std::string serializeNode(SHAMapTreeNodePtr const &node)
SharedPtr< T > makeShared(A &&... args)
BEAST_DEFINE_TESTSUITE(LedgerNodeHelpers, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
intr_ptr::SharedPtr< SHAMapTreeNode > SHAMapTreeNodePtr
uint256 const & leafKey(SHAMapTreeNode const &node)
Return the key of the item held by a SHAMap leaf node.
std::optional< SHAMapNodeID > getSHAMapNodeID(protocol::TMLedgerNode const &ledgerNode, SHAMapTreeNode const &treeNode)
Extracts or reconstructs the SHAMapNodeID from a ledger node proto message.
SHAMapTreeNodePtr getTreeNode(std::string_view data)
Deserializes a SHAMapTreeNode from wire format data.
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:148
BaseUInt< 256 > uint256
Definition base_uint.h:580
T substr(T... args)