|
|
|
@ -73,13 +73,11 @@ static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
|
|
|
|
|
|
|
|
|
|
/* Calculate the difficulty for a given block index.
|
|
|
|
|
*/
|
|
|
|
|
double GetDifficulty(const CBlockIndex* blockindex)
|
|
|
|
|
double GetDifficulty(const CBlockIndex& blockindex)
|
|
|
|
|
{
|
|
|
|
|
CHECK_NONFATAL(blockindex);
|
|
|
|
|
|
|
|
|
|
int nShift = (blockindex->nBits >> 24) & 0xff;
|
|
|
|
|
int nShift = (blockindex.nBits >> 24) & 0xff;
|
|
|
|
|
double dDiff =
|
|
|
|
|
(double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
|
|
|
|
|
(double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
|
|
|
|
|
|
|
|
|
|
while (nShift < 29)
|
|
|
|
|
{
|
|
|
|
@ -95,14 +93,14 @@ double GetDifficulty(const CBlockIndex* blockindex)
|
|
|
|
|
return dDiff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
|
|
|
|
|
static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
|
|
|
|
|
{
|
|
|
|
|
next = tip->GetAncestor(blockindex->nHeight + 1);
|
|
|
|
|
if (next && next->pprev == blockindex) {
|
|
|
|
|
return tip->nHeight - blockindex->nHeight + 1;
|
|
|
|
|
next = tip.GetAncestor(blockindex.nHeight + 1);
|
|
|
|
|
if (next && next->pprev == &blockindex) {
|
|
|
|
|
return tip.nHeight - blockindex.nHeight + 1;
|
|
|
|
|
}
|
|
|
|
|
next = nullptr;
|
|
|
|
|
return blockindex == tip ? 1 : -1;
|
|
|
|
|
return &blockindex == &tip ? 1 : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
|
|
|
|
@ -133,36 +131,36 @@ static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateMan
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
UniValue result(UniValue::VOBJ);
|
|
|
|
|
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
|
|
|
|
|
result.pushKV("hash", blockindex.GetBlockHash().GetHex());
|
|
|
|
|
const CBlockIndex* pnext;
|
|
|
|
|
int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
|
|
|
|
|
result.pushKV("confirmations", confirmations);
|
|
|
|
|
result.pushKV("height", blockindex->nHeight);
|
|
|
|
|
result.pushKV("version", blockindex->nVersion);
|
|
|
|
|
result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
|
|
|
|
|
result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
|
|
|
|
|
result.pushKV("time", (int64_t)blockindex->nTime);
|
|
|
|
|
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
|
|
|
|
|
result.pushKV("nonce", (uint64_t)blockindex->nNonce);
|
|
|
|
|
result.pushKV("bits", strprintf("%08x", blockindex->nBits));
|
|
|
|
|
result.pushKV("height", blockindex.nHeight);
|
|
|
|
|
result.pushKV("version", blockindex.nVersion);
|
|
|
|
|
result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
|
|
|
|
|
result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
|
|
|
|
|
result.pushKV("time", blockindex.nTime);
|
|
|
|
|
result.pushKV("mediantime", blockindex.GetMedianTimePast());
|
|
|
|
|
result.pushKV("nonce", blockindex.nNonce);
|
|
|
|
|
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
|
|
|
|
|
result.pushKV("difficulty", GetDifficulty(blockindex));
|
|
|
|
|
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
|
|
|
|
|
result.pushKV("nTx", (uint64_t)blockindex->nTx);
|
|
|
|
|
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
|
|
|
|
|
result.pushKV("nTx", blockindex.nTx);
|
|
|
|
|
|
|
|
|
|
if (blockindex->pprev)
|
|
|
|
|
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
|
|
|
|
|
if (blockindex.pprev)
|
|
|
|
|
result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
|
|
|
|
|
if (pnext)
|
|
|
|
|
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
|
|
|
|
|
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity)
|
|
|
|
|
{
|
|
|
|
|
UniValue result = blockheaderToJSON(tip, blockindex);
|
|
|
|
|
|
|
|
|
@ -181,8 +179,8 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn
|
|
|
|
|
case TxVerbosity::SHOW_DETAILS:
|
|
|
|
|
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
|
|
|
|
|
CBlockUndo blockUndo;
|
|
|
|
|
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(*blockindex))};
|
|
|
|
|
const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, *blockindex)};
|
|
|
|
|
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
|
|
|
|
|
const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, blockindex)};
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < block.vtx.size(); ++i) {
|
|
|
|
|
const CTransactionRef& tx = block.vtx.at(i);
|
|
|
|
@ -418,7 +416,7 @@ static RPCHelpMan getdifficulty()
|
|
|
|
|
{
|
|
|
|
|
ChainstateManager& chainman = EnsureAnyChainman(request.context);
|
|
|
|
|
LOCK(cs_main);
|
|
|
|
|
return GetDifficulty(chainman.ActiveChain().Tip());
|
|
|
|
|
return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -571,22 +569,22 @@ static RPCHelpMan getblockheader()
|
|
|
|
|
return strHex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return blockheaderToJSON(tip, pblockindex);
|
|
|
|
|
return blockheaderToJSON(*tip, *pblockindex);
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
|
|
|
|
|
static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
|
|
|
|
|
{
|
|
|
|
|
CBlock block;
|
|
|
|
|
{
|
|
|
|
|
LOCK(cs_main);
|
|
|
|
|
if (blockman.IsBlockPruned(*pblockindex)) {
|
|
|
|
|
if (blockman.IsBlockPruned(blockindex)) {
|
|
|
|
|
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
|
|
|
|
|
if (!blockman.ReadBlockFromDisk(block, blockindex)) {
|
|
|
|
|
// Block not found on disk. This could be because we have the block
|
|
|
|
|
// header in our index but not yet have the block or did not accept the
|
|
|
|
|
// block. Or if the block was pruned right after we released the lock above.
|
|
|
|
@ -596,21 +594,21 @@ static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblocki
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
|
|
|
|
|
static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
|
|
|
|
|
{
|
|
|
|
|
CBlockUndo blockUndo;
|
|
|
|
|
|
|
|
|
|
// The Genesis block does not have undo data
|
|
|
|
|
if (pblockindex->nHeight == 0) return blockUndo;
|
|
|
|
|
if (blockindex.nHeight == 0) return blockUndo;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
LOCK(cs_main);
|
|
|
|
|
if (blockman.IsBlockPruned(*pblockindex)) {
|
|
|
|
|
if (blockman.IsBlockPruned(blockindex)) {
|
|
|
|
|
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
|
|
|
|
|
if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) {
|
|
|
|
|
throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -736,7 +734,7 @@ static RPCHelpMan getblock()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CBlock block{GetBlockChecked(chainman.m_blockman, pblockindex)};
|
|
|
|
|
const CBlock block{GetBlockChecked(chainman.m_blockman, *pblockindex)};
|
|
|
|
|
|
|
|
|
|
if (verbosity <= 0)
|
|
|
|
|
{
|
|
|
|
@ -755,7 +753,7 @@ static RPCHelpMan getblock()
|
|
|
|
|
tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
|
|
|
|
|
return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -1257,7 +1255,7 @@ RPCHelpMan getblockchaininfo()
|
|
|
|
|
obj.pushKV("blocks", height);
|
|
|
|
|
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
|
|
|
|
|
obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
|
|
|
|
|
obj.pushKV("difficulty", GetDifficulty(&tip));
|
|
|
|
|
obj.pushKV("difficulty", GetDifficulty(tip));
|
|
|
|
|
obj.pushKV("time", tip.GetBlockTime());
|
|
|
|
|
obj.pushKV("mediantime", tip.GetMedianTimePast());
|
|
|
|
|
obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
|
|
|
|
@ -1815,8 +1813,8 @@ static RPCHelpMan getblockstats()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CBlock& block = GetBlockChecked(chainman.m_blockman, &pindex);
|
|
|
|
|
const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, &pindex);
|
|
|
|
|
const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
|
|
|
|
|
const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
|
|
|
|
|
|
|
|
|
|
const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
|
|
|
|
|
const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
|
|
|
|
@ -2275,8 +2273,8 @@ public:
|
|
|
|
|
|
|
|
|
|
static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
|
|
|
|
|
{
|
|
|
|
|
const CBlock block{GetBlockChecked(blockman, &blockindex)};
|
|
|
|
|
const CBlockUndo block_undo{GetUndoChecked(blockman, &blockindex)};
|
|
|
|
|
const CBlock block{GetBlockChecked(blockman, blockindex)};
|
|
|
|
|
const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
|
|
|
|
|
|
|
|
|
|
// Check if any of the outputs match the scriptPubKey
|
|
|
|
|
for (const auto& tx : block.vtx) {
|
|
|
|
@ -2845,7 +2843,7 @@ return RPCHelpMan{
|
|
|
|
|
|
|
|
|
|
data.pushKV("blocks", (int)chain.Height());
|
|
|
|
|
data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
|
|
|
|
|
data.pushKV("difficulty", (double)GetDifficulty(tip));
|
|
|
|
|
data.pushKV("difficulty", GetDifficulty(*tip));
|
|
|
|
|
data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
|
|
|
|
|
data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
|
|
|
|
|
data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
|
|
|
|
|