Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[22.x] Restore full functionality to trim_headers (untrim) #1271

Open
wants to merge 9 commits into
base: elements-22.x
Choose a base branch
from
20 changes: 20 additions & 0 deletions src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#include <chain.h>

#include <validation.h> // pblocktree

/**
* CChain implementation
*/
Expand Down Expand Up @@ -48,6 +50,24 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
return CBlockLocator(vHave);
}

void CBlockIndex::untrim() {
if (!trimmed())
return;
CBlockIndex tmp;
const CBlockIndex* pindexfull = untrim_to(&tmp);
assert(pindexfull!=this);
m_trimmed = false;
set_stored();
proof = pindexfull->proof;
m_dynafed_params = pindexfull->m_dynafed_params;
m_signblock_witness = pindexfull->m_signblock_witness;
}

const CBlockIndex *CBlockIndex::untrim_to(CBlockIndex *pindexNew) const
{
return pblocktree->RegenerateFullIndex(this, pindexNew);
}

const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
if (pindex == nullptr) {
return nullptr;
Expand Down
17 changes: 16 additions & 1 deletion src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,26 +201,38 @@ class CBlockIndex

bool m_trimmed{false};
bool m_trimmed_dynafed_block{false};
bool m_stored_lvl{false};

friend class CBlockTreeDB;

public:

// Irrevocably remove blocksigning and dynafed-related stuff from this
// in-memory copy of the block header.
void trim() {
bool trim() {
assert_untrimmed();
if (!m_stored_lvl) {
// We can't trim in-memory data if it's not on disk yet, but we can if it's already been recovered once
return false;
}
m_trimmed = true;
m_trimmed_dynafed_block = !m_dynafed_params.value().IsNull();
proof = std::nullopt;
m_dynafed_params = std::nullopt;
m_signblock_witness = std::nullopt;
return true;
}

void untrim();
const CBlockIndex *untrim_to(CBlockIndex *pindexNew) const;

inline bool trimmed() const {
return m_trimmed;
}

inline void set_stored() {
m_stored_lvl = true;
}
inline void assert_untrimmed() const {
assert(!m_trimmed);
}
Expand Down Expand Up @@ -463,6 +475,9 @@ class CDiskBlockIndex : public CBlockIndex

// For compatibility with elements 0.14 based chains
if (g_signed_blocks) {
if (!ser_action.ForRead()) {
obj.assert_untrimmed();
}
if (is_dyna) {
READWRITE(obj.m_dynafed_params.value());
READWRITE(obj.m_signblock_witness.value().stack);
Expand Down
4 changes: 4 additions & 0 deletions src/dynafed.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include <dynafed.h>
#include <hash.h>
#include <validation.h>

bool NextBlockIsParameterTransition(const CBlockIndex* pindexPrev, const Consensus::Params& consensus, DynaFedParamEntry& winning_entry)
{
Expand All @@ -15,6 +16,7 @@ bool NextBlockIsParameterTransition(const CBlockIndex* pindexPrev, const Consens
for (int32_t height = next_height - 1; height >= (int32_t)(next_height - consensus.dynamic_epoch_length); --height) {
const CBlockIndex* p_epoch_walk = pindexPrev->GetAncestor(height);
assert(p_epoch_walk);
ForceUntrimHeader(p_epoch_walk);
const DynaFedParamEntry& proposal = p_epoch_walk->dynafed_params().m_proposed;
const uint256 proposal_root = proposal.CalculateRoot();
vote_tally[proposal_root]++;
Expand Down Expand Up @@ -60,6 +62,7 @@ DynaFedParamEntry ComputeNextBlockFullCurrentParameters(const CBlockIndex* pinde
// may be pre-dynafed params
const CBlockIndex* p_epoch_start = pindexPrev->GetAncestor(epoch_start_height);
assert(p_epoch_start);
ForceUntrimHeader(p_epoch_start);
if (p_epoch_start->dynafed_params().IsNull()) {
// We need to construct the "full" current parameters of pre-dynafed
// consensus
Expand Down Expand Up @@ -93,6 +96,7 @@ DynaFedParamEntry ComputeNextBlockCurrentParameters(const CBlockIndex* pindexPre
{
assert(pindexPrev);

ForceUntrimHeader(pindexPrev);
DynaFedParamEntry entry = ComputeNextBlockFullCurrentParameters(pindexPrev, consensus);

uint32_t next_height = pindexPrev->nHeight+1;
Expand Down
11 changes: 3 additions & 8 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -987,13 +987,13 @@ bool AppInitParameterInteraction(const ArgsManager& args)
}

if (args.GetBoolArg("-trim_headers", false)) {
LogPrintf("Configured for header-trimming mode. This will reduce memory usage substantially, but we will be unable to serve as a full P2P peer, and certain header fields may be missing from JSON RPC output.\n");
LogPrintf("Configured for header-trimming mode. This will reduce memory usage substantially, but will increase IO usage when the headers need to be temporarily untrimmed.\n");
fTrimHeaders = true;
// This calculation is driven by GetValidFedpegScripts in pegins.cpp, which walks the chain
// back to current epoch start, and then an additional total_valid_epochs on top of that.
// We add one epoch here for the current partial epoch, and then another one for good luck.

nMustKeepFullHeaders = (chainparams.GetConsensus().total_valid_epochs + 2) * epoch_length;
nMustKeepFullHeaders = chainparams.GetConsensus().total_valid_epochs * epoch_length;
// This is the number of headers we can have in flight downloading at a time, beyond the
// set of blocks we've already validated. Capping this is necessary to keep memory usage
// bounded during IBD.
Expand Down Expand Up @@ -1711,7 +1711,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)

// if pruning, unset the service bit and perform the initial blockstore prune
// after any wallet rescanning has taken place.
if (fPruneMode || fTrimHeaders) {
if (fPruneMode) {
LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
if (!fReindex) {
Expand All @@ -1723,11 +1723,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
}

if (fTrimHeaders) {
LogPrintf("Unsetting NODE_NETWORK_LIMITED on header trim mode\n");
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK_LIMITED);
}

if (DeploymentEnabled(chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
// Advertise witness capabilities.
// The option to not set NODE_WITNESS is only used in the tests and should be removed.
Expand Down
11 changes: 6 additions & 5 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3183,12 +3183,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex))
{
if (pindex->trimmed()) {
// For simplicity, if any of the headers they're asking for are trimmed,
// just drop the request.
LogPrint(BCLog::NET, "%s: ignoring getheaders from peer=%i which would return at least one trimmed header\n", __func__, pfrom.GetId());
return;
// Header is trimmed, reload from disk before sending
CBlockIndex tmpBlockIndexFull;
const CBlockIndex* pindexfull = pindex->untrim_to(&tmpBlockIndexFull);
vHeaders.push_back(pindexfull->GetBlockHeader());
} else {
vHeaders.push_back(pindex->GetBlockHeader());
}
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
break;
}
Expand Down
11 changes: 0 additions & 11 deletions src/node/blockstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,17 +408,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;
}
header = tmp.GetBlockHeader();
return true;
}

bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start)
{
FlatFilePos hpos = pos;
Expand Down
1 change: 0 additions & 1 deletion src/node/blockstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start);
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, 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);
bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams);
Expand Down
3 changes: 3 additions & 0 deletions src/pegins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
// ELEMENTS
//

#include <validation.h>

namespace {
static secp256k1_context* secp256k1_ctx_validation;

Expand Down Expand Up @@ -487,6 +489,7 @@ std::vector<std::pair<CScript, CScript>> GetValidFedpegScripts(const CBlockIndex
break;
}

ForceUntrimHeader(p_epoch_start);
if (!p_epoch_start->dynafed_params().IsNull()) {
fedpegscripts.push_back(std::make_pair(p_epoch_start->dynafed_params().m_current.m_fedpeg_program, p_epoch_start->dynafed_params().m_current.m_fedpegscript));
} else {
Expand Down
21 changes: 6 additions & 15 deletions src/rest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,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;
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();
Expand All @@ -239,14 +235,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;
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";
Expand Down
21 changes: 10 additions & 11 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,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);
Expand Down Expand Up @@ -271,7 +274,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());
Expand Down Expand Up @@ -966,7 +969,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);
Expand All @@ -982,13 +985,9 @@ static RPCHelpMan getblockheader()
if (!fVerbose)
{
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
if (pblockindex->trimmed()) {
CBlockHeader tmp;
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;
}
Expand Down
Loading