rippled
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 <ripple/basics/StringUtilities.h>
21 #include <ripple/basics/random.h>
22 #include <ripple/beast/unit_test.h>
23 #include <ripple/beast/xor_shift_engine.h>
24 #include <ripple/shamap/SHAMap.h>
25 #include <ripple/shamap/SHAMapItem.h>
26 #include <test/shamap/common.h>
27 #include <test/unit_test/SuiteJournal.h>
28 
29 namespace ripple {
30 namespace tests {
31 
32 class SHAMapSync_test : public beast::unit_test::suite
33 {
34 public:
36 
39  {
40  Serializer s;
41 
42  for (int d = 0; d < 3; ++d)
43  s.add32(rand_int<std::uint32_t>(eng_));
44 
45  return std::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData());
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 
55  std::list<uint256> items;
56 
57  for (int i = 0; i < count; ++i)
58  {
60  items.push_back(item->key());
61 
62  if (!map.addItem(std::move(*item), false, false))
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  TestFamily 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  {
101  source.addItem(std::move(*makeRandomAS()), false, false);
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 
116  std::vector<SHAMapMissingNode> missingNodes;
117  source.walkMap(missingNodes, 2048);
118  BEAST_EXPECT(missingNodes.empty());
119 
120  std::vector<SHAMapNodeID> nodeIDs, gotNodeIDs;
121  std::vector<Blob> gotNodes;
122  std::vector<uint256> hashes;
123 
124  destination.setSynching();
125 
126  {
127  std::vector<SHAMapNodeID> gotNodeIDs_a;
128  std::vector<Blob> gotNodes_a;
129 
130  BEAST_EXPECT(source.getNodeFat(
131  SHAMapNodeID(),
132  gotNodeIDs_a,
133  gotNodes_a,
134  rand_bool(eng_),
135  rand_int(eng_, 2)));
136 
137  unexpected(gotNodes_a.size() < 1, "NodeSize");
138 
139  BEAST_EXPECT(destination
140  .addRootNode(
141  source.getHash(),
142  makeSlice(*gotNodes_a.begin()),
143  snfWIRE,
144  nullptr)
145  .isGood());
146  }
147 
148  do
149  {
150  f.clock().advance(std::chrono::seconds(1));
151 
152  // get the list of nodes we know we need
153  auto nodesMissing = destination.getMissingNodes(2048, nullptr);
154 
155  if (nodesMissing.empty())
156  break;
157 
158  // get as many nodes as possible based on this information
159  std::vector<SHAMapNodeID> gotNodeIDs_b;
160  std::vector<Blob> gotNodes_b;
161 
162  for (auto& it : nodesMissing)
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 (!source.getNodeFat(
168  it.first,
169  gotNodeIDs_b,
170  gotNodes_b,
171  rand_bool(eng_),
172  rand_int(eng_, 2)))
173  fail("", __FILE__, __LINE__);
174  }
175 
176  // Don't use BEAST_EXPECT here b/c it will be called a
177  // non-deterministic number of times and the number of tests run
178  // should be deterministic
179  if (gotNodeIDs_b.size() != gotNodes_b.size() ||
180  gotNodeIDs_b.empty())
181  fail("", __FILE__, __LINE__);
182 
183  for (std::size_t i = 0; i < gotNodeIDs_b.size(); ++i)
184  {
185  // Don't use BEAST_EXPECT here b/c it will be called a
186  // non-deterministic number of times and the number of tests run
187  // should be deterministic
188  if (!destination
189  .addKnownNode(
190  gotNodeIDs_b[i], makeSlice(gotNodes_b[i]), nullptr)
191  .isUseful())
192  fail("", __FILE__, __LINE__);
193  }
194  } while (true);
195 
196  destination.clearSynching();
197 
198  BEAST_EXPECT(source.deepCompare(destination));
199 
200  log << "Checking destination invariants..." << std::endl;
201  destination.invariants();
202  }
203 };
204 
205 BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, ripple);
206 
207 } // namespace tests
208 } // namespace ripple
ripple::SHAMap::invariants
void invariants() const
Definition: SHAMap.cpp:1130
ripple::SHAMap::clearSynching
void clearSynching()
Definition: SHAMap.h:517
ripple::makeSlice
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:194
std::shared_ptr
STL class.
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:789
ripple::tests::SHAMapSync_test::run
void run() override
Definition: SHAMapSync_test.cpp:89
std::list
STL class.
ripple::SHAMap::deepCompare
bool deepCompare(SHAMap &other) const
Definition: SHAMapSync.cpp:680
ripple::tests::TestFamily
Definition: common.h:32
ripple::SHAMap::getNodeFat
bool getNodeFat(SHAMapNodeID node, std::vector< SHAMapNodeID > &nodeIDs, std::vector< Blob > &rawNode, bool fatLeaves, std::uint32_t depth) const
Definition: SHAMapSync.cpp:442
std::vector
STL class.
std::vector::size
T size(T... args)
std::chrono::seconds
beast::severities
A namespace for easy access to logging severity values.
Definition: Journal.h:29
ripple::tests::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(cluster, overlay, ripple)
ripple::SHAMapNodeID
Definition: SHAMapNodeID.h:33
ripple::tests::SHAMapSync_test::makeRandomAS
std::shared_ptr< SHAMapItem > makeRandomAS()
Definition: SHAMapSync_test.cpp:38
ripple::Serializer::getSHA512Half
uint256 getSHA512Half() const
Definition: Serializer.cpp:186
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:43
std::list::push_back
T push_back(T... args)
ripple::rand_int
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Definition: ripple/basics/random.h:115
ripple::SHAMap::visitLeaves
void visitLeaves(std::function< void(std::shared_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:27
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:81
ripple::tests::SHAMapSync_test
Definition: SHAMapSync_test.cpp:32
ripple::tests::SHAMapSync_test::eng_
beast::xor_shift_engine eng_
Definition: SHAMapSync_test.cpp:35
ripple::SHAMap::getMissingNodes
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter *filter)
Check for nodes in the SHAMap not available.
Definition: SHAMapSync.cpp:316
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
ripple::SHAMap::walkMap
void walkMap(std::vector< SHAMapMissingNode > &missingNodes, int maxMissing) const
Definition: SHAMapDelta.cpp:250
ripple::Serializer
Definition: Serializer.h:39
ripple::SHAMap::setImmutable
void setImmutable()
Definition: SHAMap.h:497
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::endl
T endl(T... args)
std::vector::begin
T begin(T... args)
ripple::Serializer::peekData
Blob const & peekData() const
Definition: Serializer.h:166
ripple::snfWIRE
@ snfWIRE
Definition: SHAMapTreeNode.h:37
ripple::tests::SHAMapSync_test::confuseMap
bool confuseMap(SHAMap &map, int count)
Definition: SHAMapSync_test.cpp:49
std::vector::empty
T empty(T... args)
ripple::SHAMap::addItem
bool addItem(SHAMapItem &&i, bool isTransaction, bool hasMeta)
Definition: SHAMap.cpp:780
ripple::SHAMapType::FREE
@ FREE
std::size_t
beast::detail::xor_shift_engine
Definition: xor_shift_engine.h:32
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::rand_bool
bool rand_bool(Engine &engine)
Return a random boolean value.
Definition: ripple/basics/random.h:169
ripple::SHAMap::delItem
bool delItem(uint256 const &id)
Definition: SHAMap.cpp:621
ripple::SHAMap::setSynching
void setSynching()
Definition: SHAMap.h:511