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  {
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  nullptr)
144  .isGood());
145  }
146 
147  do
148  {
149  f.clock().advance(std::chrono::seconds(1));
150 
151  // get the list of nodes we know we need
152  auto nodesMissing = destination.getMissingNodes(2048, nullptr);
153 
154  if (nodesMissing.empty())
155  break;
156 
157  // get as many nodes as possible based on this information
158  std::vector<SHAMapNodeID> gotNodeIDs_b;
159  std::vector<Blob> gotNodes_b;
160 
161  for (auto& it : nodesMissing)
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 (!source.getNodeFat(
167  it.first,
168  gotNodeIDs_b,
169  gotNodes_b,
170  rand_bool(eng_),
171  rand_int(eng_, 2)))
172  fail("", __FILE__, __LINE__);
173  }
174 
175  // Don't use BEAST_EXPECT here b/c it will be called a
176  // non-deterministic number of times and the number of tests run
177  // should be deterministic
178  if (gotNodeIDs_b.size() != gotNodes_b.size() ||
179  gotNodeIDs_b.empty())
180  fail("", __FILE__, __LINE__);
181 
182  for (std::size_t i = 0; i < gotNodeIDs_b.size(); ++i)
183  {
184  // Don't use BEAST_EXPECT here b/c it will be called a
185  // non-deterministic number of times and the number of tests run
186  // should be deterministic
187  if (!destination
188  .addKnownNode(
189  gotNodeIDs_b[i], makeSlice(gotNodes_b[i]), nullptr)
190  .isUseful())
191  fail("", __FILE__, __LINE__);
192  }
193  } while (true);
194 
195  destination.clearSynching();
196 
197  BEAST_EXPECT(source.deepCompare(destination));
198 
199  log << "Checking destination invariants..." << std::endl;
200  destination.invariants();
201  }
202 };
203 
204 BEAST_DEFINE_TESTSUITE(SHAMapSync, shamap, ripple);
205 
206 } // namespace tests
207 } // namespace ripple
ripple::SHAMap::invariants
void invariants() const
Definition: SHAMap.cpp:1119
ripple::SHAMap::clearSynching
void clearSynching()
Definition: SHAMap.h:578
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:240
std::shared_ptr
STL class.
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:783
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:668
ripple::SHAMap::addItem
bool addItem(SHAMapNodeType type, SHAMapItem &&i)
Definition: SHAMap.cpp:777
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:559
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::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
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::getNodeFat
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< SHAMapNodeID > &nodeIDs, std::vector< Blob > &rawNodes, bool fatLeaves, std::uint32_t depth) const
Definition: SHAMapSync.cpp:427
ripple::SHAMap::delItem
bool delItem(uint256 const &id)
Definition: SHAMap.cpp:630
ripple::SHAMap::setSynching
void setSynching()
Definition: SHAMap.h:572