Skip to content

Conversation

@practicalswift
Copy link
Contributor

@practicalswift practicalswift commented Nov 2, 2017

  • Add missing cs_main locks when accessing chainActive. (The variable chainActive is guarded by the mutex cs_main.)
  • Add corresponding annotations (GUARDED_BY + EXCLUSIVE_LOCKS_REQUIRED).

Copy link
Member

@sdaftuar sdaftuar Nov 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just get rid of this assert. We can't guarantee chainActive height will not go down.

@practicalswift
Copy link
Contributor Author

@sdaftuar @morcos Thanks for reviewing. Suggested changes incorporated! :-)

Copy link
Contributor

@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove, all callers have cs_main locked, assert lock is held instead. Ping @ryanofsky as he says the goal is to removed recursive locks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@promag Thanks! Now fixed.

Copy link
Contributor Author

@practicalswift practicalswift Nov 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@promag See @TheBlueMatt's comment about cs_main locking in CWallet::CreateTransaction(…): #11596 (comment)

@practicalswift practicalswift force-pushed the chainActive branch 2 times, most recently from 3371efe to 0ada52c Compare November 6, 2017 15:19
@promag
Copy link
Contributor

promag commented Nov 6, 2017

@practicalswift following #11596 (comment), I believe a7eb21a is the fix.

@practicalswift
Copy link
Contributor Author

practicalswift commented Nov 6, 2017

@promag What is the reasoning behind the patch (a7eb21a) – what are the underlying locking requirements (exact variables being guarded)? Your patch is likely correct, but I'm trying to understand exactly why :-)

src/rest.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: care to do the serialization of bitmap/outs outside of cs_main (same below)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@practicalswift practicalswift force-pushed the chainActive branch 2 times, most recently from 17b7775 to cd8ac3c Compare November 6, 2017 20:24
@practicalswift
Copy link
Contributor Author

@TheBlueMatt Thanks for reviewing. Feedback addressed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@practicalswift
Copy link
Contributor Author

Reverting the patch suggested by @promag. The locking is now made down in CreateTransaction as suggested by @TheBlueMatt.

@TheBlueMatt
Copy link
Contributor

TheBlueMatt commented Nov 7, 2017

utACK 2e441c91e7806e6ae781ae0b0aefea958079d15b
Thanks!

src/rest.cpp Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which first lock?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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);

src/rest.cpp Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

src/rest.cpp Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

@practicalswift
Copy link
Contributor Author

practicalswift commented Nov 10, 2017

Added commit 9b3d094894350933342b5e352785cfdd9f2d03fe addressing @luke-jr:s feedback.

Please re-review :-)

@TheBlueMatt
Copy link
Contributor

@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.

Copy link
Member

@luke-jr luke-jr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

luke-jr pushed a commit to bitcoinknots/bitcoin that referenced this pull request Nov 11, 2017
The variable chainActive is guarded by the mutex cs_main.

Github-Pull: bitcoin#11596
Rebased-From: 4786fe1a50c16381d723b5291938a615cc13a490
luke-jr pushed a commit to bitcoinknots/bitcoin that referenced this pull request Nov 11, 2017
…n we identify the chain they're for

Github-Pull: bitcoin#11596
Rebased-From: 9b3d094894350933342b5e352785cfdd9f2d03fe
@practicalswift
Copy link
Contributor Author

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 -Werror=thread-safety-analysis :-)

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.

@practicalswift
Copy link
Contributor Author

practicalswift commented Mar 19, 2018

I've now reworked this PR and split it up in three commits:

  • Add missing LOCK(cs_main):s where required for chainActive access
  • Annotation: Add chainActive GUARDED_BY(cs_main) – does not change run-time behaviour
  • Annotation: Add EXCLUSIVE_LOCKS_REQUIRED(...) as implied by the chainActive guard – does not change run-time behaviour

Please re-review :-)

/cc @sdaftuar @morcos @promag @TheBlueMatt @luke-jr @MarcoFalke

@practicalswift practicalswift changed the title Add missing cs_main locks when accessing chainActive [wip] Add missing cs_main locks when accessing chainActive Mar 19, 2018
@practicalswift
Copy link
Contributor Author

Rebased!

@practicalswift
Copy link
Contributor Author

Rebased!

@practicalswift practicalswift force-pushed the chainActive branch 2 times, most recently from a40b60f to f882f91 Compare April 14, 2018 13:13
@practicalswift
Copy link
Contributor Author

Rebased! Please re-review :-)

Copy link
Contributor

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is somewhat duplicative with #11652, no? My review comments there apply here too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you just take both locks instead of adding a new scope and lots of diff lines? Its in a test, locks shouldn't matter much.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a) annotations need to go in the header file, not the cpp file. b) I dont think we can put locks required in the interfaces file, as it may become a process boundary. The callee will have to take the lock itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

annotations need to go in the header file

This is ok, these are just internal functions (in an anonymous namespace) not shared or exposed in headers.

@practicalswift
Copy link
Contributor Author

Rebased and updated. Please re-review :-)

@practicalswift
Copy link
Contributor Author

Closing. Will add new PR based on #11652 and #13083.

@practicalswift practicalswift deleted the chainActive branch April 10, 2021 19:34
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants