Skip to content

Commit f7e182a

Browse files
author
MarcoFalke
committed
Merge #12151: rpc: Remove cs_main lock from blockToJSON and blockheaderToJSON
b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin/bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
2 parents 5b6b371 + b9f226b commit f7e182a

File tree

4 files changed

+37
-48
lines changed

4 files changed

+37
-48
lines changed

src/rest.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,12 @@ static bool rest_headers(HTTPRequest* req,
136136
if (!ParseHashStr(hashStr, hash))
137137
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
138138

139+
const CBlockIndex* tip = nullptr;
139140
std::vector<const CBlockIndex *> headers;
140141
headers.reserve(count);
141142
{
142143
LOCK(cs_main);
144+
tip = chainActive.Tip();
143145
const CBlockIndex* pindex = LookupBlockIndex(hash);
144146
while (pindex != nullptr && chainActive.Contains(pindex)) {
145147
headers.push_back(pindex);
@@ -175,11 +177,8 @@ static bool rest_headers(HTTPRequest* req,
175177
}
176178
case RetFormat::JSON: {
177179
UniValue jsonHeaders(UniValue::VARR);
178-
{
179-
LOCK(cs_main);
180-
for (const CBlockIndex *pindex : headers) {
181-
jsonHeaders.push_back(blockheaderToJSON(pindex));
182-
}
180+
for (const CBlockIndex *pindex : headers) {
181+
jsonHeaders.push_back(blockheaderToJSON(tip, pindex));
183182
}
184183
std::string strJSON = jsonHeaders.write() + "\n";
185184
req->WriteHeader("Content-Type", "application/json");
@@ -207,8 +206,10 @@ static bool rest_block(HTTPRequest* req,
207206

208207
CBlock block;
209208
CBlockIndex* pblockindex = nullptr;
209+
CBlockIndex* tip = nullptr;
210210
{
211211
LOCK(cs_main);
212+
tip = chainActive.Tip();
212213
pblockindex = LookupBlockIndex(hash);
213214
if (!pblockindex) {
214215
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
@@ -241,11 +242,7 @@ static bool rest_block(HTTPRequest* req,
241242
}
242243

243244
case RetFormat::JSON: {
244-
UniValue objBlock;
245-
{
246-
LOCK(cs_main);
247-
objBlock = blockToJSON(block, pblockindex, showTxDetails);
248-
}
245+
UniValue objBlock = blockToJSON(block, tip, pblockindex, showTxDetails);
249246
std::string strJSON = objBlock.write() + "\n";
250247
req->WriteHeader("Content-Type", "application/json");
251248
req->WriteReply(HTTP_OK, strJSON);

src/rpc/blockchain.cpp

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,7 @@ static CUpdatedBlock latestblock;
5959
*/
6060
double GetDifficulty(const CBlockIndex* blockindex)
6161
{
62-
if (blockindex == nullptr)
63-
{
64-
return 1.0;
65-
}
62+
assert(blockindex);
6663

6764
int nShift = (blockindex->nBits >> 24) & 0xff;
6865
double dDiff =
@@ -82,15 +79,22 @@ double GetDifficulty(const CBlockIndex* blockindex)
8279
return dDiff;
8380
}
8481

85-
UniValue blockheaderToJSON(const CBlockIndex* blockindex)
82+
static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
83+
{
84+
next = tip->GetAncestor(blockindex->nHeight + 1);
85+
if (next && next->pprev == blockindex) {
86+
return tip->nHeight - blockindex->nHeight + 1;
87+
}
88+
next = nullptr;
89+
return blockindex == tip ? 1 : -1;
90+
}
91+
92+
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
8693
{
87-
AssertLockHeld(cs_main);
8894
UniValue result(UniValue::VOBJ);
8995
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
90-
int confirmations = -1;
91-
// Only report confirmations if the block is on the main chain
92-
if (chainActive.Contains(blockindex))
93-
confirmations = chainActive.Height() - blockindex->nHeight + 1;
96+
const CBlockIndex* pnext;
97+
int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
9498
result.pushKV("confirmations", confirmations);
9599
result.pushKV("height", blockindex->nHeight);
96100
result.pushKV("version", blockindex->nVersion);
@@ -106,21 +110,17 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
106110

107111
if (blockindex->pprev)
108112
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
109-
CBlockIndex *pnext = chainActive.Next(blockindex);
110113
if (pnext)
111114
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
112115
return result;
113116
}
114117

115-
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails)
118+
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails)
116119
{
117-
AssertLockHeld(cs_main);
118120
UniValue result(UniValue::VOBJ);
119121
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
120-
int confirmations = -1;
121-
// Only report confirmations if the block is on the main chain
122-
if (chainActive.Contains(blockindex))
123-
confirmations = chainActive.Height() - blockindex->nHeight + 1;
122+
const CBlockIndex* pnext;
123+
int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
124124
result.pushKV("confirmations", confirmations);
125125
result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
126126
result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
@@ -152,7 +152,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
152152

153153
if (blockindex->pprev)
154154
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
155-
CBlockIndex *pnext = chainActive.Next(blockindex);
156155
if (pnext)
157156
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
158157
return result;
@@ -769,7 +768,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
769768
return strHex;
770769
}
771770

772-
return blockheaderToJSON(pblockindex);
771+
return blockheaderToJSON(chainActive.Tip(), pblockindex);
773772
}
774773

775774
static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
@@ -871,7 +870,7 @@ static UniValue getblock(const JSONRPCRequest& request)
871870
return strHex;
872871
}
873872

874-
return blockToJSON(block, pblockindex, verbosity >= 2);
873+
return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2);
875874
}
876875

877876
struct CCoinsStats
@@ -1150,7 +1149,7 @@ static UniValue verifychain(const JSONRPCRequest& request)
11501149
}
11511150

11521151
/** Implementation of IsSuperMajority with better feedback */
1153-
static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
1152+
static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
11541153
{
11551154
UniValue rv(UniValue::VOBJ);
11561155
bool activated = false;
@@ -1170,7 +1169,7 @@ static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Con
11701169
return rv;
11711170
}
11721171

1173-
static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
1172+
static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
11741173
{
11751174
UniValue rv(UniValue::VOBJ);
11761175
rv.pushKV("id", name);
@@ -1277,20 +1276,21 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
12771276

12781277
LOCK(cs_main);
12791278

1279+
const CBlockIndex* tip = chainActive.Tip();
12801280
UniValue obj(UniValue::VOBJ);
12811281
obj.pushKV("chain", Params().NetworkIDString());
12821282
obj.pushKV("blocks", (int)chainActive.Height());
12831283
obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
1284-
obj.pushKV("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex());
1285-
obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip()));
1286-
obj.pushKV("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast());
1287-
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip()));
1284+
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
1285+
obj.pushKV("difficulty", (double)GetDifficulty(tip));
1286+
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
1287+
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
12881288
obj.pushKV("initialblockdownload", IsInitialBlockDownload());
1289-
obj.pushKV("chainwork", chainActive.Tip()->nChainWork.GetHex());
1289+
obj.pushKV("chainwork", tip->nChainWork.GetHex());
12901290
obj.pushKV("size_on_disk", CalculateCurrentUsage());
12911291
obj.pushKV("pruned", fPruneMode);
12921292
if (fPruneMode) {
1293-
CBlockIndex* block = chainActive.Tip();
1293+
const CBlockIndex* block = tip;
12941294
assert(block);
12951295
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
12961296
block = block->pprev;
@@ -1307,7 +1307,6 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
13071307
}
13081308

13091309
const Consensus::Params& consensusParams = Params().GetConsensus();
1310-
CBlockIndex* tip = chainActive.Tip();
13111310
UniValue softforks(UniValue::VARR);
13121311
UniValue bip9_softforks(UniValue::VOBJ);
13131312
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));

src/rpc/blockchain.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ double GetDifficulty(const CBlockIndex* blockindex);
2727
void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
2828

2929
/** Block description to JSON */
30-
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
30+
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false);
3131

3232
/** Mempool information to JSON */
3333
UniValue mempoolInfoToJSON();
@@ -36,7 +36,7 @@ UniValue mempoolInfoToJSON();
3636
UniValue mempoolToJSON(bool fVerbose = false);
3737

3838
/** Block header to JSON */
39-
UniValue blockheaderToJSON(const CBlockIndex* blockindex);
39+
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex);
4040

4141
/** Used by getblockstats to get feerates at different percentiles by weight */
4242
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight);

src/test/blockchain_tests.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,4 @@ BOOST_AUTO_TEST_CASE(get_difficulty_for_very_high_target)
6868
TestDifficulty(0x12345678, 5913134931067755359633408.0);
6969
}
7070

71-
// Verify that difficulty is 1.0 for an empty chain.
72-
BOOST_AUTO_TEST_CASE(get_difficulty_for_null_tip)
73-
{
74-
double difficulty = GetDifficulty(nullptr);
75-
RejectDifficultyMismatch(difficulty, 1.0);
76-
}
77-
7871
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)