rippled
SHAMapInnerNode.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/shamap/SHAMapInnerNode.h>
21 
22 #include <ripple/basics/ByteUtilities.h>
23 #include <ripple/basics/Log.h>
24 #include <ripple/basics/Slice.h>
25 #include <ripple/basics/contract.h>
26 #include <ripple/basics/safe_cast.h>
27 #include <ripple/beast/core/LexicalCast.h>
28 #include <ripple/protocol/HashPrefix.h>
29 #include <ripple/protocol/digest.h>
30 #include <ripple/shamap/SHAMapTreeNode.h>
31 
32 #include <openssl/sha.h>
33 
34 #include <algorithm>
35 #include <array>
36 #include <atomic>
37 #include <iterator>
38 #include <mutex>
39 #include <utility>
40 
41 namespace ripple {
42 
44 
47 {
48  auto p = std::make_shared<SHAMapInnerNode>(cowid);
49  p->hash_ = hash_;
50  p->mIsBranch = mIsBranch;
51  p->mFullBelowGen = mFullBelowGen;
52  p->mHashes = mHashes;
54  for (int i = 0; i < 16; ++i)
55  p->mChildren[i] = mChildren[i];
56  return p;
57 }
58 
61  Slice data,
62  SHAMapHash const& hash,
63  bool hashValid)
64 {
65  if (data.size() != 512)
66  Throw<std::runtime_error>("Invalid FI node");
67 
68  auto ret = std::make_shared<SHAMapInnerNode>(0);
69 
70  Serializer s(data.data(), data.size());
71 
72  for (int i = 0; i < 16; ++i)
73  {
74  s.getBitString(ret->mHashes[i].as_uint256(), i * 32);
75 
76  if (ret->mHashes[i].isNonZero())
77  ret->mIsBranch |= (1 << i);
78  }
79 
80  if (hashValid)
81  ret->hash_ = hash;
82  else
83  ret->updateHash();
84  return ret;
85 }
86 
89 {
90  Serializer s(data.data(), data.size());
91 
92  int len = s.getLength();
93 
94  auto ret = std::make_shared<SHAMapInnerNode>(0);
95 
96  for (int i = 0; i < (len / 33); ++i)
97  {
98  int pos;
99 
100  if (!s.get8(pos, 32 + (i * 33)))
101  Throw<std::runtime_error>("short CI node");
102 
103  if ((pos < 0) || (pos >= 16))
104  Throw<std::runtime_error>("invalid CI node");
105 
106  s.getBitString(ret->mHashes[pos].as_uint256(), i * 33);
107 
108  if (ret->mHashes[pos].isNonZero())
109  ret->mIsBranch |= (1 << pos);
110  }
111 
112  ret->updateHash();
113 
114  return ret;
115 }
116 
117 void
119 {
120  uint256 nh;
121  if (mIsBranch != 0)
122  {
124  using beast::hash_append;
126  for (auto const& hh : mHashes)
127  hash_append(h, hh);
128  nh = static_cast<typename sha512_half_hasher::result_type>(h);
129  }
130  hash_ = SHAMapHash{nh};
131 }
132 
133 void
135 {
136  for (auto pos = 0; pos < 16; ++pos)
137  {
138  if (mChildren[pos] != nullptr)
139  mHashes[pos] = mChildren[pos]->getHash();
140  }
141  updateHash();
142 }
143 
144 void
146 {
147  assert(!isEmpty());
148 
149  // If the node is sparse, then only send non-empty branches:
150  if (getBranchCount() < 12)
151  {
152  // compressed node
153  for (int i = 0; i < mHashes.size(); ++i)
154  {
155  if (!isEmptyBranch(i))
156  {
157  s.addBitString(mHashes[i].as_uint256());
158  s.add8(i);
159  }
160  }
161 
163  }
164  else
165  {
166  for (auto const& hh : mHashes)
167  s.addBitString(hh.as_uint256());
168 
169  s.add8(wireTypeInner);
170  }
171 }
172 
173 void
175 {
176  assert(!isEmpty());
177 
179  for (auto const& hh : mHashes)
180  s.addBitString(hh.as_uint256());
181 }
182 
183 bool
185 {
186  return mIsBranch == 0;
187 }
188 
189 int
191 {
192  int count = 0;
193 
194  for (int i = 0; i < 16; ++i)
195  if (!isEmptyBranch(i))
196  ++count;
197 
198  return count;
199 }
200 
203 {
205  for (int i = 0; i < mHashes.size(); ++i)
206  {
207  if (!isEmptyBranch(i))
208  {
209  ret += "\n";
210  ret += std::to_string(i);
211  ret += " = ";
212  ret += to_string(mHashes[i]);
213  }
214  }
215  return ret;
216 }
217 
218 // We are modifying an inner node
219 void
221 {
222  assert((m >= 0) && (m < 16));
223  assert(cowid_ != 0);
224  assert(child.get() != this);
225  mHashes[m].zero();
226  hash_.zero();
227  if (child)
228  mIsBranch |= (1 << m);
229  else
230  mIsBranch &= ~(1 << m);
231  mChildren[m] = child;
232 }
233 
234 // finished modifying, now make shareable
235 void
237 {
238  assert((m >= 0) && (m < 16));
239  assert(cowid_ != 0);
240  assert(child);
241  assert(child.get() != this);
242 
243  mChildren[m] = child;
244 }
245 
248 {
249  assert(branch >= 0 && branch < 16);
250 
252  return mChildren[branch].get();
253 }
254 
257 {
258  assert(branch >= 0 && branch < 16);
259 
261  return mChildren[branch];
262 }
263 
266  int branch,
268 {
269  assert(branch >= 0 && branch < 16);
270  assert(node);
271  assert(node->getHash() == mHashes[branch]);
272 
274  if (mChildren[branch])
275  {
276  // There is already a node hooked up, return it
277  node = mChildren[branch];
278  }
279  else
280  {
281  // Hook this node up
282  mChildren[branch] = node;
283  }
284  return node;
285 }
286 
287 void
288 SHAMapInnerNode::invariants(bool is_root) const
289 {
290  unsigned count = 0;
291  for (int i = 0; i < 16; ++i)
292  {
293  if (mHashes[i].isNonZero())
294  {
295  assert((mIsBranch & (1 << i)) != 0);
296  if (mChildren[i] != nullptr)
297  mChildren[i]->invariants();
298  ++count;
299  }
300  else
301  {
302  assert((mIsBranch & (1 << i)) == 0);
303  }
304  }
305  if (!is_root)
306  {
307  assert(hash_.isNonZero());
308  assert(count >= 1);
309  }
310  assert((count == 0) ? hash_.isZero() : hash_.isNonZero());
311 }
312 
313 } // namespace ripple
ripple::SHAMapTreeNode::cowid
std::uint32_t cowid() const
Returns the SHAMap that owns this node.
Definition: SHAMapTreeNode.h:196
ripple::SHAMapInnerNode::serializeWithPrefix
void serializeWithPrefix(Serializer &) const override
Serialize the node in a format appropriate for hashing.
Definition: SHAMapInnerNode.cpp:174
ripple::SHAMapInnerNode::setChild
void setChild(int m, std::shared_ptr< SHAMapTreeNode > const &child)
Definition: SHAMapInnerNode.cpp:220
ripple::SHAMapInnerNode::clone
std::shared_ptr< SHAMapTreeNode > clone(std::uint32_t cowid) const override
Make a copy of this node, setting the owner.
Definition: SHAMapInnerNode.cpp:46
std::string
STL class.
std::shared_ptr
STL class.
utility
ripple::SHAMapInnerNode::mHashes
std::array< SHAMapHash, 16 > mHashes
Definition: SHAMapInnerNode.h:41
ripple::detail::basic_sha512_half_hasher
Returns the SHA512-Half digest of a message.
Definition: digest.h:166
ripple::SHAMapInnerNode::getChild
std::shared_ptr< SHAMapTreeNode > getChild(int branch)
Definition: SHAMapInnerNode.cpp:256
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
ripple::SHAMapInnerNode::makeFullInner
static std::shared_ptr< SHAMapTreeNode > makeFullInner(Slice data, SHAMapHash const &hash, bool hashValid)
Definition: SHAMapInnerNode.cpp:60
ripple::SHAMapInnerNode::canonicalizeChild
virtual std::shared_ptr< SHAMapTreeNode > canonicalizeChild(int branch, std::shared_ptr< SHAMapTreeNode > node)
Definition: SHAMapInnerNode.cpp:265
ripple::SHAMapTreeNode::cowid_
std::uint32_t cowid_
Determines the owning SHAMap, if any.
Definition: SHAMapTreeNode.h:144
ripple::SHAMapInnerNode::mFullBelowGen
std::uint32_t mFullBelowGen
Definition: SHAMapInnerNode.h:44
ripple::Serializer::add8
int add8(unsigned char i)
Definition: Serializer.cpp:158
ripple::SHAMapInnerNode::updateHash
void updateHash() override
Recalculate the hash of this node.
Definition: SHAMapInnerNode.cpp:118
iterator
std::lock_guard
STL class.
ripple::SHAMapHash::isZero
bool isZero() const
Definition: SHAMapTreeNode.h:68
ripple::SHAMapInnerNode::shareChild
void shareChild(int m, std::shared_ptr< SHAMapTreeNode > const &child)
Definition: SHAMapInnerNode.cpp:236
ripple::wireTypeInner
static constexpr unsigned const char wireTypeInner
Definition: SHAMapTreeNode.h:40
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::SHAMapNodeID
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:33
ripple::SHAMapHash::isNonZero
bool isNonZero() const
Definition: SHAMapTreeNode.h:73
ripple::SHAMapTreeNode::getString
virtual std::string getString(SHAMapNodeID const &) const
Definition: SHAMapTreeNode.cpp:187
ripple::SHAMapTreeNode::hash_
SHAMapHash hash_
Definition: SHAMapTreeNode.h:136
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:47
algorithm
ripple::SHAMapInnerNode::isEmptyBranch
bool isEmptyBranch(int m) const
Definition: SHAMapInnerNode.h:130
ripple::base_uint< 256 >
ripple::SHAMapInnerNode::getString
std::string getString(SHAMapNodeID const &) const override
Definition: SHAMapInnerNode.cpp:202
ripple::HashPrefix::innerNode
@ innerNode
inner node in V1 tree
ripple::SHAMapTreeNode
Definition: SHAMapTreeNode.h:133
std::to_string
T to_string(T... args)
array
ripple::Serializer::get8
bool get8(int &, int offset) const
Definition: Serializer.cpp:166
ripple::SHAMapInnerNode::updateHashDeep
void updateHashDeep()
Recalculate the hash of all children and this node.
Definition: SHAMapInnerNode.cpp:134
ripple::SHAMapInnerNode::getBranchCount
int getBranchCount() const
Definition: SHAMapInnerNode.cpp:190
std::uint32_t
atomic
ripple::Serializer
Definition: Serializer.h:39
ripple::wireTypeCompressedInner
static constexpr unsigned const char wireTypeCompressedInner
Definition: SHAMapTreeNode.h:41
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::SHAMapInnerNode::serializeForWire
void serializeForWire(Serializer &) const override
Serialize the node in a format appropriate for sending over the wire.
Definition: SHAMapInnerNode.cpp:145
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:97
ripple::Serializer::getBitString
bool getBitString(base_uint< Bits, Tag > &data, int offset) const
Definition: Serializer.h:144
ripple::SHAMapInnerNode::mIsBranch
int mIsBranch
Definition: SHAMapInnerNode.h:43
ripple::SHAMapHash::zero
void zero()
Definition: SHAMapTreeNode.h:83
beast::hash_append
std::enable_if_t< is_contiguously_hashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
Definition: hash_append.h:237
ripple::hash_append
void hash_append(Hasher &h, Slice const &v)
Definition: Slice.h:195
ripple::SHAMapInnerNode::childLock
static std::mutex childLock
Definition: SHAMapInnerNode.h:46
mutex
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::SHAMapInnerNode::isEmpty
bool isEmpty() const
Definition: SHAMapInnerNode.cpp:184
ripple::SHAMapInnerNode::makeCompressedInner
static std::shared_ptr< SHAMapTreeNode > makeCompressedInner(Slice data)
Definition: SHAMapInnerNode.cpp:88
ripple::SHAMapInnerNode::getChildPointer
SHAMapTreeNode * getChildPointer(int branch)
Definition: SHAMapInnerNode.cpp:247
ripple::Serializer::getLength
int getLength() const
Definition: Serializer.h:197
ripple::SHAMapInnerNode::invariants
void invariants(bool is_root=false) const override
Definition: SHAMapInnerNode.cpp:288
ripple::SHAMapInnerNode::mChildren
std::shared_ptr< SHAMapTreeNode > mChildren[16]
Definition: SHAMapInnerNode.h:42