diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -78,20 +78,18 @@ result.pushKV("confirmations", confirmations); result.pushKV("height", blockindex->nHeight); result.pushKV("version", blockindex->nVersion); - result.push_back( - Pair("versionHex", strprintf("%08x", blockindex->nVersion))); + result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion)); result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex()); result.pushKV("time", int64_t(blockindex->nTime)); - result.push_back( - Pair("mediantime", int64_t(blockindex->GetMedianTimePast()))); + result.pushKV("mediantime", int64_t(blockindex->GetMedianTimePast())); result.pushKV("nonce", uint64_t(blockindex->nNonce)); result.pushKV("bits", strprintf("%08x", blockindex->nBits)); result.pushKV("difficulty", GetDifficulty(blockindex)); result.pushKV("chainwork", blockindex->nChainWork.GetHex()); if (blockindex->pprev) { - result.push_back(Pair("previousblockhash", - blockindex->pprev->GetBlockHash().GetHex())); + result.pushKV("previousblockhash", + blockindex->pprev->GetBlockHash().GetHex()); } CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) { @@ -110,8 +108,8 @@ confirmations = chainActive.Height() - blockindex->nHeight + 1; } result.pushKV("confirmations", confirmations); - result.push_back(Pair( - "size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); + result.pushKV( + "size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)); result.pushKV("height", blockindex->nHeight); result.pushKV("version", block.nVersion); result.pushKV("versionHex", strprintf("%08x", block.nVersion)); @@ -128,16 +126,15 @@ } result.pushKV("tx", txs); result.pushKV("time", block.GetBlockTime()); - result.push_back( - Pair("mediantime", int64_t(blockindex->GetMedianTimePast()))); + result.pushKV("mediantime", int64_t(blockindex->GetMedianTimePast())); result.pushKV("nonce", uint64_t(block.nNonce)); result.pushKV("bits", strprintf("%08x", block.nBits)); result.pushKV("difficulty", GetDifficulty(blockindex)); result.pushKV("chainwork", blockindex->nChainWork.GetHex()); if (blockindex->pprev) { - result.push_back(Pair("previousblockhash", - blockindex->pprev->GetBlockHash().GetHex())); + result.pushKV("previousblockhash", + blockindex->pprev->GetBlockHash().GetHex()); } CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) { @@ -179,6 +176,19 @@ return chainActive.Tip()->GetBlockHash().GetHex(); } +UniValue getfinalizedblock(const Config &config, + const JSONRPCRequest &request) { + if (request.fHelp || request.params.size() != 0) { + throw std::runtime_error( + "getfinalizedblock\n" + "\nReturns the hash of the currently finalized block\n" + "\nResult:\n" + "\"hex\" (string) the block hash hex encoded\n"); + } + + return GetFinalizedBlockHash().GetHex(); +} + void RPCNotifyBlockChange(bool ibd, const CBlockIndex *pindex) { if (pindex) { std::lock_guard lock(cs_blockchange); @@ -407,12 +417,10 @@ info.pushKV("time", e.GetTime()); info.pushKV("height", (int)e.GetHeight()); info.pushKV("startingpriority", e.GetPriority(e.GetHeight())); - info.push_back( - Pair("currentpriority", e.GetPriority(chainActive.Height()))); + info.pushKV("currentpriority", e.GetPriority(chainActive.Height())); info.pushKV("descendantcount", e.GetCountWithDescendants()); info.pushKV("descendantsize", e.GetSizeWithDescendants()); - info.push_back( - Pair("descendantfees", e.GetModFeesWithDescendants() / SATOSHI)); + info.pushKV("descendantfees", e.GetModFeesWithDescendants() / SATOSHI); info.pushKV("ancestorcount", e.GetCountWithAncestors()); info.pushKV("ancestorsize", e.GetSizeWithAncestors()); info.pushKV("ancestorfees", e.GetModFeesWithAncestors() / SATOSHI); @@ -1040,8 +1048,7 @@ ret.pushKV("bogosize", int64_t(stats.nBogoSize)); ret.pushKV("hash_serialized", stats.hashSerialized.GetHex()); ret.pushKV("disk_size", stats.nDiskSize); - ret.push_back( - Pair("total_amount", ValueFromAmount(stats.nTotalAmount))); + ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount)); } else { throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); } @@ -1126,8 +1133,8 @@ if (coin.GetHeight() == MEMPOOL_HEIGHT) { ret.pushKV("confirmations", 0); } else { - ret.push_back(Pair("confirmations", - int64_t(pindex->nHeight - coin.GetHeight() + 1))); + ret.pushKV("confirmations", + int64_t(pindex->nHeight - coin.GetHeight() + 1)); } ret.pushKV("value", ValueFromAmount(coin.GetTxOut().nValue)); UniValue o(UniValue::VOBJ); @@ -1201,8 +1208,7 @@ UniValue rv(UniValue::VOBJ); rv.pushKV("id", name); rv.pushKV("version", version); - rv.push_back( - Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams))); + rv.pushKV("reject", SoftForkMajorityDesc(version, pindex, consensusParams)); return rv; } @@ -1257,17 +1263,13 @@ UniValue obj(UniValue::VOBJ); obj.pushKV("chain", config.GetChainParams().NetworkIDString()); obj.pushKV("blocks", int(chainActive.Height())); - obj.push_back( - Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); - obj.push_back( - Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); + obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); + obj.pushKV("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()); obj.pushKV("difficulty", double(GetDifficulty(chainActive.Tip()))); - obj.push_back( - Pair("mediantime", int64_t(chainActive.Tip()->GetMedianTimePast()))); - obj.push_back( - Pair("verificationprogress", - GuessVerificationProgress(config.GetChainParams().TxData(), - chainActive.Tip()))); + obj.pushKV("mediantime", int64_t(chainActive.Tip()->GetMedianTimePast())); + obj.pushKV("verificationprogress", + GuessVerificationProgress(config.GetChainParams().TxData(), + chainActive.Tip())); obj.pushKV("chainwork", chainActive.Tip()->nChainWork.GetHex()); obj.pushKV("pruned", fPruneMode); @@ -1434,9 +1436,8 @@ size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; ret.pushKV("maxmempool", (int64_t)maxmempool); - ret.push_back( - Pair("mempoolminfee", - ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK()))); + ret.pushKV("mempoolminfee", + ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK())); return ret; } @@ -1827,6 +1828,7 @@ { "blockchain", "preciousblock", preciousblock, {"blockhash"} }, /* Not shown in help */ + { "hidden", "getfinalizedblock", getfinalizedblock, {""} }, { "hidden", "finalizeblock", finalizeblock, {"blockhash"} }, { "hidden", "invalidateblock", invalidateblock, {"blockhash"} }, { "hidden", "parkblock", parkblock, {"blockhash"} }, diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -636,6 +636,8 @@ bool FinalizeBlockAndInvalidate(const Config &config, CValidationState &state, CBlockIndex *pindex); +uint256 GetFinalizedBlockHash(); + /** Mark a block as invalid. */ bool InvalidateBlock(const Config &config, CValidationState &state, CBlockIndex *pindex); diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2915,6 +2915,11 @@ return true; } +uint256 GetFinalizedBlockHash() { + LOCK(cs_main); + return pindexFinalized->GetBlockHash(); +} + bool InvalidateBlock(const Config &config, CValidationState &state, CBlockIndex *pindex) { return UnwindBlock(config, state, pindex, true); diff --git a/test/functional/abc-finalize-block.py b/test/functional/abc-finalize-block.py --- a/test/functional/abc-finalize-block.py +++ b/test/functional/abc-finalize-block.py @@ -76,10 +76,13 @@ self.log.info("Trigger reorg via block finalization...") node.finalizeblock(tip) assert_equal(node.getbestblockhash(), tip) + assert_equal(node.getfinalizedblock(), tip) self.log.info("Try to finalized a block on a competiting fork...") assert_raises_rpc_error(-20, RPC_FINALIZE_INVALID_BLOCK_ERROR, node.finalizeblock, alt_node.getbestblockhash()) + assert_not_equal(node.getfinalizedblock(), alt_node.getbestblockhash()) + assert_equal(node.getfinalizedblock(), tip) if __name__ == '__main__':