Introduce waitTipChanged() mining interface, replace RPCNotifyBlockChange, drop CRPCSignals & g_best_block#30409
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
7caba51 to
b442f37
Compare
b442f37 to
4a2296f
Compare
|
Some of the functional tests that use the refactored RPC calls still fail under TSAN, so keeping this draft until that's resolved. |
4a2296f to
0fd7f52
Compare
|
Fixed the deadlock. I ran into the same issue before when working on #29432: That's not a problem here; I just had to break out of the while loop instead of returning from it. Back in the other PR this led to a deadlock if we simultaneously submitted a block and received it via p2p from the pool, which can happen in Stratum v2, see #29432 (comment) |
0fd7f52 to
377c4b5
Compare
Add interface changes from bitcoin#30409 bitcoin#30356 bitcoin#30440 bitcoin#30443
Add interface changes from bitcoin#30409 bitcoin#30356 bitcoin#30440 bitcoin#30443
Add interface changes from bitcoin#30409 bitcoin#30356 bitcoin#30440 bitcoin#30443
Add interface changes from bitcoin#30409 bitcoin#30356 bitcoin#30440 bitcoin#30443 This commit changes the C++ Mining interface without changing the corresponding Capn'Proto interface. The capnp interface is updated the next commit.
Add interface changes from bitcoin#30409 bitcoin#30356 bitcoin#30440 bitcoin#30443 This commit updates the Cap'n Proto Mining interface after updating the C++ Mining interface last commit.
966027b to
76ec301
Compare
|
Trivial |
ryanofsky
left a comment
There was a problem hiding this comment.
Code review ACK 76ec301c60e2530de7f58e2e4cea3d15c6a77cbc. Just simple rebase since last review
Also signal m_tip_block_cv when StopRPC is called, for consistency with g_best_block_cv. This is handled in StopRPC instead of OnRPCStopped() because the latter is deleted in a later commit. Co-authored-by: TheCharlatan <seb.kung@gmail.com> Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
Co-authored-by: TheCharlatan <seb.kung@gmail.com>
The waitforblock RPC method takes a hash argument and waits for that specific block. The waitfornewblock waits for any new block. This commit fixes the documentation.
This refactoring commit uses the newly introduced waitTipChanged mining interface method to replace the RPCNotifyBlockChange mechanism.
They are no longer used for anything since RPCNotifyBlockChange was replaced with waitTipChanged() from the mining interface.
This removes the last remaining use of g_best_block by the RPC.
|
Rebased after #30440. Just some |
|
ACK 7942951 |
maflcko
left a comment
There was a problem hiding this comment.
review ACK 7942951 🛋
Show signature
Signature:
untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: review ACK 7942951e3fcc58f7db0059546d03be9ea243f1db 🛋
KRzS4gS3SXCvu+SqXrmOlO59h7EfpDm03wNYXbXyxcUpf1uSvRs0Wxsdg7n96gG9dwQPet+ZPAL6FR2cNKqBCw==
| WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear()); | ||
| DeleteAuthCookie(); | ||
| g_rpcSignals.Stopped(); | ||
| node::NodeContext& node = EnsureAnyNodeContext(context); |
There was a problem hiding this comment.
nit in 7eccdaf: Any reason to use the throwing function? The internal error isn't caught anywhere, IIUC. So, the program will terminate either way. By using *Assert(AnyPtr(context)) here instead, at least a usable error message is printed.
There was a problem hiding this comment.
I probably just copied similar code from another place :-)
Can make a followup, though *Assert(AnyPtr(context)) looks pretty scary.
There was a problem hiding this comment.
You probably copied it from an RPC method implementation. There, it would be the right choice, because the http threads catch exceptions and then continue with the next RPC call.
However, here no exceptions are caught (and doing so wouldn't make sense, probably). The program will terminate either way, for example:
2024-09-24T10:38:06Z opencon thread exit
terminate called after throwing an instance of 'UniValue'
Aborted (core dumped)
However, by using Assert/assert, at least a source location is printed. If you don't like the assert, you can also use an if guard against a nullptr, but I am not sure if that is cleaner.
In any case, this is just a style nit.
| // std::chrono does not check against overflow | ||
| if (deadline < now) deadline = std::chrono::steady_clock::time_point::max(); |
There was a problem hiding this comment.
b94b27c: Can you explain the meaning of "overflow" in the context of double?
To clarify: Signed interger overflow is UB, so it can't happen. And overflow for double can't happen either, so this is dead code either way, unless I am missing something.
There was a problem hiding this comment.
It was in response to: #30409 (comment) where @ryanofsky wrote:
I'm also concerned about the
deadline = now() + timeoutassignment above because it seems like that will be an overflowed value when timeout isMillisecondsDouble::max()so the while loop condition might be invalid.
There was a problem hiding this comment.
Nice catch. I believe this can be simplified to:
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -941,9 +941,7 @@ public:
// Interrupt check interval
const MillisecondsDouble tick{1000};
auto now{std::chrono::steady_clock::now()};
- auto deadline = now + timeout;
- // std::chrono does not check against overflow
- if (deadline < now) deadline = std::chrono::steady_clock::time_point::max();
+ const auto deadline{now + timeout};
{
WAIT_LOCK(notifications().m_tip_block_mutex, lock);
while ((notifications().m_tip_block == uint256() || notifications().m_tip_block == current_tip) && !chainman().m_interrupt) {This previous code written to handle the case where now + timeout calculation would overflow, basically assuming both values were unsigned integer values and overflow behavior would be well defined. But since timeout is a floating point number where "overflow" would just result in inf being set, trying to deal with it this way doesn't make sense.
| Mutex m_tip_block_mutex; | ||
| std::condition_variable m_tip_block_cv; | ||
| //! The block for which the last blockTip notification was received for. | ||
| uint256 m_tip_block; |
There was a problem hiding this comment.
This needs a GUARDED_BY(m_tip_block_mutex).
Adding it causes new warnings in validation_chainstate_tests.cpp. For ex:
src/test/validation_chainstate_tests.cpp:73:46: warning: reading variable 'm_tip_block' requires holding mutex 'm_node.notifications->m_tip_block_mutex' [-Wthread-safety-analysis]
I assume those particular accesses are harmless (maybe actually racy in the right conditions?), but future users may not be.
Related: It's a shame that the condvar/mutex leak out of here. Is there a reason not to add getter/waiter/notifier functions?
|
I'll work on a followup for the above things. |
Already started working on this, because I needed it for other stuff. Happy to drop mine, if you are done already. |
This continues the work in #30200 so that a future Stratum v2 Template Provider (see #29432) can avoid accessing node internals. It needs to know when a new block arrives in order to push new templates to connected clients.
waitTipChanged()uses a new kernel notificationnotifications().m_tip_block_mutex, which this PR also introduces (a previous version usedg_best_block).In order to ensure the new method works as intended, the
waitfornewblock,waitforblockandwaitforblockheightRPC methods are refactored to use it. This allows removingRPCNotifyBlockChange.There's a commit to add (direct) tests for the methods that are about to be refactored:
waitfornewblockwas already implicitly tested byfeature_shutdown.py.waitforblockheightbyfeature_coinstatsindex.pyandexample_test.pyThis PR renames
getTipHash()togetTip()and returns aBlockRef(renamed fromBlockKey) so that callers can use either the height or hash.The later commits make trivial improvements to the
waitfor*RPC calls (not needed for this PR).The
waitTipChanged()method could probably also be used for the longpoll functionality ingetblocktemplate, but I'm a bit reluctant to touch that.RPCServer::OnStartedno longer does anything andRPCServer::OnStoppedmerely prints a log statement. They were added in #5711 as a refactor. This PR drops them entirely.Finally
g_best_blockis also dropped.