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  return std::make_shared<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 
54  std::list<uint256> items;
55 
56  for (int i = 0; i < count; ++i)
57  {
59  items.push_back(item->key());
60 
61  if (!map.addItem(SHAMapNodeType::tnACCOUNT_STATE, std::move(*item)))
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  {
100  source.addItem(
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  {
128 
129  BEAST_EXPECT(source.getNodeFat(
130  SHAMapNodeID(), a, rand_bool(eng_), rand_int(eng_, 2)));
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 
191 BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, ripple);
192 
193 } // namespace tests
194 } // namespace ripple
ripple::SHAMap::invariants
void invariants() const
Definition: SHAMap.cpp:1178
ripple::SHAMap::clearSynching
void clearSynching()
Definition: SHAMap.h:611
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:241
std::shared_ptr
STL class.
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:842
ripple::tests::SHAMapSync_test::run
void run() override
Definition: SHAMapSync_test.cpp:88
std::list
STL class.
ripple::SHAMap::deepCompare
bool deepCompare(SHAMap &other) const
Definition: SHAMapSync.cpp:667
ripple::SHAMap::addItem
bool addItem(SHAMapNodeType type, SHAMapItem &&i)
Definition: SHAMap.cpp:836
ripple::SHAMapNodeType::tnACCOUNT_STATE
@ tnACCOUNT_STATE
std::vector
STL class.
std::vector::size
T size(T... args)
std::chrono::seconds
ripple::tests::TestNodeFamily
Definition: common.h:32
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
Identifies a node inside a SHAMap.
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:194
ripple::SHAMapHash
Definition: SHAMapHash.h:32
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:95
ripple::tests::SHAMapSync_test
Definition: SHAMapSync_test.cpp:32
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:63
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:317
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
ripple::SHAMap::walkMap
void walkMap(std::vector< SHAMapMissingNode > &missingNodes, int maxMissing) const
Definition: SHAMapDelta.cpp:252
ripple::Serializer
Definition: Serializer.h:39
ripple::SHAMap::setImmutable
void setImmutable()
Definition: SHAMap.h:592
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)
ripple::tests::SHAMapSync_test::confuseMap
bool confuseMap(SHAMap &map, int count)
Definition: SHAMapSync_test.cpp:48
std::vector::empty
T empty(T... args)
ripple::SHAMapType::FREE
@ FREE
ripple::SHAMap::getNodeFat
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< std::pair< SHAMapNodeID, Blob >> &data, bool fatLeaves, std::uint32_t depth) const
Definition: SHAMapSync.cpp:427
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:196
ripple::SHAMap::delItem
bool delItem(uint256 const &id)
Definition: SHAMap.cpp:690
ripple::SHAMap::setSynching
void setSynching()
Definition: SHAMap.h:605