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