6#ifndef ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOCKCHAIN_CHAIN_HPP_
7#define ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOCKCHAIN_CHAIN_HPP_
10#include <unordered_set>
11#include <veriblock/pop/keystone_util.hpp>
13#include "block_index.hpp"
24template <
typename BlockIndexT>
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*>;
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;
39 explicit Chain(height_t startHeight) : startHeight_(startHeight) {}
41 explicit Chain(height_t startHeight, index_t* tip)
42 : startHeight_(startHeight) {
47 height_t getStartHeight()
const {
return firstHeight(); }
48 height_t firstHeight()
const {
return startHeight_; }
50 bool contains(
const index_t* index)
const {
51 return index !=
nullptr && this->operator[](index->getHeight()) == index;
54 index_t* operator[](height_t height)
const {
55 if (height < startHeight_)
return nullptr;
57 height_t innerHeight = toInnerHeight(height);
58 if (innerHeight >= height_t(chain.size())) {
61 return chain[innerHeight];
64 index_t* next(
const index_t* index)
const {
65 return !contains(index) ? nullptr : (*this)[index->getHeight() + 1];
68 height_t chainHeight()
const {
69 return (height_t)chain.size() + startHeight_ - 1;
72 bool empty()
const {
return chain.empty(); }
74 size_t size()
const {
return chain.size(); }
76 size_t blocksCount()
const {
return size(); }
78 index_t* tip()
const {
79 return chain.empty() ? nullptr : (*this)[chainHeight()];
82 index_t* first()
const {
return chain.empty() ? nullptr : chain[0]; }
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(); }
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(); }
94 void prependRoot(index_t* index) {
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);
102 void setTip(index_t* index) {
103 if (index ==
nullptr || index->getHeight() < startHeight_) {
108 height_t innerHeight = toInnerHeight(index->getHeight());
109 chain.resize(innerHeight + 1);
111 while (index !=
nullptr && !contains(index) &&
112 index->getHeight() >= startHeight_) {
113 innerHeight = toInnerHeight(index->getHeight());
114 chain[innerHeight] = index;
115 index = index->getPrev();
119 void disconnectTip() { chain.pop_back(); }
121 friend bool operator==(
const Chain& a,
const Chain& b) {
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();
129 friend bool operator!=(
const Chain& a,
const Chain& b) {
return !(a == b); }
132 height_t startHeight_ = 0;
133 std::vector<index_t*> chain{};
135 height_t toInnerHeight(height_t in)
const {
136 VBK_ASSERT(in >= startHeight_);
137 return in - startHeight_;
145 const typename C::index_t* pindex) {
146 if (pindex ==
nullptr || chain.tip() ==
nullptr) {
150 auto lastHeight = chain.chainHeight();
151 if (pindex->getHeight() > lastHeight) {
152 pindex = pindex->getAncestor(lastHeight);
154 while (pindex !=
nullptr && !chain.contains(pindex)) {
155 pindex = pindex->getPrev();
157 return const_cast<typename C::index_t*
>(pindex);
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();
170 if (workBlock->getContainingEndorsements().count(
id)) {
173 workBlock = workBlock->pprev;
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);
191void PrintTo(
const Chain<T>& c, std::ostream* os) {
194 *os << format(
"Chain(height={} tip=empty)", c.getStartHeight());
198 *os <<
"Chain(height=" << c.getStartHeight() <<
"\n";
199 while (tip !=
nullptr) {
200 *os << tip->toPrettyString() <<
"\n";
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.
Fully in-memory chain representation.