rippled
Loading...
Searching...
No Matches
SHAMapSync_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/shamap/common.h>
21#include <test/unit_test/SuiteJournal.h>
22
23#include <xrpld/shamap/SHAMap.h>
24#include <xrpld/shamap/SHAMapItem.h>
25
26#include <xrpl/basics/random.h>
27#include <xrpl/beast/unit_test.h>
28#include <xrpl/beast/xor_shift_engine.h>
29
30namespace ripple {
31namespace tests {
32
34{
35public:
37
38 boost::intrusive_ptr<SHAMapItem>
40 {
41 Serializer s;
42
43 for (int d = 0; d < 3; ++d)
44 s.add32(rand_int<std::uint32_t>(eng_));
45 return make_shamapitem(s.getSHA512Half(), s.slice());
46 }
47
48 bool
49 confuseMap(SHAMap& map, int count)
50 {
51 // add a bunch of random states to a map, then remove them
52 // map should be the same
53 SHAMapHash beforeHash = map.getHash();
54
56
57 for (int i = 0; i < count; ++i)
58 {
59 auto item = makeRandomAS();
60 items.push_back(item->key());
61
63 {
64 log << "Unable to add item to map\n";
65 return false;
66 }
67 }
68
69 for (auto const& item : items)
70 {
71 if (!map.delItem(item))
72 {
73 log << "Unable to remove item from map\n";
74 return false;
75 }
76 }
77
78 if (beforeHash != map.getHash())
79 {
80 log << "Hashes do not match " << beforeHash << " " << map.getHash()
81 << std::endl;
82 return false;
83 }
84
85 return true;
86 }
87
88 void
89 run() override
90 {
91 using namespace beast::severities;
92 test::SuiteJournal journal("SHAMapSync_test", *this);
93
94 TestNodeFamily f(journal), f2(journal);
95 SHAMap source(SHAMapType::FREE, f);
96 SHAMap destination(SHAMapType::FREE, f2);
97
98 int items = 10000;
99 for (int i = 0; i < items; ++i)
100 {
102 if (i % 100 == 0)
103 source.invariants();
104 }
105
106 source.invariants();
107 BEAST_EXPECT(confuseMap(source, 500));
108 source.invariants();
109
110 source.setImmutable();
111
112 int count = 0;
113 source.visitLeaves([&count](auto const& item) { ++count; });
114 BEAST_EXPECT(count == items);
115
117 source.walkMap(missingNodes, 2048);
118 BEAST_EXPECT(missingNodes.empty());
119
120 std::vector<SHAMapNodeID> nodeIDs, gotNodeIDs;
121 std::vector<Blob> gotNodes;
123
124 destination.setSynching();
125
126 {
128
129 BEAST_EXPECT(source.getNodeFat(
131
132 unexpected(a.size() < 1, "NodeSize");
133
134 BEAST_EXPECT(
135 destination
136 .addRootNode(
137 source.getHash(), makeSlice(a[0].second), nullptr)
138 .isGood());
139 }
140
141 do
142 {
143 f.clock().advance(std::chrono::seconds(1));
144
145 // get the list of nodes we know we need
146 auto nodesMissing = destination.getMissingNodes(2048, nullptr);
147
148 if (nodesMissing.empty())
149 break;
150
151 // get as many nodes as possible based on this information
153
154 for (auto& it : nodesMissing)
155 {
156 // Don't use BEAST_EXPECT here b/c it will be called a
157 // non-deterministic number of times and the number of tests run
158 // should be deterministic
159 if (!source.getNodeFat(
160 it.first, b, rand_bool(eng_), rand_int(eng_, 2)))
161 fail("", __FILE__, __LINE__);
162 }
163
164 // Don't use BEAST_EXPECT here b/c it will be called a
165 // non-deterministic number of times and the number of tests run
166 // should be deterministic
167 if (b.empty())
168 fail("", __FILE__, __LINE__);
169
170 for (std::size_t i = 0; i < b.size(); ++i)
171 {
172 // Don't use BEAST_EXPECT here b/c it will be called a
173 // non-deterministic number of times and the number of tests run
174 // should be deterministic
175 if (!destination
176 .addKnownNode(
177 b[i].first, makeSlice(b[i].second), nullptr)
178 .isUseful())
179 fail("", __FILE__, __LINE__);
180 }
181 } while (true);
182
183 destination.clearSynching();
184
185 BEAST_EXPECT(source.deepCompare(destination));
186
187 destination.invariants();
188 }
189};
190
191BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, ripple);
192
193} // namespace tests
194} // namespace ripple
A testsuite class.
Definition: suite.h:55
log_os< char > log
Logging output stream.
Definition: suite.h:152
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition: suite.h:499
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:533
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:34
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:98
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< std::pair< SHAMapNodeID, Blob > > &data, bool fatLeaves, std::uint32_t depth) const
Definition: SHAMapSync.cpp:434
void clearSynching()
Definition: SHAMap.h:624
void setImmutable()
Definition: SHAMap.h:603
void invariants() const
Definition: SHAMap.cpp:1245
bool addItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition: SHAMap.cpp:881
SHAMapHash getHash() const
Definition: SHAMap.cpp:889
void walkMap(std::vector< SHAMapMissingNode > &missingNodes, int maxMissing) const
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter *filter)
Check for nodes in the SHAMap not available.
Definition: SHAMapSync.cpp:318
void setSynching()
Definition: SHAMap.h:618
bool delItem(uint256 const &id)
Definition: SHAMap.cpp:720
void visitLeaves(std::function< void(boost::intrusive_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:28
bool deepCompare(SHAMap &other) const
Definition: SHAMapSync.cpp:676
Slice slice() const noexcept
Definition: Serializer.h:67
uint256 getSHA512Half() const
Definition: Serializer.cpp:184
boost::intrusive_ptr< SHAMapItem > makeRandomAS()
bool confuseMap(SHAMap &map, int count)
void run() override
Runs the suite.
beast::xor_shift_engine eng_
T empty(T... args)
T endl(T... args)
A namespace for easy access to logging severity values.
Definition: Journal.h:30
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:244
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition: SHAMapItem.h:161
T push_back(T... args)
T size(T... args)