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.
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition SHAMap.h:99
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< std::pair< SHAMapNodeID, Blob > > &data, bool fatLeaves, std::uint32_t depth) const
void clearSynching()
Definition SHAMap.h:625
void setImmutable()
Definition SHAMap.h:604
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.
void setSynching()
Definition SHAMap.h:619
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.
bool deepCompare(SHAMap &other) const
Slice slice() const noexcept
Definition Serializer.h:66
uint256 getSHA512Half() const
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:25
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)