Skip to content

Conversation

TheBlueMatt
Copy link
Contributor

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.

@TheBlueMatt TheBlueMatt force-pushed the 2017-12-remove-cvblockchange branch 2 times, most recently from 4afd218 to 93264c3 Compare December 8, 2017 20:53
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
Copy link
Contributor

Choose a reason for hiding this comment

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

itnerrupted

@TheBlueMatt TheBlueMatt force-pushed the 2017-12-remove-cvblockchange branch 3 times, most recently from 2f0eb46 to 9ebcabf Compare December 9, 2017 19:27
Copy link
Contributor

@jimpo jimpo left a 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.

RPCServer::BlockChangeBlocker block_waiter;
{
WaitableLock lock(block_waiter.m_cs);
block_waiter.m_last_block_hash = hashWatchedChain;
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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;
Copy link
Contributor

@jimpo jimpo Dec 12, 2017

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@TheBlueMatt TheBlueMatt force-pushed the 2017-12-remove-cvblockchange branch 2 times, most recently from e36037f to 5f99bf4 Compare December 12, 2017 21:39
}
cond_blockchange.notify_all();
template<typename T>
static UniValue AwaitBlockChangeCondition(int timeout, const T& term_condition) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

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

@TheBlueMatt TheBlueMatt force-pushed the 2017-12-remove-cvblockchange branch from 5f99bf4 to 17e931d Compare December 15, 2017 23:25
@laanwj
Copy link
Member

laanwj commented Dec 21, 2017

It does, however, add a good bit of overhead where there was previously none

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.

Copy link
Contributor

@ryanofsky ryanofsky left a 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
Copy link
Contributor

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.

@@ -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());
Copy link
Contributor

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);
Copy link
Contributor

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())
Copy link
Contributor

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()) {
Copy link
Contributor

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();
Copy link
Contributor

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.

@ryanofsky
Copy link
Contributor

Note: The first commit in this PR ("Clarify validationinterface notification ordering") also appears in #11775 and #12979, but I think the other the commits are unique.

@jnewbery
Copy link
Contributor

This needs rebase, but probably shouldn't be updated until #12979 gets merged (with which this PR shares a commit)

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
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