veriblock-pop-cpp
C++11 Libraries for leveraging VeriBlock Proof-Of-Proof blockchain technology.
chain.hpp
1// Copyright (c) 2019-2022 Xenios SEZC
2// https://www.veriblock.org
3// Distributed under the MIT software license, see the accompanying
4// file LICENSE or http://www.opensource.org/licenses/mit-license.php.
5
6#ifndef ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOCKCHAIN_CHAIN_HPP_
7#define ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOCKCHAIN_CHAIN_HPP_
8
9#include <map>
10#include <unordered_set>
11#include <veriblock/pop/keystone_util.hpp>
12
13#include "block_index.hpp"
14
15namespace altintegration {
16
24template <typename BlockIndexT>
25struct Chain {
26 using index_t = BlockIndexT;
27 using block_t = typename index_t::block_t;
28 using hash_t = typename index_t::hash_t;
29 using height_t = typename block_t::height_t;
30 using storage_t = std::vector<index_t*>;
31
32 using iterator_t = typename storage_t::iterator;
33 using const_iterator_t = typename storage_t::const_iterator;
34 using reverse_iterator_t = typename storage_t::reverse_iterator;
35 using const_reverse_iterator_t = typename storage_t::const_reverse_iterator;
36
37 Chain() = default;
38
39 explicit Chain(height_t startHeight) : startHeight_(startHeight) {}
40
41 explicit Chain(height_t startHeight, index_t* tip)
42 : startHeight_(startHeight) {
43 setTip(tip);
44 }
45
46 // for compatibility
47 height_t getStartHeight() const { return firstHeight(); }
48 height_t firstHeight() const { return startHeight_; }
49
50 bool contains(const index_t* index) const {
51 return index != nullptr && this->operator[](index->getHeight()) == index;
52 }
53
54 index_t* operator[](height_t height) const {
55 if (height < startHeight_) return nullptr;
56
57 height_t innerHeight = toInnerHeight(height);
58 if (innerHeight >= height_t(chain.size())) {
59 return nullptr;
60 }
61 return chain[innerHeight];
62 }
63
64 index_t* next(const index_t* index) const {
65 return !contains(index) ? nullptr : (*this)[index->getHeight() + 1];
66 }
67
68 height_t chainHeight() const {
69 return (height_t)chain.size() + startHeight_ - 1;
70 }
71
72 bool empty() const { return chain.empty(); }
73
74 size_t size() const { return chain.size(); }
75 // for compatibility
76 size_t blocksCount() const { return size(); }
77
78 index_t* tip() const {
79 return chain.empty() ? nullptr : (*this)[chainHeight()];
80 }
81
82 index_t* first() const { return chain.empty() ? nullptr : chain[0]; }
83
84 reverse_iterator_t rbegin() { return chain.rbegin(); }
85 const_reverse_iterator_t rbegin() const { return chain.rbegin(); }
86 reverse_iterator_t rend() { return chain.rend(); }
87 const_reverse_iterator_t rend() const { return chain.rend(); }
88
89 iterator_t begin() { return chain.begin(); }
90 const_iterator_t begin() const { return chain.begin(); }
91 iterator_t end() { return chain.end(); }
92 const_iterator_t end() const { return chain.end(); }
93
94 void prependRoot(index_t* index) {
95 // set a new bootstrap block which should be connected to the current one
96 VBK_ASSERT_MSG(!chain.empty() && index == chain[0]->pprev,
97 "new bootstrap block does not connect to the current one");
98 startHeight_ = index->getHeight();
99 chain.insert(chain.begin(), index);
100 }
101
102 void setTip(index_t* index) {
103 if (index == nullptr || index->getHeight() < startHeight_) {
104 chain.clear();
105 return;
106 }
107
108 height_t innerHeight = toInnerHeight(index->getHeight());
109 chain.resize(innerHeight + 1);
110
111 while (index != nullptr && !contains(index) &&
112 index->getHeight() >= startHeight_) {
113 innerHeight = toInnerHeight(index->getHeight());
114 chain[innerHeight] = index;
115 index = index->getPrev();
116 }
117 }
118
119 void disconnectTip() { chain.pop_back(); }
120
121 friend bool operator==(const Chain& a, const Chain& b) {
122 // sizes may vary, so compare tips
123 if (a.tip() == nullptr && b.tip() == nullptr) return true;
124 if (a.tip() == nullptr) return false;
125 if (b.tip() == nullptr) return false;
126 return a.tip()->getHash() == b.tip()->getHash();
127 }
128
129 friend bool operator!=(const Chain& a, const Chain& b) { return !(a == b); }
130
131 private:
132 height_t startHeight_ = 0;
133 std::vector<index_t*> chain{};
134
135 height_t toInnerHeight(height_t in) const {
136 VBK_ASSERT(in >= startHeight_);
137 return in - startHeight_;
138 }
139};
140
143template <typename C>
144typename C::index_t* findFork(const C& chain,
145 const typename C::index_t* pindex) {
146 if (pindex == nullptr || chain.tip() == nullptr) {
147 return nullptr;
148 }
149
150 auto lastHeight = chain.chainHeight();
151 if (pindex->getHeight() > lastHeight) {
152 pindex = pindex->getAncestor(lastHeight);
153 }
154 while (pindex != nullptr && !chain.contains(pindex)) {
155 pindex = pindex->getPrev();
156 }
157 return const_cast<typename C::index_t*>(pindex);
158}
159
161template <typename index_t>
162const index_t* findBlockContainingEndorsement(
163 const Chain<index_t>& chain,
164 const index_t* workBlock,
165 const typename index_t::endorsement_t::id_t& id,
166 const uint32_t& window) {
167 for (uint32_t count = 0; count < window && workBlock != nullptr &&
168 workBlock->getHeight() >= chain.getStartHeight();
169 count++) {
170 if (workBlock->getContainingEndorsements().count(id)) {
171 return workBlock;
172 }
173 workBlock = workBlock->pprev;
174 }
175
176 return nullptr;
177}
178
180template <typename index_t>
181inline const index_t* findBlockContainingEndorsement(
182 const Chain<index_t>& chain,
183 const typename index_t::endorsement_t& e,
184 const uint32_t& endorsement_settlement_interval) {
185 return findBlockContainingEndorsement<index_t>(
186 chain, chain.tip(), e.id, endorsement_settlement_interval);
187}
188
190template <typename T>
191void PrintTo(const Chain<T>& c, std::ostream* os) {
192 auto* tip = c.tip();
193 if (!tip) {
194 *os << format("Chain(height={} tip=empty)", c.getStartHeight());
195 return;
196 }
197
198 *os << "Chain(height=" << c.getStartHeight() << "\n";
199 while (tip != nullptr) {
200 *os << tip->toPrettyString() << "\n";
201 tip = tip->pprev;
202 }
203 *os << ")\n";
204}
205
206} // namespace altintegration
207
208#endif // ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOCKCHAIN_CHAIN_HPP_
Defines logging helpers.
Definition: block.hpp:14
void PrintTo(const ArithUint256 &uint, ::std::ostream *os)
custom gtest printer, which prints Blob of any size as hexstring @ private
C::index_t * findFork(const C &chain, const typename C::index_t *pindex)
Find fork between chain and pindex.
Definition: chain.hpp:144
Fully in-memory chain representation.
Definition: chain.hpp:25