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 
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 
54  std::list<uint256> items;
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 
115  std::vector<SHAMapMissingNode> missingNodes;
116  source.walkMap(missingNodes, 2048);
117  BEAST_EXPECT(missingNodes.empty());
118 
119  std::vector<SHAMapNodeID> nodeIDs, gotNodeIDs;
120  std::vector<Blob> gotNodes;
121  std::vector<uint256> hashes;
122 
123  destination.setSynching();
124 
125  {
127 
128  BEAST_EXPECT(source.getNodeFat(
129  SHAMapNodeID(), a, rand_bool(eng_), rand_int(eng_, 2)));
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 
190 BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, ripple);
191 
192 } // namespace tests
193 } // namespace ripple
ripple::SHAMap::invariants
void invariants() const
Definition: SHAMap.cpp:1188
ripple::SHAMap::clearSynching
void clearSynching()
Definition: SHAMap.h:619
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
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:852
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::SHAMapNodeType::tnACCOUNT_STATE
@ tnACCOUNT_STATE
ripple::make_shamapitem
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition: SHAMapItem.h:160
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
boost::intrusive_ptr< SHAMapItem > makeRandomAS()
Definition: SHAMapSync_test.cpp:38
ripple::Serializer::getSHA512Half
uint256 getSHA512Half() const
Definition: Serializer.cpp:194
ripple::SHAMap::addItem
bool addItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition: SHAMap.cpp:844
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
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:236
ripple::Serializer
Definition: Serializer.h:39
ripple::SHAMap::setImmutable
void setImmutable()
Definition: SHAMap.h:600
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:696
ripple::SHAMap::setSynching
void setSynching()
Definition: SHAMap.h:613
ripple::SHAMap::visitLeaves
void visitLeaves(std::function< void(boost::intrusive_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:27