6#ifndef ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOCKCHAIN_BLOCK_INDEX_HPP_
7#define ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOCKCHAIN_BLOCK_INDEX_HPP_
12#include <veriblock/pop/algorithm.hpp>
13#include <veriblock/pop/entities/endorsements.hpp>
14#include <veriblock/pop/entities/vbkblock.hpp>
15#include <veriblock/pop/logger.hpp>
16#include <veriblock/pop/storage/stored_block_index.hpp>
17#include <veriblock/pop/validation_state.hpp>
18#include <veriblock/pop/write_stream.hpp>
20#include "block_status.hpp"
22#include "command_group.hpp"
30template <
typename Block>
32 using block_t = Block;
33 using addon_t =
typename Block::addon_t;
34 using hash_t =
typename block_t::hash_t;
35 using prev_hash_t =
typename block_t::prev_hash_t;
36 using height_t =
typename block_t::height_t;
50 VBK_ASSERT(prev !=
nullptr);
54 if (
pprev->isFailed()) {
58 height = prev->getHeight() + 1;
69 VBK_ASSERT(isDeleted());
70 VBK_ASSERT_MSG(
pprev ==
nullptr,
pprev->toPrettyString());
73 void disconnectFromPrev() {
74 if (
pprev ==
nullptr) {
79 VBK_ASSERT_MSG(
pprev->
pnext.count(
this) > 0, this->toPrettyString());
80 this->pprev->
pnext.erase(
this);
81 this->pprev =
nullptr;
84 bool isTip()
const {
return pnext.empty(); }
94 bool isRoot()
const {
return pprev ==
nullptr; };
97 VBK_ASSERT_MSG(isDeleted(),
98 "tried to restore block %s that is not deleted",
105 void deleteTemporarily() {
106 VBK_ASSERT_MSG(!isDeleted(),
107 "tried to delete block %s that is already deleted",
123 void mergeFrom(
const StoredBlockIndex<Block>& other) {
124 setHeight(other.height);
125 setHeader(other.header);
126 setStatus(other.status);
128 other.addon.toInmem(*
this);
131 StoredBlockIndex<Block> toStoredBlockIndex()
const {
132 StoredBlockIndex<Block> ret;
149 uint32_t getStatus()
const {
return status; }
150 void setStatus(uint32_t _status) {
151 if (_status == this->
status)
return;
156 uint32_t getValidityLevel()
const {
165 return !isFailed() && isValidUpTo(upTo);
169 auto validityLevel = getValidityLevel();
172 "block %s is both BLOCK_CAN_BE_APPLIED and BLOCK_FAILED_POP which are "
173 "mutually exclusive",
176 return getValidityLevel() >= upTo;
181 this->pprev =
nullptr;
189 void setNullInmemFields() {
190 addon_t::setNullInmemFields();
191 this->pprev =
nullptr;
202 VBK_ASSERT_MSG(isRoot() ||
pprev->getValidityLevel() >= upTo,
203 "attempted to raise the validity level of block %s beyond "
204 "the validity level of its ancestor %s",
206 pprev->toPrettyString());
229 void setDirty() { this->
dirty =
true; }
230 void unsetDirty() { this->
dirty =
false; }
231 bool isDirty()
const {
return this->
dirty; }
234 auto newStatus = this->
status | s;
235 if (newStatus == this->
status)
return;
240 auto newStatus = this->
status & ~s;
241 if (newStatus == this->
status)
return;
248 const hash_t& getHash()
const {
return header->getHash(); }
249 uint32_t getTimestamp()
const {
return header->getTimestamp(); }
250 uint32_t getDifficulty()
const {
return header->getDifficulty(); }
252 height_t getHeight()
const {
return height; }
253 void setHeight(
const height_t newHeight) {
258 const block_t& getHeader()
const {
return *
header; }
259 void setHeader(
const block_t& newHeader) {
260 header = std::make_shared<block_t>(newHeader);
263 void setHeader(std::shared_ptr<block_t> newHeader) {
264 header = std::move(newHeader);
268 bool canBeATip()
const {
269 return !isDeleted() && isValid(addon_t::validTipLevel);
276 return canBeATip() &&
279 return index->canBeATip();
289 return index->hasFlags(BLOCK_ACTIVE);
297 return std::count_if(
299 return !index->isDeleted();
309 return index->isConnected();
313 const BlockIndex* getAncestorBlocksBehind(height_t steps)
const {
314 if (steps < 0 || steps > this->
height) {
322 VBK_ASSERT_MSG(isRoot() || getHeight() ==
pprev->getHeight() + 1,
323 "state corruption: unexpected height of the previous block "
325 pprev->toPrettyString(),
332 const auto& t = as_const(*
this);
336 bool isDescendantOf(
const BlockIndex& ancestor)
const {
337 return getAncestor(ancestor.getHeight()) == &ancestor;
340 bool isAncestorOf(
const BlockIndex& descendant)
const {
341 return descendant.
getAncestor(getHeight()) ==
this;
348 VBK_ASSERT(_height >= 0);
349 if (_height > this->
height) {
357 while (index !=
nullptr && index->
height > _height) {
358 index = index->getPrev();
361 VBK_ASSERT(index ==
nullptr || index->
height == _height);
367 const auto& t = as_const(*
this);
368 return const_cast<BlockIndex*
>(t.getAncestor(_height));
371 std::string toPrettyString(
size_t level = 0)
const {
373 "{}{}BlockIndex(height={} hash={} prev={} next={} final={} status={} "
375 std::string(level,
' '),
385 addon_t::toPrettyString());
388 std::string toShortPrettyString()
const {
389 return format(
"{}:{}:{}", Block::name(),
height,
HexStr(getHash()));
393 return a.getStatus() == b.getStatus() && a.getHeight() == b.getHeight() &&
394 a.getHeader() == b.getHeader();
398 return a.getStatus() != b.getStatus() && a.getHeight() != b.getHeight() &&
399 a.getHeader() != b.getHeader();
407 std::shared_ptr<block_t>
header = std::make_shared<block_t>();
427template <
typename Block>
430 const auto initialHeight = std::min(a.getHeight(), b.getHeight());
434 cursorA !=
nullptr && cursorB !=
nullptr;
435 cursorA = cursorA->getPrev(), cursorB = cursorB->getPrev()) {
436 if (cursorA == cursorB) {
447template <
typename Block>
451 if (candidate.
getAncestor(finalBlock.getHeight()) == &finalBlock) {
456 if (candidate.getHeight() < finalBlock.getHeight()) {
461 if (candidate.getHeight() == finalBlock.getHeight() &&
462 &finalBlock != &candidate) {
467 if (finalBlock.
getAncestor(candidate.getHeight()) == &candidate) {
475 if (fork ==
nullptr) {
484template <
typename Block>
485void PrintTo(
const BlockIndex<Block>& b, ::std::ostream* os) {
486 *os << b.toPrettyString();
BlockStateStatus
Flags that describe block status.
@ BLOCK_VALID_MASK
all stateful validity levels
@ BLOCK_VALID_TREE
acceptBlockHeader succeded.
@ BLOCK_CONNECTED
the block is connected via connectBlock, which means that this block and all its ancestors are at lea...
@ BLOCK_CAN_BE_APPLIED
the chain with the block at its tip is fully valid, so if we do SetState on this block,...
BlockValidityStatus
Flags that describe block status.
@ BLOCK_VALID_UNKNOWN
default state for validity - validity state is unknown
@ BLOCK_FAILED_CHILD
block is state{lessly,fully} valid and the altchain did not report it as invalid, but some of the anc...
@ BLOCK_DELETED
the block is temporarily deleted
@ BLOCK_FAILED_MASK
all invalidity flags
@ BLOCK_FAILED_POP
block failed state{less,ful} validation due to its payloads
bool isBlockOutdated(const BlockIndex< Block > &finalBlock, const BlockIndex< Block > &candidate)
a candidate is considered outdated if it is behind finalBlock, or on same height and not equal to fin...
std::string HexStr(const T itbegin, const T itend)
Convert bytes to hex.
void PrintTo(const ArithUint256 &uint, ::std::ostream *os)
custom gtest printer, which prints Blob of any size as hexstring @ private
const BlockIndex< Block > * getForkBlock(const BlockIndex< Block > &a, const BlockIndex< Block > &b)
getForkBlock assumes that: the block tree is not malformed the fork block(worst case: genesis/bootstr...
size_t nondeletedDescendantCount() const
Count the descendants that are not deleted.
BlockIndex * pprev
(memory only) pointer to the previous block
std::set< BlockIndex * > pnext
(memory only) a set of pointers for forward iteration
BlockIndex(height_t _height)
create a root block in a deleted state
bool finalized
(memory only) if true, this block can not be reorganized
BlockIndex(BlockIndex *prev)
create a regular block in a deleted state
BlockIndex * getAncestor(height_t _height)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool allDescendantsUnconnected() const
Check if all immediate descendants of the block are not connected.
const BlockIndex * getAncestor(height_t _height) const
bool dirty
(memory only) if true, this block should be written on disk
bool allDescendantsUnapplied() const
Check if all immediate descendants of the block are unapplied.
std::shared_ptr< block_t > header
block header
height_t height
height of the entry in the chain
bool isConnected() const noexcept
Block is connected if it contains block body (PopData), and all its ancestors are connected.
uint32_t status
contains status flags
bool isValidTip() const
The block is a valid tip if it can be a tip and either there are no descendant blocks or none of the ...