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 <xrpl/basics/random.h>
24#include <xrpl/beast/unit_test.h>
25#include <xrpl/beast/xor_shift_engine.h>
26#include <xrpl/shamap/SHAMap.h>
27#include <xrpl/shamap/SHAMapItem.h>
28
29namespace ripple {
30namespace tests {
31
33{
34public:
36
37 boost::intrusive_ptr<SHAMapItem>
39 {
40 Serializer s;
41
42 for (int d = 0; d < 3; ++d)
43 s.add32(rand_int<std::uint32_t>(eng_));
44 return make_shamapitem(s.getSHA512Half(), s.slice());
45 }
46
47 bool
48 confuseMap(SHAMap& map, int count)
49 {
50 // add a bunch of random states to a map, then remove them
51 // map should be the same
52 SHAMapHash beforeHash = map.getHash();
53
55
56 for (int i = 0; i < count; ++i)
57 {
58 auto item = makeRandomAS();
59 items.push_back(item->key());
60
62 {
63 log << "Unable to add item to map\n";
64 return false;
65 }
66 }
67
68 for (auto const& item : items)
69 {
70 if (!map.delItem(item))
71 {
72 log << "Unable to remove item from map\n";
73 return false;
74 }
75 }
76
77 if (beforeHash != map.getHash())
78 {
79 log << "Hashes do not match " << beforeHash << " " << map.getHash()
80 << std::endl;
81 return false;
82 }
83
84 return true;
85 }
86
87 void
88 run() override
89 {
90 using namespace beast::severities;
91 test::SuiteJournal journal("SHAMapSync_test", *this);
92
93 TestNodeFamily f(journal), f2(journal);
94 SHAMap source(SHAMapType::FREE, f);
95 SHAMap destination(SHAMapType::FREE, f2);
96
97 int items = 10000;
98 for (int i = 0; i < items; ++i)
99 {
101 if (i % 100 == 0)
102 source.invariants();
103 }
104
105 source.invariants();
106 BEAST_EXPECT(confuseMap(source, 500));
107 source.invariants();
108
109 source.setImmutable();
110
111 int count = 0;
112 source.visitLeaves([&count](auto const& item) { ++count; });
113 BEAST_EXPECT(count == items);
114
116 source.walkMap(missingNodes, 2048);
117 BEAST_EXPECT(missingNodes.empty());
118
119 std::vector<SHAMapNodeID> nodeIDs, gotNodeIDs;
120 std::vector<Blob> gotNodes;
122
123 destination.setSynching();
124
125 {
127
128 BEAST_EXPECT(source.getNodeFat(
130
131 unexpected(a.size() < 1, "NodeSize");
132
133 BEAST_EXPECT(
134 destination
135 .addRootNode(
136 source.getHash(), makeSlice(a[0].second), nullptr)
137 .isGood());
138 }
139
140 do
141 {
142 f.clock().advance(std::chrono::seconds(1));
143
144 // get the list of nodes we know we need
145 auto nodesMissing = destination.getMissingNodes(2048, nullptr);
146
147 if (nodesMissing.empty())
148 break;
149
150 // get as many nodes as possible based on this information
152
153 for (auto& it : nodesMissing)
154 {
155 // Don't use BEAST_EXPECT here b/c it will be called a
156 // non-deterministic number of times and the number of tests run
157 // should be deterministic
158 if (!source.getNodeFat(
159 it.first, b, rand_bool(eng_), rand_int(eng_, 2)))
160 fail("", __FILE__, __LINE__);
161 }
162
163 // Don't use BEAST_EXPECT here b/c it will be called a
164 // non-deterministic number of times and the number of tests run
165 // should be deterministic
166 if (b.empty())
167 fail("", __FILE__, __LINE__);
168
169 for (std::size_t i = 0; i < b.size(); ++i)
170 {
171 // Don't use BEAST_EXPECT here b/c it will be called a
172 // non-deterministic number of times and the number of tests run
173 // should be deterministic
174 if (!destination
175 .addKnownNode(
176 b[i].first, makeSlice(b[i].second), nullptr)
177 .isUseful())
178 fail("", __FILE__, __LINE__);
179 }
180 } while (true);
181
182 destination.clearSynching();
183
184 BEAST_EXPECT(source.deepCompare(destination));
185
186 destination.invariants();
187 }
188};
189
190BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, ripple);
191
192} // namespace tests
193} // 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:97
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< std::pair< SHAMapNodeID, Blob > > &data, bool fatLeaves, std::uint32_t depth) const
void clearSynching()
Definition SHAMap.h:623
void setImmutable()
Definition SHAMap.h:602
void invariants() const
Definition SHAMap.cpp:1248
bool addItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:882
SHAMapHash getHash() const
Definition SHAMap.cpp:890
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:617
bool delItem(uint256 const &id)
Definition SHAMap.cpp:721
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)