-
Notifications
You must be signed in to change notification settings - Fork 37.8k
[RFC] I Have a Hammer! (Replace parts of ui_interface with validationinterface) #11856
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] I Have a Hammer! (Replace parts of ui_interface with validationinterface) #11856
Conversation
4afd218
to
93264c3
Compare
src/rpc/server.h
Outdated
@@ -25,6 +27,45 @@ namespace RPCServer | |||
{ | |||
void OnStarted(std::function<void ()> slot); | |||
void OnStopped(std::function<void ()> slot); | |||
|
|||
struct InterruptedListenerInternals; | |||
/** A scoped listener for when RPC is itnerrupted (ie IsRPCRunning moves |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
itnerrupted
2f0eb46
to
9ebcabf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally like the changes.
src/rpc/mining.cpp
Outdated
RPCServer::BlockChangeBlocker block_waiter; | ||
{ | ||
WaitableLock lock(block_waiter.m_cs); | ||
block_waiter.m_last_block_hash = hashWatchedChain; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this necessary if m_last_block_hash
in block_waiter is initialized to the chain tip? Seems like it would block longer than necessary below if lpval
has an old block hash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hashWatchedChain could be set a few lines up by lpstr instead of by chainActive.Tip().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I see that, but it looks like the old behavior would have been to return immediately if the longpollid was out of date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, but without setting m_last_block_hash to hashWatchedChain we would instead still wait until chainActive.Tip() advances?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would never even enter the while (block_waiter.m_last_block_hash == hashWatchedChain && ...)
loop, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohoh, yea, I think I had changed the loop condition since a previous iteration. Fixed.
src/init.cpp
Outdated
@@ -1633,7 +1635,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) | |||
while (!fHaveGenesis) { | |||
condvar_GenesisWait.wait(lock); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe worth changing to condvar_GenesisWait.wait(lock, []{ return fHaveGenesis; });
and dropping the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/init.cpp
Outdated
@@ -536,22 +536,24 @@ class BlockNotifyCaller : public CValidationInterface { | |||
} | |||
} | |||
} g_blocknotify_caller; | |||
} // anonymous namespace | |||
|
|||
static bool fHaveGenesis = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather see more of these globals encapsulated in the GenesisWaiter. AppInitMain
could be simplified if GenesisWaiter
just had a method like BlockUntilHaveGenesis
or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
e36037f
to
5f99bf4
Compare
src/rpc/blockchain.cpp
Outdated
} | ||
cond_blockchange.notify_all(); | ||
template<typename T> | ||
static UniValue AwaitBlockChangeCondition(int timeout, const T& term_condition) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: "break before braces on function, namespace and class definitions"
https://github.com/bitcoin/bitcoin/blob/master/src/.clang-format#L15
http://clang.llvm.org/docs/ClangFormatStyleOptions.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed (for at least not-two-line-functions).
Also push down cs_main locking in getblocktemplate a bit.
5f99bf4
to
17e931d
Compare
Adding overhead sounds bad. Can you quantify this somehow? Note that none of the GUI notifications take significant time. They already just queue a signal to Qt, to be handled later. Adding another layer sounds somewhat bad. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Started review (about halfway through).
* Is called after a series of BlockConnected/BlockDisconnected events once | ||
* the chain has made forward progress and is now at the best-known-tip. | ||
* | ||
* If a block is found to be invalid, this event may trigger without |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Clarify validationinterface notification ordering"
All of the other comments in this commit are very good, but for some reason I'm finding this sentence really confusing. I think this is saying that UpdateBlockTip might be called repeatedly with the same pindexNew value in cases where invalid blocks are being received. But the current wording seems to imply that this might actually pass an invalid block pointer, which I don't think is the case (unless invalidateblock is called?). And "without forward progress" seems to imply that pindexNew might go backwards? I think it'd be helpful to replace this sentence with a list of some specific invariants the notification (1) does guarantee (2) doesn't guarantee, or (3) aspires to guarantee (in case of the TODO) instead of being so vague.
src/validation.cpp
Outdated
@@ -2717,6 +2717,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c | |||
|
|||
InvalidChainFound(pindex); | |||
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); | |||
GetMainSignals().UpdatedBlockTip(chainActive.Tip(), chainActive.Tip(), IsInitialBlockDownload()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Also call UpdatedBlockTip on invalidateblock"
This seems like a good change, but was it just a bug that that this call wasn't being made before? Or is this preparation for some new feature? Should this have a test? Should it have a mention in release notes if it affects RPC or ZMQ? It's good when commits like this have some test or documentation update, or a sentence in the commit message that sheds light on what the motivation for the change is.
src/init.cpp
Outdated
@@ -721,7 +715,6 @@ bool InitSanityCheck(void) | |||
|
|||
bool AppInitServers(boost::thread_group& threadGroup) | |||
{ | |||
RPCServer::OnStopped(&OnRPCStopped); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Replace csBestBlock/cvBlockChanged with validationinterface"
Maybe remove the OnStopped function and stopped signal as they no longer have any listeners.
WaitableLock lock(csBestBlock); | ||
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) | ||
WaitableLock lock(block_waiter.m_cs); | ||
while (block_waiter.m_last_block_hash == hashWatchedChain && IsRPCRunning()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Replace csBestBlock/cvBlockChanged with validationinterface "
IsRPCRunning does not appear to be thread safe. Maybe fRPCRunning be a changed to an atomic bool.
@@ -447,6 +447,19 @@ UniValue getblocktemplate(const JSONRPCRequest& request) | |||
if (IsInitialBlockDownload()) | |||
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks..."); | |||
|
|||
if (!lpval.isNull()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Replace csBestBlock/cvBlockChanged with validationinterface"
Is the !
here a mistake? I could see how the RPC call might return too early if lpval is null, but if it's non-null and actually set to a hash, it seems like this would only lead to unnecessary delays.
{ | ||
{ | ||
LOCK(cs_main); | ||
m_last_block_hash = chainActive.Tip()->GetBlockHash(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Add RPC utility to block until tip changes or RPC is interrupted"
Do you need to acquire m_cs while updating m_last_block variables here? It doesn't seem like there is a guard against these writes being delayed and UpdatedBlockTip trying to update the values at the same time. Or if this is safe, should add a comment here saying why m_cs isn't needed.
This needs rebase, but probably shouldn't be updated until #12979 gets merged (with which this PR shares a commit) |
Look at my pretty harrmer, watch as I make everything into a nail!
This de-duplicates the NotifyBlockTip/BlockTipChanged callbacks by removing the NotifyBlockTip callback from ui_interface, cleaning up a few things along the way. It does, however, add a good bit of overhead where there was previously none - instead of a simple boost::signal things are now being called on the scheduler background thread. Still, I think its worth it because a) background-threading this stuff makes us less vulnerable to latency spikes in different subsystems because some other subsystem takes forever (at least once validationitnerface is parallel across different clients) and b) avoids lockorder issues creeping in due to cs_main complexity.