Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
incremental_merkle.hpp
Go to the documentation of this file.
1#pragma once
4#include <fc/io/raw.hpp>
5
6namespace sysio { namespace chain {
7
8namespace detail {
9
18 value -= 1;
19 value |= value >> 1;
20 value |= value >> 2;
21 value |= value >> 4;
22 value |= value >> 8;
23 value |= value >> 16;
24 value |= value >> 32;
25 value += 1;
26 return value;
27}
28
38constexpr int clz_power_2(uint64_t value) {
39 int lz = 64;
40
41 if (value) lz--;
42 if (value & 0x00000000FFFFFFFFULL) lz -= 32;
43 if (value & 0x0000FFFF0000FFFFULL) lz -= 16;
44 if (value & 0x00FF00FF00FF00FFULL) lz -= 8;
45 if (value & 0x0F0F0F0F0F0F0F0FULL) lz -= 4;
46 if (value & 0x3333333333333333ULL) lz -= 2;
47 if (value & 0x5555555555555555ULL) lz -= 1;
48
49 return lz;
50}
51
59constexpr int calcluate_max_depth(uint64_t node_count) {
60 if (node_count == 0) {
61 return 0;
62 }
63 auto implied_count = next_power_of_2(node_count);
64 return clz_power_2(implied_count) + 1;
65}
66
67template<typename ContainerA, typename ContainerB>
68inline void move_nodes(ContainerA& to, const ContainerB& from) {
69 to.clear();
70 to.insert(to.begin(), from.begin(), from.end());
71}
72
73template<typename Container>
74inline void move_nodes(Container& to, Container&& from) {
75 to = std::forward<Container>(from);
76}
77
78
79}
80
94template<typename DigestType, template<typename ...> class Container = vector, typename ...Args>
96 public:
100
105
106 template<typename Allocator, std::enable_if_t<!std::is_same<std::decay_t<Allocator>, incremental_merkle_impl>::value, int> = 0>
108
109 /*
110 template<template<typename ...> class OtherContainer, typename ...OtherArgs>
111 incremental_merkle_impl( incremental_merkle_impl<DigestType, OtherContainer, OtherArgs...>&& other )
112 :_node_count(other._node_count)
113 ,_active_nodes(other._active_nodes.begin(), other.active_nodes.end())
114 {}
115
116 incremental_merkle_impl( incremental_merkle_impl&& other )
117 :_node_count(other._node_count)
118 ,_active_nodes(std::forward<decltype(_active_nodes)>(other._active_nodes))
119 {}
120 */
121
168 const DigestType& append(const DigestType& digest) {
169 bool partial = false;
170 auto max_depth = detail::calcluate_max_depth(_node_count + 1);
171 auto current_depth = max_depth - 1;
172 auto index = _node_count;
173 auto top = digest;
174 auto active_iter = _active_nodes.begin();
175 auto updated_active_nodes = vector<DigestType>();
176 updated_active_nodes.reserve(max_depth);
177
178 while (current_depth > 0) {
179 if (!(index & 0x1)) {
180 // we are collapsing from a "left" value and an implied "right" creating a partial node
181
182 // we only need to append this node if it is fully-realized and by definition
183 // if we have encountered a partial node during collapse this cannot be
184 // fully-realized
185 if (!partial) {
186 updated_active_nodes.emplace_back(top);
187 }
188
189 // calculate the partially realized node value by implying the "right" value is identical
190 // to the "left" value
191 top = DigestType::hash(make_canonical_pair(top, top));
192 partial = true;
193 } else {
194 // we are collapsing from a "right" value and an fully-realized "left"
195
196 // pull a "left" value from the previous active nodes
197 const auto& left_value = *active_iter;
198 ++active_iter;
199
200 // if the "right" value is a partial node we will need to copy the "left" as future appends still need it
201 // otherwise, it can be dropped from the set of active nodes as we are collapsing a fully-realized node
202 if (partial) {
203 updated_active_nodes.emplace_back(left_value);
204 }
205
206 // calculate the node
207 top = DigestType::hash(make_canonical_pair(left_value, top));
208 }
209
210 // move up a level in the tree
211 current_depth--;
212 index = index >> 1;
213 }
214
215 // append the top of the collapsed tree (aka the root of the merkle)
216 updated_active_nodes.emplace_back(top);
217
218 // store the new active_nodes
219 detail::move_nodes(_active_nodes, std::move(updated_active_nodes));
220
221 // update the node count
222 _node_count++;
223
224 return _active_nodes.back();
225
226 }
227
233 DigestType get_root() const {
234 if (_node_count > 0) {
235 return _active_nodes.back();
236 } else {
237 return DigestType();
238 }
239 }
240
241// private:
243 Container<DigestType, Args...> _active_nodes;
244};
245
248
249} }
250
251FC_REFLECT( sysio::chain::incremental_merkle, (_active_nodes)(_node_count) );
Concept for allocating, resizing and freeing memory block.
incremental_merkle_impl & operator=(const incremental_merkle_impl &)=default
const DigestType & append(const DigestType &digest)
Container< DigestType, Args... > _active_nodes
incremental_merkle_impl(const incremental_merkle_impl &)=default
incremental_merkle_impl(incremental_merkle_impl &&)=default
fc::sha256 digest(const T &value)
Definition digest.hpp:9
constexpr int calcluate_max_depth(uint64_t node_count)
constexpr int clz_power_2(uint64_t value)
constexpr uint64_t next_power_of_2(uint64_t value)
void move_nodes(ContainerA &to, const ContainerB &from)
incremental_merkle_impl< digest_type, shared_vector > shared_incremental_merkle
incremental_merkle_impl< digest_type > incremental_merkle
auto make_canonical_pair(const digest_type &l, const digest_type &r)
Definition merkle.hpp:13
#define value
Definition pkcs11.h:157
#define FC_REFLECT(TYPE, MEMBERS)
Specializes fc::reflector for TYPE.
Definition reflect.hpp:311
unsigned __int64 uint64_t
Definition stdint.h:136