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(SHAMapNodeType::tnACCOUNT_STATE, std::move(*item)))
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  TestNodeFamily 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(
103  if (i % 100 == 0)
104  source.invariants();
105  }
106 
107  source.invariants();
108  BEAST_EXPECT(confuseMap(source, 500));
109  source.invariants();
110 
111  source.setImmutable();
112 
113  int count = 0;
114  source.visitLeaves([&count](auto const& item) { ++count; });
115  BEAST_EXPECT(count == items);
116 
117  std::vector<SHAMapMissingNode> missingNodes;
118  source.walkMap(missingNodes, 2048);
119  BEAST_EXPECT(missingNodes.empty());
120 
121  std::vector<SHAMapNodeID> nodeIDs, gotNodeIDs;
122  std::vector<Blob> gotNodes;
123  std::vector<uint256> hashes;
124 
125  destination.setSynching();
126 
127  {
128  std::vector<SHAMapNodeID> gotNodeIDs_a;
129  std::vector<Blob> gotNodes_a;
130 
131  BEAST_EXPECT(source.getNodeFat(
132  SHAMapNodeID(),
133  gotNodeIDs_a,
134  gotNodes_a,
135  rand_bool(eng_),
136  rand_int(eng_, 2)));
137 
138  unexpected(gotNodes_a.size() < 1, "NodeSize");
139 
140  BEAST_EXPECT(destination
141  .addRootNode(
142  source.getHash(),
143  makeSlice(*gotNodes_a.begin()),
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:1114
ripple::SHAMap::clearSynching
void clearSynching()
Definition: SHAMap.h:533
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:778
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:667
ripple::SHAMap::addItem
bool addItem(SHAMapNodeType type, SHAMapItem &&i)
Definition: SHAMap.cpp:772
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:186
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:47
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::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:315
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
ripple::SHAMap::walkMap
void walkMap(std::vector< SHAMapMissingNode > &missingNodes, int maxMissing) const
Definition: SHAMapDelta.cpp:249
ripple::Serializer
Definition: Serializer.h:39
ripple::SHAMap::setImmutable
void setImmutable()
Definition: SHAMap.h:514
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::tests::SHAMapSync_test::confuseMap
bool confuseMap(SHAMap &map, int count)
Definition: SHAMapSync_test.cpp:49
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:426
ripple::SHAMap::delItem
bool delItem(uint256 const &id)
Definition: SHAMap.cpp:625
ripple::SHAMap::setSynching
void setSynching()
Definition: SHAMap.h:527