Reading the variable chainActive
requires holding the mutex cs_main
.
Prior to this commit the cs_main
mutex was not held when accessing chainActive
in:
0while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
Reading the variable chainActive
requires holding the mutex cs_main
.
Prior to this commit the cs_main
mutex was not held when accessing chainActive
in:
0while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
483+ bool keepRunning;
484+ {
485+ LOCK(cs_main);
486+ keepRunning = chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning();
487+ }
488+ while (keepRunning)
My suggestion is to create a function like:
0bool KeepRunning() {
1 LOCK(cs_main);
2 assert(chainActive.Tip());
3 return chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning();
4}
And here just:
0while (KeepRunning()) {
1 ...
2}
Reading the variable `chainActive` requires holding the mutex `cs_main`.
Prior to this commit the `cs_main` mutex was not held when accessing
`chainActive` in:
```
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
```
The whole point of csBestBlock was that we shouldn’t need cs_main to simply check the best block. It looks like the logic for that got lost somewhere, and I’m not sure we’re even safe from races anymore. :(
Suggest instead of this, fixing csBestBlock so it is sufficient/works.
@luke-jr Do you mean that fixing this make things worse? If so, please describe why :-)
I’m not familiar with the csBestBlock
issue you are describing, so I’m afraid I’ll have to leave fixing that to someone else :-)
No reason to wait on a “better fix” before merging this. Lets just merge and then @luke-jr can fix it in the way he wants in a cleanup follow-up.
utACK 6e65f35f23337cf0b284acb2bb2ec038ae83aeca
If the scope of this grows beyond this PR’s goal of fixing the missing cs_main
lock I’m afraid I’ll have to leave that for others to fix. Let me know when a fix for the issue described by @luke-jr is available and I’ll close this PR.
If that is something that is unlikely to happen soon I’d vote for merging this fix while waiting for a future better fix.
Ok, since we re-lock cs_main before returning anyway, and since cs_main being locked for any notable period of time after a legitimate cvBlockChange notification would likely indicate a rapid 2nd block anyway, I suppose no regressions would be introduced.
So, -0 to 6e65f35f23337cf0b284acb2bb2ec038ae83aeca. Looks correct to fix the unguarded access.
483+ auto KeepRunning = [&]() -> bool {
484+ LOCK(cs_main);
485+ assert(chainActive.Tip());
486+ return chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning();
487+ };
488+ while (KeepRunning())
Sorry but how about plain code?
0while (IsRPCRunning()) {
1 {
2 LOCK(cs_main);
3 if (chainActive.Tip()->GetBlockHash() != hashWatchedChain) break;
4 }
5 ...
478@@ -479,7 +479,12 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
479 checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
480
481 WaitableLock lock(csBestBlock);
482- while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
483+ auto KeepRunning = [&]() -> bool {
484+ LOCK(cs_main);
485+ assert(chainActive.Tip());