rippled
Loading...
Searching...
No Matches
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 <xrpld/shamap/SHAMap.h>
21#include <xrpld/shamap/SHAMapNodeID.h>
22#include <xrpl/beast/core/LexicalCast.h>
23#include <xrpl/beast/utility/instrumentation.h>
24#include <xrpl/crypto/csprng.h>
25#include <xrpl/protocol/Serializer.h>
26
27namespace ripple {
28
29static uint256 const&
30depthMask(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
57SHAMapNodeID::SHAMapNodeID(unsigned int depth, uint256 const& hash)
58 : id_(hash), depth_(depth)
59{
60 XRPL_ASSERT(
61 depth <= SHAMap::leafDepth,
62 "ripple::SHAMapNodeID::SHAMapNodeID : maximum depth input");
63 XRPL_ASSERT(
64 id_ == (id_ & depthMask(depth)),
65 "ripple::SHAMapNodeID::SHAMapNodeID : hash and depth inputs do match");
66}
67
70{
71 Serializer s(33);
73 s.add8(depth_);
74 return s.getString();
75}
76
78SHAMapNodeID::getChildNodeID(unsigned int m) const
79{
80 XRPL_ASSERT(
82 "ripple::SHAMapNodeID::getChildNodeID : valid branch input");
83
84 // A SHAMap has exactly 65 levels, so nodes must not exceed that
85 // depth; if they do, this breaks the invariant of never allowing
86 // the construction of a SHAMapNodeID at an invalid depth. We assert
87 // to catch this in debug builds.
88 //
89 // We throw (but never assert) if the node is at level 64, since
90 // entries at that depth are leaf nodes and have no children and even
91 // constructing a child node from them would break the above invariant.
92 XRPL_ASSERT(
94 "ripple::SHAMapNodeID::getChildNodeID : maximum leaf depth");
95
97 Throw<std::logic_error>(
98 "Request for child node ID of " + to_string(*this));
99
100 if (id_ != (id_ & depthMask(depth_)))
101 Throw<std::logic_error>("Incorrect mask for " + to_string(*this));
102
103 SHAMapNodeID node{depth_ + 1, id_};
104 node.id_.begin()[depth_ / 2] |= (depth_ & 1) ? m : (m << 4);
105 return node;
106}
107
108[[nodiscard]] std::optional<SHAMapNodeID>
110{
112
113 if (size == 33)
114 {
115 unsigned int depth = *(static_cast<unsigned char const*>(data) + 32);
116 if (depth <= SHAMap::leafDepth)
117 {
118 auto const id = uint256::fromVoid(data);
119
120 if (id == (id & depthMask(depth)))
121 ret.emplace(depth, id);
122 }
123 }
124
125 return ret;
126}
127
128[[nodiscard]] unsigned int
129selectBranch(SHAMapNodeID const& id, uint256 const& hash)
130{
131 auto const depth = id.getDepth();
132 auto branch = static_cast<unsigned int>(*(hash.begin() + (depth / 2)));
133
134 if (depth & 1)
135 branch &= 0xf;
136 else
137 branch >>= 4;
138
139 XRPL_ASSERT(
140 branch < SHAMap::branchFactor, "ripple::selectBranch : maximum result");
141 return branch;
142}
143
144SHAMapNodeID
145SHAMapNodeID::createID(int depth, uint256 const& key)
146{
147 XRPL_ASSERT(
148 (depth >= 0) && (depth < 65),
149 "ripple::SHAMapNodeID::createID : valid branch input");
150 return SHAMapNodeID(depth, key & depthMask(depth));
151}
152
153} // namespace ripple
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:34
SHAMapNodeID getChildNodeID(unsigned int m) const
std::string getRawString() const
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.
unsigned int depth_
Definition: SHAMapNodeID.h:37
static constexpr unsigned int leafDepth
The depth of the hash map: data is only present in the leaves.
Definition: SHAMap.h:120
static constexpr unsigned int branchFactor
Number of children each non-leaf node has (the 'radix tree' part of the map)
Definition: SHAMap.h:116
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:131
int add8(unsigned char i)
Definition: Serializer.cpp:143
std::string getString() const
Definition: Serializer.h:238
iterator begin()
Definition: base_uint.h:135
static base_uint fromVoid(void const *data)
Definition: base_uint.h:318
T emplace(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
unsigned int selectBranch(SHAMapNodeID const &id, uint256 const &hash)
Returns the branch that would contain the given hash.
std::optional< SHAMapNodeID > deserializeSHAMapNodeID(void const *data, std::size_t size)
Return an object representing a serialized SHAMap Node ID.
base_uint< 256 > uint256
Definition: base_uint.h:557
static uint256 const & depthMask(unsigned int depth)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629