rippled
SHAMap_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/Blob.h>
21 #include <ripple/basics/StringUtilities.h>
22 #include <ripple/beast/unit_test.h>
23 #include <ripple/beast/utility/Journal.h>
24 #include <ripple/shamap/SHAMap.h>
25 #include <test/shamap/common.h>
26 #include <test/unit_test/SuiteJournal.h>
27 
28 namespace ripple {
29 namespace tests {
30 
31 #ifndef __INTELLISENSE__
32 static_assert(std::is_nothrow_destructible<SHAMap>{}, "");
33 static_assert(!std::is_default_constructible<SHAMap>{}, "");
34 static_assert(!std::is_copy_constructible<SHAMap>{}, "");
35 static_assert(!std::is_copy_assignable<SHAMap>{}, "");
36 static_assert(!std::is_move_constructible<SHAMap>{}, "");
37 static_assert(!std::is_move_assignable<SHAMap>{}, "");
38 
45 
46 static_assert(std::is_nothrow_destructible<SHAMapItem>{}, "");
47 static_assert(!std::is_default_constructible<SHAMapItem>{}, "");
48 static_assert(std::is_copy_constructible<SHAMapItem>{}, "");
49 static_assert(std::is_copy_assignable<SHAMapItem>{}, "");
50 static_assert(std::is_move_constructible<SHAMapItem>{}, "");
51 static_assert(std::is_move_assignable<SHAMapItem>{}, "");
52 
55 static_assert(std::is_copy_constructible<SHAMapNodeID>{}, "");
56 static_assert(std::is_copy_assignable<SHAMapNodeID>{}, "");
57 static_assert(std::is_move_constructible<SHAMapNodeID>{}, "");
58 static_assert(std::is_move_assignable<SHAMapNodeID>{}, "");
59 
60 static_assert(std::is_nothrow_destructible<SHAMapHash>{}, "");
62 static_assert(std::is_copy_constructible<SHAMapHash>{}, "");
63 static_assert(std::is_copy_assignable<SHAMapHash>{}, "");
64 static_assert(std::is_move_constructible<SHAMapHash>{}, "");
65 static_assert(std::is_move_assignable<SHAMapHash>{}, "");
66 
69 static_assert(!std::is_copy_constructible<SHAMapTreeNode>{}, "");
70 static_assert(!std::is_copy_assignable<SHAMapTreeNode>{}, "");
71 static_assert(!std::is_move_constructible<SHAMapTreeNode>{}, "");
72 static_assert(!std::is_move_assignable<SHAMapTreeNode>{}, "");
73 
77 static_assert(!std::is_copy_assignable<SHAMapInnerNode>{}, "");
79 static_assert(!std::is_move_assignable<SHAMapInnerNode>{}, "");
80 
83 static_assert(!std::is_copy_constructible<SHAMapLeafNode>{}, "");
84 static_assert(!std::is_copy_assignable<SHAMapLeafNode>{}, "");
85 static_assert(!std::is_move_constructible<SHAMapLeafNode>{}, "");
86 static_assert(!std::is_move_assignable<SHAMapLeafNode>{}, "");
87 #endif
88 
89 inline bool
90 operator==(SHAMapItem const& a, SHAMapItem const& b)
91 {
92  return a.key() == b.key();
93 }
94 inline bool
95 operator!=(SHAMapItem const& a, SHAMapItem const& b)
96 {
97  return a.key() != b.key();
98 }
99 inline bool
100 operator==(SHAMapItem const& a, uint256 const& b)
101 {
102  return a.key() == b;
103 }
104 inline bool
105 operator!=(SHAMapItem const& a, uint256 const& b)
106 {
107  return a.key() != b;
108 }
109 
110 class SHAMap_test : public beast::unit_test::suite
111 {
112 public:
113  static Blob
114  IntToVUC(int v)
115  {
116  Blob vuc;
117 
118  for (int i = 0; i < 32; ++i)
119  vuc.push_back(static_cast<unsigned char>(v));
120 
121  return vuc;
122  }
123 
124  void
125  run() override
126  {
127  using namespace beast::severities;
128  test::SuiteJournal journal("SHAMap_test", *this);
129 
130  run(true, journal);
131  run(false, journal);
132  }
133 
134  void
135  run(bool backed, beast::Journal const& journal)
136  {
137  if (backed)
138  testcase("add/traverse backed");
139  else
140  testcase("add/traverse unbacked");
141 
142  tests::TestNodeFamily f(journal);
143 
144  // h3 and h4 differ only in the leaf, same terminal node (level 19)
145  uint256 h1, h2, h3, h4, h5;
146  (void)h1.parseHex(
147  "092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
148  (void)h2.parseHex(
149  "436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe");
150  (void)h3.parseHex(
151  "b92891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
152  (void)h4.parseHex(
153  "b92891fe4ef6cee585fdc6fda2e09eb4d386363158ec3321b8123e5a772c6ca8");
154  (void)h5.parseHex(
155  "a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
156 
157  SHAMap sMap(SHAMapType::FREE, f);
158  sMap.invariants();
159  if (!backed)
160  sMap.setUnbacked();
161 
162  SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)),
163  i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
164  unexpected(
166  "no add");
167  sMap.invariants();
168  unexpected(
170  "no add");
171  sMap.invariants();
172 
173  auto i = sMap.begin();
174  auto e = sMap.end();
175  unexpected(i == e || (*i != i1), "bad traverse");
176  ++i;
177  unexpected(i == e || (*i != i2), "bad traverse");
178  ++i;
179  unexpected(i != e, "bad traverse");
181  sMap.invariants();
182  sMap.delItem(i2.key());
183  sMap.invariants();
185  sMap.invariants();
186  i = sMap.begin();
187  e = sMap.end();
188  unexpected(i == e || (*i != i1), "bad traverse");
189  ++i;
190  unexpected(i == e || (*i != i3), "bad traverse");
191  ++i;
192  unexpected(i == e || (*i != i4), "bad traverse");
193  ++i;
194  unexpected(i != e, "bad traverse");
195 
196  if (backed)
197  testcase("snapshot backed");
198  else
199  testcase("snapshot unbacked");
200 
201  SHAMapHash mapHash = sMap.getHash();
202  std::shared_ptr<SHAMap> map2 = sMap.snapShot(false);
203  map2->invariants();
204  unexpected(sMap.getHash() != mapHash, "bad snapshot");
205  unexpected(map2->getHash() != mapHash, "bad snapshot");
206 
207  SHAMap::Delta delta;
208  BEAST_EXPECT(sMap.compare(*map2, delta, 100));
209  BEAST_EXPECT(delta.empty());
210 
211  unexpected(!sMap.delItem(sMap.begin()->key()), "bad mod");
212  sMap.invariants();
213  unexpected(sMap.getHash() == mapHash, "bad snapshot");
214  unexpected(map2->getHash() != mapHash, "bad snapshot");
215 
216  BEAST_EXPECT(sMap.compare(*map2, delta, 100));
217  BEAST_EXPECT(delta.size() == 1);
218  BEAST_EXPECT(delta.begin()->first == h1);
219  BEAST_EXPECT(delta.begin()->second.first == nullptr);
220  BEAST_EXPECT(delta.begin()->second.second->key() == h1);
221 
222  sMap.dump();
223 
224  if (backed)
225  testcase("build/tear backed");
226  else
227  testcase("build/tear unbacked");
228  {
229  std::vector<uint256> keys(8);
230  (void)keys[0].parseHex(
231  "b92891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
232  "a8");
233  (void)keys[1].parseHex(
234  "b92881fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
235  "a8");
236  (void)keys[2].parseHex(
237  "b92691fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
238  "a8");
239  (void)keys[3].parseHex(
240  "b92791fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
241  "a8");
242  (void)keys[4].parseHex(
243  "b91891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
244  "a8");
245  (void)keys[5].parseHex(
246  "b99891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
247  "a8");
248  (void)keys[6].parseHex(
249  "f22891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
250  "a8");
251  (void)keys[7].parseHex(
252  "292891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
253  "a8");
254 
255  std::vector<uint256> hashes(8);
256  (void)hashes[0].parseHex(
257  "B7387CFEA0465759ADC718E8C42B52D2309D179B326E239EB5075C64B6281F"
258  "7F");
259  (void)hashes[1].parseHex(
260  "FBC195A9592A54AB44010274163CB6BA95F497EC5BA0A8831845467FB2ECE2"
261  "66");
262  (void)hashes[2].parseHex(
263  "4E7D2684B65DFD48937FFB775E20175C43AF0C94066F7D5679F51AE756795B"
264  "75");
265  (void)hashes[3].parseHex(
266  "7A2F312EB203695FFD164E038E281839EEF06A1B99BFC263F3CECC6C74F93E"
267  "07");
268  (void)hashes[4].parseHex(
269  "395A6691A372387A703FB0F2C6D2C405DAF307D0817F8F0E207596462B0E3A"
270  "3E");
271  (void)hashes[5].parseHex(
272  "D044C0A696DE3169CC70AE216A1564D69DE96582865796142CE7D98A84D9DD"
273  "E4");
274  (void)hashes[6].parseHex(
275  "76DCC77C4027309B5A91AD164083264D70B77B5E43E08AEDA5EBF943611436"
276  "15");
277  (void)hashes[7].parseHex(
278  "DF4220E93ADC6F5569063A01B4DC79F8DB9553B6A3222ADE23DEA02BBE7230"
279  "E5");
280 
281  SHAMap map(SHAMapType::FREE, f);
282  if (!backed)
283  map.setUnbacked();
284 
285  BEAST_EXPECT(map.getHash() == beast::zero);
286  for (int k = 0; k < keys.size(); ++k)
287  {
288  SHAMapItem item(keys[k], IntToVUC(k));
289  BEAST_EXPECT(map.addItem(
290  SHAMapNodeType::tnTRANSACTION_NM, std::move(item)));
291  BEAST_EXPECT(map.getHash().as_uint256() == hashes[k]);
292  map.invariants();
293  }
294  for (int k = keys.size() - 1; k >= 0; --k)
295  {
296  BEAST_EXPECT(map.getHash().as_uint256() == hashes[k]);
297  BEAST_EXPECT(map.delItem(keys[k]));
298  map.invariants();
299  }
300  BEAST_EXPECT(map.getHash() == beast::zero);
301  }
302 
303  if (backed)
304  testcase("iterate backed");
305  else
306  testcase("iterate unbacked");
307 
308  {
309  std::vector<uint256> keys(8);
310  (void)keys[0].parseHex(
311  "f22891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
312  "a8");
313  (void)keys[1].parseHex(
314  "b99891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
315  "a8");
316  (void)keys[2].parseHex(
317  "b92891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
318  "a8");
319  (void)keys[3].parseHex(
320  "b92881fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
321  "a8");
322  (void)keys[4].parseHex(
323  "b92791fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
324  "a8");
325  (void)keys[5].parseHex(
326  "b92691fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
327  "a8");
328  (void)keys[6].parseHex(
329  "b91891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
330  "a8");
331  (void)keys[7].parseHex(
332  "292891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6c"
333  "a8");
334 
335  tests::TestNodeFamily tf{journal};
336  SHAMap map{SHAMapType::FREE, tf};
337  if (!backed)
338  map.setUnbacked();
339  for (auto const& k : keys)
340  {
341  map.addItem(
343  SHAMapItem{k, IntToVUC(0)});
344  map.invariants();
345  }
346 
347  int h = 7;
348  for (auto const& k : map)
349  {
350  BEAST_EXPECT(k.key() == keys[h]);
351  --h;
352  }
353  }
354  }
355 };
356 
357 BEAST_DEFINE_TESTSUITE(SHAMap, ripple_app, ripple);
358 
359 } // namespace tests
360 } // namespace ripple
ripple::tests::SHAMap_test
Definition: SHAMap_test.cpp:110
ripple::SHAMap::invariants
void invariants() const
Definition: SHAMap.cpp:1114
std::shared_ptr
STL class.
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:778
std::is_nothrow_destructible
ripple::SHAMap::addItem
bool addItem(SHAMapNodeType type, SHAMapItem &&i)
Definition: SHAMap.cpp:772
ripple::tests::SHAMap_test::run
void run(bool backed, beast::Journal const &journal)
Definition: SHAMap_test.cpp:135
ripple::SHAMap::dump
void dump(bool withHashes=false) const
Definition: SHAMap.cpp:1050
std::vector< unsigned char >
std::map::size
T size(T... args)
ripple::tests::TestNodeFamily
Definition: common.h:32
std::is_default_constructible
beast::severities
A namespace for easy access to logging severity values.
Definition: Journal.h:29
ripple::SHAMap::begin
const_iterator begin() const
Definition: SHAMap.h:653
ripple::tests::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(cluster, overlay, ripple)
ripple::SHAMap::snapShot
std::shared_ptr< SHAMap > snapShot(bool isMutable) const
Definition: SHAMap.cpp:70
ripple::tests::operator!=
bool operator!=(SHAMapItem const &a, SHAMapItem const &b)
Definition: SHAMap_test.cpp:95
std::is_move_constructible
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:47
ripple::SHAMapNodeType::tnTRANSACTION_NM
@ tnTRANSACTION_NM
std::vector::push_back
T push_back(T... args)
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:73
ripple::SHAMapItem::key
uint256 const & key() const
Definition: SHAMapItem.h:82
ripple::SHAMapItem
Definition: SHAMapItem.h:35
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:95
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::map
STL class.
ripple::tests::operator==
bool operator==(SHAMapItem const &a, SHAMapItem const &b)
Definition: SHAMap_test.cpp:90
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
std::is_copy_constructible
std::is_move_assignable
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::SHAMap::setUnbacked
void setUnbacked()
Definition: SHAMap.h:543
ripple::base_uint::parseHex
bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:384
std::map::begin
T begin(T... args)
ripple::SHAMap::end
const_iterator end() const
Definition: SHAMap.h:659
ripple::tests::SHAMap_test::run
void run() override
Definition: SHAMap_test.cpp:125
std::map::empty
T empty(T... args)
ripple::SHAMap::compare
bool compare(SHAMap const &otherMap, Delta &differences, int maxCount) const
Definition: SHAMapDelta.cpp:124
ripple::SHAMapType::FREE
@ FREE
std::is_copy_assignable
ripple::SHAMapHash::as_uint256
uint256 const & as_uint256() const
Definition: SHAMapTreeNode.h:58
ripple::SHAMap::delItem
bool delItem(uint256 const &id)
Definition: SHAMap.cpp:625
ripple::tests::SHAMap_test::IntToVUC
static Blob IntToVUC(int v)
Definition: SHAMap_test.cpp:114