diff --git a/src/chain.cpp b/src/chain.cpp index 6c37bda0bb..fc36659025 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -56,6 +56,11 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { return CBlockLocator(vHave); } +const CBlockIndex *CBlockIndex::untrim_to(CBlockIndex *pindexNew) const +{ + return m_pcontext->chainman->m_blockman.m_block_tree_db->RegenerateFullIndex(this, pindexNew); +} + const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { if (pindex == nullptr) { return nullptr; diff --git a/src/chain.h b/src/chain.h index a73d0d9215..119b3683a3 100644 --- a/src/chain.h +++ b/src/chain.h @@ -244,6 +244,8 @@ public: } void untrim(); + const CBlockIndex * untrim_to(CBlockIndex *pindexNew) const; + inline bool trimmed() const { return m_trimmed; } diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 63ed09fc40..05d62e5b3b 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -803,23 +803,6 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus return true; } -bool ReadBlockHeaderFromDisk(CBlockHeader& header, const CBlockIndex* pindex, const Consensus::Params& consensusParams) -{ - // Not very efficient: read a block and throw away all but the header. - CBlock tmp; - if (!ReadBlockFromDisk(tmp, pindex, consensusParams)) { - return false; - } - const FlatFilePos block_pos{WITH_LOCK(cs_main, return pindex->GetBlockPos())}; - - header = tmp.GetBlockHeader(); - if (tmp.GetHash() != pindex->GetBlockHash()) { - return error("ReadBlockheaderFromDisk(CBlockHeader&, CBlockIndex*): GetHash() doesn't match index for %s at %s", - pindex->ToString(), block_pos.ToString()); - } - return true; -} - bool ReadRawBlockFromDisk(std::vector& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start) { FlatFilePos hpos = pos; diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 1276a3f003..aceb775848 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -194,7 +194,6 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); bool ReadRawBlockFromDisk(std::vector& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start); // ELEMENTS: -bool ReadBlockHeaderFromDisk(class CBlockHeader& header, const CBlockIndex* pindex, const Consensus::Params& consensusParams); bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); diff --git a/src/rest.cpp b/src/rest.cpp index 754b55c2f8..6f79834dcd 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -232,13 +232,9 @@ static bool rest_headers(const std::any& context, case RetFormat::BINARY: { CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); for (const CBlockIndex *pindex : headers) { - if (pindex->trimmed()) { - CBlockHeader tmp; - node::ReadBlockHeaderFromDisk(tmp, pindex, Params().GetConsensus()); - ssHeader << tmp; - } else { - ssHeader << pindex->GetBlockHeader(); - } + CBlockIndex tmpBlockIndexFull; + const CBlockIndex* pindexfull=pindex->untrim_to(&tmpBlockIndexFull); + ssHeader << pindexfull->GetBlockHeader(); } std::string binaryHeader = ssHeader.str(); @@ -250,14 +246,9 @@ static bool rest_headers(const std::any& context, case RetFormat::HEX: { CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); for (const CBlockIndex *pindex : headers) { - if (pindex->trimmed()) { - CBlockHeader tmp; - node::ReadBlockHeaderFromDisk(tmp, pindex, Params().GetConsensus()); - ssHeader << tmp; - - } else { - ssHeader << pindex->GetBlockHeader(); - } + CBlockIndex tmpBlockIndexFull; + const CBlockIndex* pindexfull=pindex->untrim_to(&tmpBlockIndexFull); + ssHeader << pindexfull->GetBlockHeader(); } std::string strHex = HexStr(ssHeader) + "\n"; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 4f702b6bd5..37691ec51d 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -193,15 +193,18 @@ CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainma } } -UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) +UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex_) { // Serialize passed information without accessing chain state of the active chain! AssertLockNotHeld(cs_main); // For performance reasons + CBlockIndex tmpBlockIndexFull; + const CBlockIndex* blockindex=blockindex_->untrim_to(&tmpBlockIndexFull); + UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); const CBlockIndex* pnext; - int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext); + int confirmations = ComputeNextBlockAndDepth(tip, blockindex_, pnext); result.pushKV("confirmations", confirmations); result.pushKV("height", blockindex->nHeight); result.pushKV("version", blockindex->nVersion); @@ -238,7 +241,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex } } result.pushKV("nTx", (uint64_t)blockindex->nTx); - if (blockindex->pprev) + if (blockindex_->pprev) result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); @@ -1002,7 +1005,7 @@ static RPCHelpMan getblockheader() if (!request.params[1].isNull()) fVerbose = request.params[1].get_bool(); - const CBlockIndex* pblockindex; + CBlockIndex* pblockindex; const CBlockIndex* tip; { ChainstateManager& chainman = EnsureAnyChainman(request.context); @@ -1018,13 +1021,9 @@ static RPCHelpMan getblockheader() if (!fVerbose) { CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); - if (pblockindex->trimmed()) { - CBlockHeader tmp; - node::ReadBlockHeaderFromDisk(tmp, pblockindex, Params().GetConsensus()); - ssBlock << tmp; - } else { - ssBlock << pblockindex->GetBlockHeader(); - } + CBlockIndex tmpBlockIndexFull; + const CBlockIndex* pblockindexfull=pblockindex->untrim_to(&tmpBlockIndexFull); + ssBlock << pblockindexfull->GetBlockHeader(); std::string strHex = HexStr(ssBlock); return strHex; } diff --git a/src/txdb.cpp b/src/txdb.cpp index 6fbd37585f..e05211ed97 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -19,6 +19,7 @@ // ELEMENTS #include // CheckProof +#include // Params() static constexpr uint8_t DB_COIN{'C'}; static constexpr uint8_t DB_COINS{'c'}; @@ -365,6 +366,51 @@ bool CBlockTreeDB::WalkBlockIndexGutsForMaxHeight(int* nHeight) { return true; } +const CBlockIndex *CBlockTreeDB::RegenerateFullIndex(const CBlockIndex *pindexTrimmed, CBlockIndex *pindexNew) const +{ + if(!pindexTrimmed->trimmed()) { + return pindexTrimmed; + } + CBlockHeader tmp; + bool BlockRead = false; + { + // At this point we can either be locked or unlocked depending on where we're being called + // but cs_main is a RecursiveMutex, so it doesn't matter + LOCK(cs_main); + // In unpruned nodes, same data could be read from blocks using ReadBlockFromDisk, but that turned out to + // be about 6x slower than reading from the index + std::pair key(DB_BLOCK_INDEX, pindexTrimmed->GetBlockHash()); + CDiskBlockIndex diskindex; + BlockRead = this->Read(key, diskindex); + tmp = diskindex.GetBlockHeader(); + } + assert(BlockRead); + // Clone the needed data from the original trimmed block + pindexNew->pprev = pindexTrimmed->pprev; + pindexNew->phashBlock = pindexTrimmed->phashBlock; + // Construct block index object + pindexNew->nHeight = pindexTrimmed->nHeight; + pindexNew->nFile = pindexTrimmed->nFile; + pindexNew->nDataPos = pindexTrimmed->nDataPos; + pindexNew->nUndoPos = pindexTrimmed->nUndoPos; + pindexNew->nVersion = pindexTrimmed->nVersion; + pindexNew->hashMerkleRoot = pindexTrimmed->hashMerkleRoot; + pindexNew->nTime = pindexTrimmed->nTime; + pindexNew->nBits = pindexTrimmed->nBits; + pindexNew->nNonce = pindexTrimmed->nNonce; + pindexNew->nStatus = pindexTrimmed->nStatus; + pindexNew->nTx = pindexTrimmed->nTx; + + pindexNew->proof = tmp.proof; + pindexNew->m_dynafed_params = tmp.m_dynafed_params; + pindexNew->m_signblock_witness = tmp.m_signblock_witness; + + if (pindexTrimmed->nHeight && pindexTrimmed->nHeight % 1000 == 0) { + assert(CheckProof(pindexNew->GetBlockHeader(), Params().GetConsensus())); + } + return pindexNew; +} + bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function insertBlockIndex, int trimBelowHeight) { AssertLockHeld(::cs_main); diff --git a/src/txdb.h b/src/txdb.h index aa28a0061e..b7cef7f2b7 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -91,6 +91,7 @@ public: bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function insertBlockIndex, int trimBelowHeight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); // ELEMENTS: + const CBlockIndex *RegenerateFullIndex(const CBlockIndex *pindexTrimmed, CBlockIndex *pindexNew) const; bool WalkBlockIndexGutsForMaxHeight(int* nHeight); bool ReadPAKList(std::vector >& offline_list, std::vector >& online_list, bool& reject); bool WritePAKList(const std::vector >& offline_list, const std::vector >& online_list, bool reject);