Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/blockchain.cpp
Show First 20 Lines • Show All 1,171 Lines • ▼ Show 20 Lines | return RPCHelpMan{ | ||||
if (!fPruneMode) { | if (!fPruneMode) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_MISC_ERROR, | RPC_MISC_ERROR, | ||||
"Cannot prune blocks because node is not in prune mode."); | "Cannot prune blocks because node is not in prune mode."); | ||||
} | } | ||||
ChainstateManager &chainman = EnsureAnyChainman(request.context); | ChainstateManager &chainman = EnsureAnyChainman(request.context); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CChainState &active_chainstate = chainman.ActiveChainstate(); | |||||
CChain &active_chain = active_chainstate.m_chain; | |||||
int heightParam = request.params[0].get_int(); | int heightParam = request.params[0].get_int(); | ||||
if (heightParam < 0) { | if (heightParam < 0) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"Negative block height."); | "Negative block height."); | ||||
} | } | ||||
// Height value more than a billion is too high to be a block | // Height value more than a billion is too high to be a block | ||||
// height, and too low to be a block time (corresponds to timestamp | // height, and too low to be a block time (corresponds to timestamp | ||||
// from Sep 2001). | // from Sep 2001). | ||||
if (heightParam > 1000000000) { | if (heightParam > 1000000000) { | ||||
// Add a 2 hour buffer to include blocks which might have had | // Add a 2 hour buffer to include blocks which might have had | ||||
// old timestamps | // old timestamps | ||||
CBlockIndex *pindex = | CBlockIndex *pindex = active_chain.FindEarliestAtLeast( | ||||
chainman.ActiveChain().FindEarliestAtLeast( | |||||
heightParam - TIMESTAMP_WINDOW, 0); | heightParam - TIMESTAMP_WINDOW, 0); | ||||
if (!pindex) { | if (!pindex) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"Could not find block with at least the " | "Could not find block with at least the " | ||||
"specified timestamp."); | "specified timestamp."); | ||||
} | } | ||||
heightParam = pindex->nHeight; | heightParam = pindex->nHeight; | ||||
} | } | ||||
unsigned int height = (unsigned int)heightParam; | unsigned int height = (unsigned int)heightParam; | ||||
unsigned int chainHeight = (unsigned int)chainman.ActiveHeight(); | unsigned int chainHeight = (unsigned int)active_chain.Height(); | ||||
if (chainHeight < config.GetChainParams().PruneAfterHeight()) { | if (chainHeight < config.GetChainParams().PruneAfterHeight()) { | ||||
throw JSONRPCError(RPC_MISC_ERROR, | throw JSONRPCError(RPC_MISC_ERROR, | ||||
"Blockchain is too short for pruning."); | "Blockchain is too short for pruning."); | ||||
} else if (height > chainHeight) { | } else if (height > chainHeight) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_INVALID_PARAMETER, | RPC_INVALID_PARAMETER, | ||||
"Blockchain is shorter than the attempted prune height."); | "Blockchain is shorter than the attempted prune height."); | ||||
} else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { | } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { | ||||
LogPrint(BCLog::RPC, | LogPrint(BCLog::RPC, | ||||
"Attempt to prune blocks close to the tip. " | "Attempt to prune blocks close to the tip. " | ||||
"Retaining the minimum number of blocks.\n"); | "Retaining the minimum number of blocks.\n"); | ||||
height = chainHeight - MIN_BLOCKS_TO_KEEP; | height = chainHeight - MIN_BLOCKS_TO_KEEP; | ||||
} | } | ||||
PruneBlockFilesManual(chainman.ActiveChainstate(), height); | PruneBlockFilesManual(active_chainstate, height); | ||||
const CBlockIndex *block = chainman.ActiveTip(); | const CBlockIndex *block = active_chain.Tip(); | ||||
CHECK_NONFATAL(block); | CHECK_NONFATAL(block); | ||||
while (block->pprev && (block->pprev->nStatus.hasData())) { | while (block->pprev && (block->pprev->nStatus.hasData())) { | ||||
block = block->pprev; | block = block->pprev; | ||||
} | } | ||||
return uint64_t(block->nHeight); | return uint64_t(block->nHeight); | ||||
}, | }, | ||||
}; | }; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 415 Lines • ▼ Show 20 Lines | return RPCHelpMan{ | ||||
RPCExamples{HelpExampleCli("getblockchaininfo", "") + | RPCExamples{HelpExampleCli("getblockchaininfo", "") + | ||||
HelpExampleRpc("getblockchaininfo", "")}, | HelpExampleRpc("getblockchaininfo", "")}, | ||||
[&](const RPCHelpMan &self, const Config &config, | [&](const RPCHelpMan &self, const Config &config, | ||||
const JSONRPCRequest &request) -> UniValue { | const JSONRPCRequest &request) -> UniValue { | ||||
const CChainParams &chainparams = config.GetChainParams(); | const CChainParams &chainparams = config.GetChainParams(); | ||||
ChainstateManager &chainman = EnsureAnyChainman(request.context); | ChainstateManager &chainman = EnsureAnyChainman(request.context); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CChainState &active_chainstate = chainman.ActiveChainstate(); | |||||
const CBlockIndex *tip = chainman.ActiveTip(); | const CBlockIndex *tip = active_chainstate.m_chain.Tip(); | ||||
CHECK_NONFATAL(tip); | CHECK_NONFATAL(tip); | ||||
const int height = tip->nHeight; | const int height = tip->nHeight; | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
obj.pushKV("chain", chainparams.NetworkIDString()); | obj.pushKV("chain", chainparams.NetworkIDString()); | ||||
obj.pushKV("blocks", height); | obj.pushKV("blocks", height); | ||||
obj.pushKV("headers", | obj.pushKV("headers", | ||||
pindexBestHeader ? pindexBestHeader->nHeight : -1); | pindexBestHeader ? pindexBestHeader->nHeight : -1); | ||||
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); | obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); | ||||
obj.pushKV("difficulty", double(GetDifficulty(tip))); | obj.pushKV("difficulty", double(GetDifficulty(tip))); | ||||
obj.pushKV("mediantime", int64_t(tip->GetMedianTimePast())); | obj.pushKV("mediantime", int64_t(tip->GetMedianTimePast())); | ||||
obj.pushKV("verificationprogress", | obj.pushKV("verificationprogress", | ||||
GuessVerificationProgress(Params().TxData(), tip)); | GuessVerificationProgress(Params().TxData(), tip)); | ||||
obj.pushKV("initialblockdownload", | obj.pushKV("initialblockdownload", | ||||
chainman.ActiveChainstate().IsInitialBlockDownload()); | active_chainstate.IsInitialBlockDownload()); | ||||
obj.pushKV("chainwork", tip->nChainWork.GetHex()); | obj.pushKV("chainwork", tip->nChainWork.GetHex()); | ||||
obj.pushKV("size_on_disk", CalculateCurrentUsage()); | obj.pushKV("size_on_disk", CalculateCurrentUsage()); | ||||
obj.pushKV("pruned", fPruneMode); | obj.pushKV("pruned", fPruneMode); | ||||
if (fPruneMode) { | if (fPruneMode) { | ||||
const CBlockIndex *block = tip; | const CBlockIndex *block = tip; | ||||
CHECK_NONFATAL(block); | CHECK_NONFATAL(block); | ||||
while (block->pprev && (block->pprev->nStatus.hasData())) { | while (block->pprev && (block->pprev->nStatus.hasData())) { | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | return RPCHelpMan{ | ||||
"active main chain, which is certainly valid"}, | "active main chain, which is certainly valid"}, | ||||
}}}}, | }}}}, | ||||
RPCExamples{HelpExampleCli("getchaintips", "") + | RPCExamples{HelpExampleCli("getchaintips", "") + | ||||
HelpExampleRpc("getchaintips", "")}, | HelpExampleRpc("getchaintips", "")}, | ||||
[&](const RPCHelpMan &self, const Config &config, | [&](const RPCHelpMan &self, const Config &config, | ||||
const JSONRPCRequest &request) -> UniValue { | const JSONRPCRequest &request) -> UniValue { | ||||
ChainstateManager &chainman = EnsureAnyChainman(request.context); | ChainstateManager &chainman = EnsureAnyChainman(request.context); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CChain &active_chain = chainman.ActiveChain(); | |||||
/** | /** | ||||
* Idea: The set of chain tips is the active chain tip, plus orphan | * Idea: The set of chain tips is the active chain tip, plus orphan | ||||
* blocks which do not have another orphan building off of them. | * blocks which do not have another orphan building off of them. | ||||
* Algorithm: | * Algorithm: | ||||
* - Make one pass through BlockIndex(), picking out the orphan | * - Make one pass through BlockIndex(), picking out the orphan | ||||
* blocks, and also storing a set of the orphan block's pprev | * blocks, and also storing a set of the orphan block's pprev | ||||
* pointers. | * pointers. | ||||
* - Iterate through the orphan blocks. If the block isn't pointed | * - Iterate through the orphan blocks. If the block isn't pointed | ||||
* to by another orphan, it is a chain tip. | * to by another orphan, it is a chain tip. | ||||
* - Add the active chain tip | * - Add the active chain tip | ||||
*/ | */ | ||||
std::set<const CBlockIndex *, CompareBlocksByHeight> setTips; | std::set<const CBlockIndex *, CompareBlocksByHeight> setTips; | ||||
std::set<const CBlockIndex *> setOrphans; | std::set<const CBlockIndex *> setOrphans; | ||||
std::set<const CBlockIndex *> setPrevs; | std::set<const CBlockIndex *> setPrevs; | ||||
for (const std::pair<const BlockHash, CBlockIndex *> &item : | for (const std::pair<const BlockHash, CBlockIndex *> &item : | ||||
chainman.BlockIndex()) { | chainman.BlockIndex()) { | ||||
if (!chainman.ActiveChain().Contains(item.second)) { | if (!active_chain.Contains(item.second)) { | ||||
setOrphans.insert(item.second); | setOrphans.insert(item.second); | ||||
setPrevs.insert(item.second->pprev); | setPrevs.insert(item.second->pprev); | ||||
} | } | ||||
} | } | ||||
for (std::set<const CBlockIndex *>::iterator it = | for (std::set<const CBlockIndex *>::iterator it = | ||||
setOrphans.begin(); | setOrphans.begin(); | ||||
it != setOrphans.end(); ++it) { | it != setOrphans.end(); ++it) { | ||||
if (setPrevs.erase(*it) == 0) { | if (setPrevs.erase(*it) == 0) { | ||||
setTips.insert(*it); | setTips.insert(*it); | ||||
} | } | ||||
} | } | ||||
// Always report the currently active tip. | // Always report the currently active tip. | ||||
setTips.insert(chainman.ActiveChain().Tip()); | setTips.insert(active_chain.Tip()); | ||||
/* Construct the output array. */ | /* Construct the output array. */ | ||||
UniValue res(UniValue::VARR); | UniValue res(UniValue::VARR); | ||||
for (const CBlockIndex *block : setTips) { | for (const CBlockIndex *block : setTips) { | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
obj.pushKV("height", block->nHeight); | obj.pushKV("height", block->nHeight); | ||||
obj.pushKV("hash", block->phashBlock->GetHex()); | obj.pushKV("hash", block->phashBlock->GetHex()); | ||||
const int branchLen = | const int branchLen = | ||||
block->nHeight - | block->nHeight - active_chain.FindFork(block)->nHeight; | ||||
chainman.ActiveChain().FindFork(block)->nHeight; | |||||
obj.pushKV("branchlen", branchLen); | obj.pushKV("branchlen", branchLen); | ||||
std::string status; | std::string status; | ||||
if (chainman.ActiveChain().Contains(block)) { | if (active_chain.Contains(block)) { | ||||
// This block is part of the currently active chain. | // This block is part of the currently active chain. | ||||
status = "active"; | status = "active"; | ||||
} else if (block->nStatus.isInvalid()) { | } else if (block->nStatus.isInvalid()) { | ||||
// This block or one of its ancestors is invalid. | // This block or one of its ancestors is invalid. | ||||
status = "invalid"; | status = "invalid"; | ||||
} else if (block->nStatus.isOnParkedChain()) { | } else if (block->nStatus.isOnParkedChain()) { | ||||
// This block or one of its ancestors is parked. | // This block or one of its ancestors is parked. | ||||
status = "parked"; | status = "parked"; | ||||
▲ Show 20 Lines • Show All 566 Lines • ▼ Show 20 Lines | return RPCHelpMan{ | ||||
"getblockstats", | "getblockstats", | ||||
R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") + | R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") + | ||||
HelpExampleRpc("getblockstats", | HelpExampleRpc("getblockstats", | ||||
R"(1000, ["minfeerate","avgfeerate"])")}, | R"(1000, ["minfeerate","avgfeerate"])")}, | ||||
[&](const RPCHelpMan &self, const Config &config, | [&](const RPCHelpMan &self, const Config &config, | ||||
const JSONRPCRequest &request) -> UniValue { | const JSONRPCRequest &request) -> UniValue { | ||||
ChainstateManager &chainman = EnsureAnyChainman(request.context); | ChainstateManager &chainman = EnsureAnyChainman(request.context); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CChain &active_chain = chainman.ActiveChain(); | |||||
CBlockIndex *pindex; | CBlockIndex *pindex; | ||||
if (request.params[0].isNum()) { | if (request.params[0].isNum()) { | ||||
const int height = request.params[0].get_int(); | const int height = request.params[0].get_int(); | ||||
const int current_tip = chainman.ActiveHeight(); | const int current_tip = active_chain.Height(); | ||||
if (height < 0) { | if (height < 0) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_INVALID_PARAMETER, | RPC_INVALID_PARAMETER, | ||||
strprintf("Target block height %d is negative", | strprintf("Target block height %d is negative", | ||||
height)); | height)); | ||||
} | } | ||||
if (height > current_tip) { | if (height > current_tip) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_INVALID_PARAMETER, | RPC_INVALID_PARAMETER, | ||||
strprintf("Target block height %d after current tip %d", | strprintf("Target block height %d after current tip %d", | ||||
height, current_tip)); | height, current_tip)); | ||||
} | } | ||||
pindex = chainman.ActiveChain()[height]; | pindex = active_chain[height]; | ||||
} else { | } else { | ||||
const BlockHash hash( | const BlockHash hash( | ||||
ParseHashV(request.params[0], "hash_or_height")); | ParseHashV(request.params[0], "hash_or_height")); | ||||
pindex = chainman.m_blockman.LookupBlockIndex(hash); | pindex = chainman.m_blockman.LookupBlockIndex(hash); | ||||
if (!pindex) { | if (!pindex) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Block not found"); | "Block not found"); | ||||
} | } | ||||
if (!chainman.ActiveChain().Contains(pindex)) { | if (!active_chain.Contains(pindex)) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
strprintf("Block is not in chain %s", | strprintf("Block is not in chain %s", | ||||
Params().NetworkIDString())); | Params().NetworkIDString())); | ||||
} | } | ||||
} | } | ||||
CHECK_NONFATAL(pindex != nullptr); | CHECK_NONFATAL(pindex != nullptr); | ||||
▲ Show 20 Lines • Show All 441 Lines • ▼ Show 20 Lines | return RPCHelpMan{ | ||||
g_scan_progress = 0; | g_scan_progress = 0; | ||||
int64_t count = 0; | int64_t count = 0; | ||||
std::unique_ptr<CCoinsViewCursor> pcursor; | std::unique_ptr<CCoinsViewCursor> pcursor; | ||||
CBlockIndex *tip; | CBlockIndex *tip; | ||||
NodeContext &node = EnsureAnyNodeContext(request.context); | NodeContext &node = EnsureAnyNodeContext(request.context); | ||||
{ | { | ||||
ChainstateManager &chainman = EnsureChainman(node); | ChainstateManager &chainman = EnsureChainman(node); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
chainman.ActiveChainstate().ForceFlushStateToDisk(); | CChainState &active_chainstate = | ||||
chainman.ActiveChainstate(); | |||||
active_chainstate.ForceFlushStateToDisk(); | |||||
pcursor = std::unique_ptr<CCoinsViewCursor>( | pcursor = std::unique_ptr<CCoinsViewCursor>( | ||||
chainman.ActiveChainstate().CoinsDB().Cursor()); | active_chainstate.CoinsDB().Cursor()); | ||||
CHECK_NONFATAL(pcursor); | CHECK_NONFATAL(pcursor); | ||||
tip = chainman.ActiveTip(); | tip = active_chainstate.m_chain.Tip(); | ||||
CHECK_NONFATAL(tip); | CHECK_NONFATAL(tip); | ||||
} | } | ||||
bool res = FindScriptPubKey( | bool res = FindScriptPubKey( | ||||
g_scan_progress, g_should_abort_scan, count, pcursor.get(), | g_scan_progress, g_should_abort_scan, count, pcursor.get(), | ||||
needles, coins, node.rpc_interruption_point); | needles, coins, node.rpc_interruption_point); | ||||
result.pushKV("success", res); | result.pushKV("success", res); | ||||
result.pushKV("txouts", count); | result.pushKV("txouts", count); | ||||
result.pushKV("height", tip->nHeight); | result.pushKV("height", tip->nHeight); | ||||
▲ Show 20 Lines • Show All 298 Lines • Show Last 20 Lines |