Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
Already on GitHub? Sign in to your account
Add missing cs_main locks when accessing chainActive #11596
Conversation
| - if (chainActive.Tip() == nullptr || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) { | ||
| - setBlockIndexCandidates.insert(pindex); | ||
| + { | ||
| + LOCK(cs_main); |
sdaftuar
Nov 2, 2017
•
Member
I think we can just add an AssertLockHeld(cs_main) to the top of this function -- this function only has two callers, both of which lock cs_main before calling.
EDIT: actually one of the callers does AssertLockHeld(cs_main).
| - assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); | ||
| + { | ||
| + LOCK(cs_main); | ||
| + assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); |
morcos
Nov 2, 2017
Member
I think we should just get rid of this assert. We can't guarantee chainActive height will not go down.
fanquake
added
the
Refactoring
label
Nov 3, 2017
| @@ -2639,7 +2639,10 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT | ||
| // enough, that fee sniping isn't a problem yet, but by implementing a fix | ||
| // now we ensure code won't be written that makes assumptions about | ||
| // nLockTime that preclude a fix later. | ||
| - txNew.nLockTime = chainActive.Height(); | ||
| + { | ||
| + LOCK(cs_main); |
promag
Nov 3, 2017
Contributor
Remove, all callers have cs_main locked, assert lock is held instead. Ping @ryanofsky as he says the goal is to removed recursive locks.
practicalswift
Nov 6, 2017
•
Contributor
@promag I'm getting an assertion failure when running test/functional/test_runner.py with your suggested patch applied. Does it pass for you? Reverting to previous version for now.
|
@practicalswift following #11596 (comment), I believe a7eb21a is the fix. |
| - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; | ||
| + { | ||
| + LOCK(cs_main); | ||
| + ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; |
TheBlueMatt
Nov 6, 2017
Contributor
nit: care to do the serialization of bitmap/outs outside of cs_main (same below)?
| @@ -2594,6 +2594,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC | ||
| bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, | ||
| int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign) | ||
| { | ||
| + AssertLockHeld(cs_main); |
TheBlueMatt
Nov 6, 2017
Contributor
Ugh, can we not add more cs_main requirements - if the goal is to resolve the chainActive.Height() issue only then please add the cs_main around just that, its not gonna hurt anything to not hold cs_main for the duration of this function, and we really should be trying to remove cs_main from this function, not go the other way.
|
@TheBlueMatt Thanks for reviewing. Feedback addressed. |
| - if (!pwallet->FundTransaction(tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl)) { | ||
| - throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); | ||
| + { | ||
| + LOCK2(cs_main, pwallet->cs_wallet); |
TheBlueMatt
Nov 7, 2017
Contributor
Please no. Can we instead add the locking in CreateTransaction itself? We need to be pushing locks down, especially when it comes to cs_main, not putting more locks in RPC functions.
|
Reverting the patch suggested by @promag. The locking is now made down in |
|
utACK 2e441c9 |
ryanofsky
referenced this pull request
Nov 10, 2017
Open
[WIP] Add Clang thread safety analysis annotations: GUARDED_BY(lock) / EXCLUSIVE_LOCKS_REQUIRED(lock) #11226
| - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; | ||
| + { | ||
| + LOCK(cs_main); | ||
| + ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash(); |
luke-jr
Nov 10, 2017
Member
This isn't sufficient I think. We don't want to allow chainActive to change from when we get the results, to when we identify the chain they're for. So extract this info above in the first lock...
practicalswift
Nov 10, 2017
Contributor
@luke-jr Thanks for reviewing. Do you mean like this?
diff --git a/src/rest.cpp b/src/rest.cpp
index 0ed11e6..649059e 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -479,6 +479,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
std::string bitmapStringRepresentation;
std::vector<bool> hits;
bitmap.resize((vOutPoints.size() + 7) / 8);
+ int chainActiveHeight;
+ uint256 chainActiveTipBlockHash;
{
LOCK2(cs_main, mempool.cs);
@@ -503,6 +505,9 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
bitmapStringRepresentation.append(hit ? "1" : "0"); // form a binary string representation (human-readable for json output)
bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
}
+
+ chainActiveHeight = chainActive.Height();
+ chainActiveTipBlockHash = chainActive.Tip()->GetBlockHash();
}
switch (rf) {
@@ -510,11 +515,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// serialize data
// use exact same output as mentioned in Bip64
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
- {
- LOCK(cs_main);
- ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash();
- }
- ssGetUTXOResponse << bitmap << outs;
+ ssGetUTXOResponse << chainActiveHeight << chainActiveTipBlockHash << bitmap << outs;
std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
req->WriteHeader("Content-Type", "application/octet-stream");
@@ -524,11 +525,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
case RF_HEX: {
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
- {
- LOCK(cs_main);
- ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash();
- }
- ssGetUTXOResponse << bitmap << outs;
+ ssGetUTXOResponse << chainActiveHeight << chainActiveTipBlockHash << bitmap << outs;
std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n";
req->WriteHeader("Content-Type", "text/plain");
@@ -541,11 +538,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// pack in some essentials
// use more or less the same output as mentioned in Bip64
- {
- LOCK(cs_main);
- objGetUTXOResponse.push_back(Pair("chainHeight", chainActive.Height()));
- objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex()));
- }
+ objGetUTXOResponse.push_back(Pair("chainHeight", chainActiveHeight));
+ objGetUTXOResponse.push_back(Pair("chaintipHash", chainActiveTipBlockHash.GetHex()));
objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation));
UniValue utxos(UniValue::VARR);| - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; | ||
| + { | ||
| + LOCK(cs_main); | ||
| + ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash(); |
| + { | ||
| + LOCK(cs_main); | ||
| + objGetUTXOResponse.push_back(Pair("chainHeight", chainActive.Height())); | ||
| + objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex())); |
|
@practicalswift why did you rebase this? It makes reviewing something that was previously reviewed much more difficult. Mind squashing the two commits? There seems to be no reason to have them separate. |
added a commit
to bitcoinknots/bitcoin
that referenced
this pull request
Nov 11, 2017
added a commit
to bitcoinknots/bitcoin
that referenced
this pull request
Nov 11, 2017
|
Now squashed into one commit. Please re-review! :-) @TheBlueMatt The reason for the rebase was that I wanted to get rebased on top of 76ea17c (IIRC) in order to get the build to pass – I always compile with The reason for the two commits was to allow separate review for the latter commit in the case that I had misunderstood @luke-jr:s suggestion and needed to revert. |
|
Updated:
Please review :-) |
practicalswift commentedNov 2, 2017
Add missing
cs_mainlocks when accessingchainActive.The variable
chainActiveis guarded by the mutexcs_main.