xrpld
Loading...
Searching...
No Matches
tests/libxrpl/shamap/SHAMapSync.cpp
1#include <xrpl/basics/SHAMapHash.h>
2#include <xrpl/basics/Slice.h>
3#include <xrpl/basics/base_uint.h>
4#include <xrpl/basics/random.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/beast/xor_shift_engine.h>
7#include <xrpl/protocol/Serializer.h>
8#include <xrpl/shamap/SHAMap.h>
9#include <xrpl/shamap/SHAMapItem.h>
10#include <xrpl/shamap/SHAMapMissingNode.h>
11#include <xrpl/shamap/SHAMapTreeNode.h>
12
13#include <boost/smart_ptr/intrusive_ptr.hpp>
14
15#include <gtest/gtest.h>
16#include <helpers/TestSink.h>
17#include <shamap/common.h>
18
19#include <chrono>
20#include <cstddef>
21#include <cstdint>
22#include <list>
23#include <utility>
24#include <vector>
25
26namespace xrpl::tests {
27
28class SHAMapSyncTest : public ::testing::Test
29{
30protected:
33
34 boost::intrusive_ptr<SHAMapItem>
36 {
37 static constexpr auto kWordsPerState = 3uz;
38
39 Serializer s;
40
41 for (auto word = 0uz; word < kWordsPerState; ++word)
43 return makeShamapitem(s.getSHA512Half(), s.slice());
44 }
45
46 bool
48 {
49 // add a bunch of random states to a map, then remove them
50 // map should be the same
51 SHAMapHash const beforeHash = map.getHash();
52
54
55 for (auto i = 0uz; i < count; ++i)
56 {
57 auto item = makeRandomAS();
58 items.push_back(item->key());
59
61 {
62 ADD_FAILURE() << "Unable to add item to map";
63 return false;
64 }
65 }
66
67 for (auto const& item : items)
68 {
69 if (!map.delItem(item))
70 {
71 ADD_FAILURE() << "Unable to remove item from map";
72 return false;
73 }
74 }
75
76 if (beforeHash != map.getHash())
77 {
78 ADD_FAILURE() << "Hashes do not match " << beforeHash << " " << map.getHash();
79 return false;
80 }
81
82 return true;
83 }
84};
85
87{
88 TestNodeFamily f{j_}, f2{j_};
89 SHAMap source{SHAMapType::FREE, f};
90 SHAMap destination{SHAMapType::FREE, f2};
91
92 static constexpr auto kItemCount = 10000uz;
93 static constexpr auto kInvariantInterval = 100uz;
94 static constexpr auto kNodesToConfuse = 500uz;
95 static constexpr auto kMaxNodesPerRequest = 2048;
96
97 for (auto i = 0uz; i < kItemCount; ++i)
98 {
99 source.addItem(SHAMapNodeType::TnAccountState, makeRandomAS());
100 if (i % kInvariantInterval == 0)
101 source.invariants();
102 }
103
104 source.invariants();
105 ASSERT_TRUE(confuseMap(source, kNodesToConfuse));
106 source.invariants();
107
108 source.setImmutable();
109
110 std::size_t count = 0;
111 source.visitLeaves([&count]([[maybe_unused]] auto const& item) { ++count; });
112 EXPECT_EQ(count, kItemCount);
113
115 source.walkMap(missingNodes, kMaxNodesPerRequest);
116 EXPECT_TRUE(missingNodes.empty());
117
118 destination.setSynching();
119
120 {
122
123 ASSERT_TRUE(source.getNodeFat(SHAMapNodeID(), a, randBool(eng_), randInt(eng_, 2)));
124
125 ASSERT_FALSE(a.empty()) << "NodeSize";
126
127 auto node = SHAMapTreeNode::makeFromWire(makeSlice(a[0].data));
128 if (!node)
129 FAIL() << "Could not create node";
130 ASSERT_TRUE(destination.addRootNode(source.getHash(), std::move(node), nullptr).isGood());
131 }
132
133 do
134 {
136
137 // get the list of nodes we know we need
138 auto nodesMissing = destination.getMissingNodes(kMaxNodesPerRequest, nullptr);
139
140 if (nodesMissing.empty())
141 break;
142
143 // get as many nodes as possible based on this information
145
146 for (auto& it : nodesMissing)
147 {
148 // Keep failures fatal here because this loop is data-dependent.
149 // non-deterministic number of times and the number of tests run
150 // should be deterministic
151 if (!source.getNodeFat(it.first, b, randBool(eng_), randInt(eng_, 2)))
152 FAIL() << "Unable to fetch node";
153 }
154
155 // Keep failures fatal here because this loop is data-dependent.
156 // non-deterministic number of times and the number of tests run
157 // should be deterministic
158 if (b.empty())
159 FAIL() << "No nodes returned";
160
161 for (auto const& i : b)
162 {
163 // Keep failures fatal here because this loop is data-dependent.
164 // non-deterministic number of times and the number of tests run
165 // should be deterministic
166 auto node = SHAMapTreeNode::makeFromWire(makeSlice(i.data));
167 if (!node)
168 FAIL() << "Could not create node";
169 if (i.isLeaf != node->isLeaf())
170 FAIL() << "Node is not a leaf";
171 if (!destination.addKnownNode(i.nodeID, std::move(node), nullptr).isUseful())
172 FAIL() << "Known node was not useful";
173 }
174 } while (true);
175
176 destination.clearSynching();
177
178 EXPECT_TRUE(source.deepCompare(destination));
179
180 destination.invariants();
181}
182
183} // namespace xrpl::tests
A generic endpoint for log messages.
Definition Journal.h:44
void advance(std::chrono::duration< Rep, Period > const &elapsed)
Advance the clock by a duration.
bool isUseful() const
Identifies a node inside a SHAMap.
static SHAMapTreeNodePtr makeFromWire(Slice rawNode)
bool addItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< SHAMapNodeData > &data, bool fatLeaves, std::uint32_t depth) const
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter const *filter)
Check for nodes in the SHAMap not available.
void walkMap(std::vector< SHAMapMissingNode > &missingNodes, int maxMissing) const
void setSynching()
Definition SHAMap.h:660
bool deepCompare(SHAMap &other) const
SHAMapAddNode addRootNode(SHAMapHash const &hash, SHAMapTreeNodePtr rootNode, SHAMapSyncFilter const *filter)
Add a root node to the SHAMap during synchronization.
void visitLeaves(std::function< void(boost::intrusive_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
SHAMapAddNode addKnownNode(SHAMapNodeID const &nodeID, SHAMapTreeNodePtr treeNode, SHAMapSyncFilter const *filter)
Add a known node at a specific position in the SHAMap during synchronization.
void setImmutable()
Definition SHAMap.h:647
void clearSynching()
Definition SHAMap.h:666
SHAMapHash getHash() const
bool delItem(uint256 const &id)
Slice slice() const noexcept
Definition Serializer.h:45
static TestSink & instance()
Definition TestSink.h:12
boost::intrusive_ptr< SHAMapItem > makeRandomAS()
bool confuseMap(SHAMap &map, std::size_t count)
TestStopwatch & clock()
Definition common.h:117
T empty(T... args)
detail::XorShiftEngine<> xor_shift_engine
XOR-shift Generator.
TEST_F(SHAMapPathProof, verify_proof_path)
bool randBool(Engine &engine)
Return a random boolean value.
Integral randInt(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Slice makeSlice(std::array< T, N > const &a)
Definition Slice.h:228
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:148
T push_back(T... args)