xrpld
Loading...
Searching...
No Matches
SHAMapSync_test.cpp
1#include <test/shamap/common.h>
2#include <test/unit_test/SuiteJournal.h>
3
4#include <xrpl/basics/Blob.h>
5#include <xrpl/basics/SHAMapHash.h>
6#include <xrpl/basics/Slice.h>
7#include <xrpl/basics/base_uint.h>
8#include <xrpl/basics/random.h>
9#include <xrpl/beast/unit_test/suite.h>
10#include <xrpl/beast/utility/Journal.h>
11#include <xrpl/beast/xor_shift_engine.h>
12#include <xrpl/protocol/Serializer.h>
13#include <xrpl/shamap/SHAMap.h>
14#include <xrpl/shamap/SHAMapItem.h>
15#include <xrpl/shamap/SHAMapMissingNode.h>
16#include <xrpl/shamap/SHAMapTreeNode.h>
17
18#include <boost/smart_ptr/intrusive_ptr.hpp>
19
20#include <chrono>
21#include <cstddef>
22#include <cstdint>
23#include <list>
24#include <ostream>
25#include <utility>
26#include <vector>
27
28namespace xrpl::tests {
29
31{
32public:
34
35 boost::intrusive_ptr<SHAMapItem>
37 {
38 Serializer s;
39
40 for (int d = 0; d < 3; ++d)
42 return makeShamapitem(s.getSHA512Half(), s.slice());
43 }
44
45 bool
46 confuseMap(SHAMap& map, int count)
47 {
48 // add a bunch of random states to a map, then remove them
49 // map should be the same
50 SHAMapHash const beforeHash = map.getHash();
51
53
54 for (int i = 0; i < count; ++i)
55 {
56 auto item = makeRandomAS();
57 items.push_back(item->key());
58
60 {
61 log << "Unable to add item to map\n";
62 return false;
63 }
64 }
65
66 for (auto const& item : items)
67 {
68 if (!map.delItem(item))
69 {
70 log << "Unable to remove item from map\n";
71 return false;
72 }
73 }
74
75 if (beforeHash != map.getHash())
76 {
77 log << "Hashes do not match " << beforeHash << " " << map.getHash() << std::endl;
78 return false;
79 }
80
81 return true;
82 }
83
84 void
85 run() override
86 {
87 using beast::Severity;
88 test::SuiteJournal journal("SHAMapSync_test", *this);
89
90 TestNodeFamily f(journal), f2(journal);
91 SHAMap source(SHAMapType::FREE, f);
92 SHAMap destination(SHAMapType::FREE, f2);
93
94 int const items = 10000;
95 for (int i = 0; i < items; ++i)
96 {
98 if (i % 100 == 0)
99 source.invariants();
100 }
101
102 source.invariants();
103 BEAST_EXPECT(confuseMap(source, 500));
104 source.invariants();
105
106 source.setImmutable();
107
108 int count = 0;
109 source.visitLeaves([&count](auto const& item) { ++count; });
110 BEAST_EXPECT(count == items);
111
113 source.walkMap(missingNodes, 2048);
114 BEAST_EXPECT(missingNodes.empty());
115
116 destination.setSynching();
117
118 {
120
121 BEAST_EXPECT(source.getNodeFat(SHAMapNodeID(), a, randBool(eng), randInt(eng, 2)));
122
123 unexpected(a.empty(), "NodeSize");
124
125 BEAST_EXPECT(destination.addRootNode(source.getHash(), makeSlice(a[0].second), nullptr)
126 .isGood());
127 }
128
129 do
130 {
131 f.clock().advance(std::chrono::seconds(1));
132
133 // get the list of nodes we know we need
134 auto nodesMissing = destination.getMissingNodes(2048, nullptr);
135
136 if (nodesMissing.empty())
137 break;
138
139 // get as many nodes as possible based on this information
141
142 for (auto& it : nodesMissing)
143 {
144 // Don't use BEAST_EXPECT here b/c it will be called a
145 // non-deterministic number of times and the number of tests run
146 // should be deterministic
147 if (!source.getNodeFat(it.first, b, randBool(eng), randInt(eng, 2)))
148 fail("", __FILE__, __LINE__);
149 }
150
151 // Don't use BEAST_EXPECT here b/c it will be called a
152 // non-deterministic number of times and the number of tests run
153 // should be deterministic
154 if (b.empty())
155 fail("", __FILE__, __LINE__);
156
157 for (std::size_t i = 0; i < b.size(); ++i)
158 {
159 // Don't use BEAST_EXPECT here b/c it will be called a
160 // non-deterministic number of times and the number of tests run
161 // should be deterministic
162 if (!destination.addKnownNode(b[i].first, makeSlice(b[i].second), nullptr)
163 .isUseful())
164 fail("", __FILE__, __LINE__);
165 }
166 } while (true);
167
168 destination.clearSynching();
169
170 BEAST_EXPECT(source.deepCompare(destination));
171
172 destination.invariants();
173 }
174};
175
176BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, xrpl);
177
178} // namespace xrpl::tests
A testsuite class.
Definition suite.h:50
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:484
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:522
LogOs< char > log
Logging output stream.
Definition suite.h:146
Identifies a node inside a SHAMap.
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition SHAMap.h:77
bool addItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:830
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:552
bool deepCompare(SHAMap &other) const
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, Slice const &rawNode, SHAMapSyncFilter const *filter)
void setImmutable()
Definition SHAMap.h:539
void clearSynching()
Definition SHAMap.h:558
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< std::pair< SHAMapNodeID, Blob > > &data, bool fatLeaves, std::uint32_t depth) const
SHAMapAddNode addRootNode(SHAMapHash const &hash, Slice const &rootNode, SHAMapSyncFilter const *filter)
void invariants() const
Definition SHAMap.cpp:1170
SHAMapHash getHash() const
Definition SHAMap.cpp:836
bool delItem(uint256 const &id)
Definition SHAMap.cpp:678
uint256 getSHA512Half() const
Slice slice() const noexcept
Definition Serializer.h:44
bool confuseMap(SHAMap &map, int count)
boost::intrusive_ptr< SHAMapItem > makeRandomAS()
void run() override
Runs the suite.
beast::xor_shift_engine eng
T empty(T... args)
T endl(T... args)
detail::XorShiftEngine<> xor_shift_engine
XOR-shift Generator.
Severity
Severity level / threshold of a Journal message.
Definition Journal.h:11
BEAST_DEFINE_TESTSUITE(IntrusiveShared, basics, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool randBool(Engine &engine)
Return a random boolean value.
std::enable_if_t< std::is_integral_v< Integral > &&detail::is_engine< Engine >::value, Integral > randInt(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
std::enable_if_t< std::is_integral_v< Integral >, Integral > randInt()
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:139
std::enable_if_t< std::is_same_v< T, char >||std::is_same_v< T, unsigned char >, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:215
T push_back(T... args)
T size(T... args)