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