rippled
SHAMapNodeID.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/beast/core/LexicalCast.h>
21 #include <ripple/crypto/csprng.h>
22 #include <ripple/protocol/Serializer.h>
23 #include <ripple/shamap/SHAMap.h>
24 #include <ripple/shamap/SHAMapNodeID.h>
25 #include <cassert>
26 
27 namespace ripple {
28 
29 static uint256 const&
30 depthMask(unsigned int depth)
31 {
32  enum { mask_size = 65 };
33 
34  struct masks_t
35  {
36  uint256 entry[mask_size];
37 
38  masks_t()
39  {
40  uint256 selector;
41  for (int i = 0; i < mask_size - 1; i += 2)
42  {
43  entry[i] = selector;
44  *(selector.begin() + (i / 2)) = 0xF0;
45  entry[i + 1] = selector;
46  *(selector.begin() + (i / 2)) = 0xFF;
47  }
48  entry[mask_size - 1] = selector;
49  }
50  };
51 
52  static masks_t const masks;
53  return masks.entry[depth];
54 }
55 
56 // canonicalize the hash to a node ID for this depth
57 SHAMapNodeID::SHAMapNodeID(unsigned int depth, uint256 const& hash)
58  : id_(hash), depth_(depth)
59 {
60  assert(depth <= SHAMap::leafDepth);
61  assert(id_ == (id_ & depthMask(depth)));
62 }
63 
66 {
67  Serializer s(33);
68  s.addBitString(id_);
69  s.add8(depth_);
70  return s.getString();
71 }
72 
74 SHAMapNodeID::getChildNodeID(unsigned int m) const
75 {
76  assert(m < SHAMap::branchFactor);
77 
78  // A SHAMap has exactly 65 levels, so nodes must not exceed that
79  // depth; if they do, this breaks the invariant of never allowing
80  // the construction of a SHAMapNodeID at an invalid depth. We assert
81  // to catch this in debug builds.
82  //
83  // We throw (but never assert) if the node is at level 64, since
84  // entries at that depth are leaf nodes and have no children and even
85  // constructing a child node from them would break the above invariant.
86  assert(depth_ <= SHAMap::leafDepth);
87 
89  Throw<std::logic_error>(
90  "Request for child node ID of " + to_string(*this));
91 
92  if (id_ != (id_ & depthMask(depth_)))
93  Throw<std::logic_error>("Incorrect mask for " + to_string(*this));
94 
95  SHAMapNodeID node{depth_ + 1, id_};
96  node.id_.begin()[depth_ / 2] |= (depth_ & 1) ? m : (m << 4);
97  return node;
98 }
99 
100 [[nodiscard]] std::optional<SHAMapNodeID>
101 deserializeSHAMapNodeID(void const* data, std::size_t size)
102 {
104 
105  if (size == 33)
106  {
107  unsigned int depth = *(static_cast<unsigned char const*>(data) + 32);
108  if (depth <= SHAMap::leafDepth)
109  {
110  auto const id = uint256::fromVoid(data);
111 
112  if (id == (id & depthMask(depth)))
113  ret.emplace(depth, id);
114  }
115  }
116 
117  return ret;
118 }
119 
120 [[nodiscard]] unsigned int
121 selectBranch(SHAMapNodeID const& id, uint256 const& hash)
122 {
123  auto const depth = id.getDepth();
124  auto branch = static_cast<unsigned int>(*(hash.begin() + (depth / 2)));
125 
126  if (depth & 1)
127  branch &= 0xf;
128  else
129  branch >>= 4;
130 
131  assert(branch < SHAMap::branchFactor);
132  return branch;
133 }
134 
135 SHAMapNodeID
136 SHAMapNodeID::createID(int depth, uint256 const& key)
137 {
138  assert((depth >= 0) && (depth < 65));
139  return SHAMapNodeID(depth, key & depthMask(depth));
140 }
141 
142 } // namespace ripple
ripple::SHAMap::branchFactor
static constexpr unsigned int branchFactor
Number of children each non-leaf node has (the 'radix tree' part of the map)
Definition: SHAMap.h:116
ripple::SHAMapNodeID::getChildNodeID
SHAMapNodeID getChildNodeID(unsigned int m) const
Definition: SHAMapNodeID.cpp:74
std::string
STL class.
ripple::selectBranch
unsigned int selectBranch(SHAMapNodeID const &id, uint256 const &hash)
Returns the branch that would contain the given hash.
Definition: SHAMapNodeID.cpp:121
ripple::deserializeSHAMapNodeID
std::optional< SHAMapNodeID > deserializeSHAMapNodeID(void const *data, std::size_t size)
Return an object representing a serialized SHAMap Node ID.
Definition: SHAMapNodeID.cpp:101
ripple::Serializer::getString
std::string getString() const
Definition: Serializer.h:204
ripple::Serializer::add8
int add8(unsigned char i)
Definition: Serializer.cpp:166
ripple::SHAMapNodeID::id_
uint256 id_
Definition: SHAMapNodeID.h:36
std::optional::emplace
T emplace(T... args)
ripple::SHAMapNodeID
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:33
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:550
ripple::SHAMapNodeID::SHAMapNodeID
SHAMapNodeID()=default
ripple::base_uint< 256 >
ripple::depthMask
static uint256 const & depthMask(unsigned int depth)
Definition: SHAMapNodeID.cpp:30
ripple::SHAMapNodeID::getRawString
std::string getRawString() const
Definition: SHAMapNodeID.cpp:65
ripple::SHAMapNodeID::depth_
unsigned int depth_
Definition: SHAMapNodeID.h:37
ripple::Serializer
Definition: Serializer.h:39
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:97
ripple::base_uint::begin
iterator begin()
Definition: base_uint.h:133
ripple::base_uint< 256 >::fromVoid
static base_uint fromVoid(void const *data)
Definition: base_uint.h:312
cassert
ripple::SHAMap::leafDepth
static constexpr unsigned int leafDepth
The depth of the hash map: data is only present in the leaves.
Definition: SHAMap.h:120
std::optional
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::SHAMapNodeID::createID
static SHAMapNodeID createID(int depth, uint256 const &key)
Create a SHAMapNodeID of a node with the depth of the node and the key of a leaf.
Definition: SHAMapNodeID.cpp:136