net_processing: make m_tx_for_private_broadcast optional#34271
net_processing: make m_tx_for_private_broadcast optional#34271vasild wants to merge 1 commit intobitcoin:masterfrom
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/34271. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please copy-paste 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. |
src/net_processing.cpp
Outdated
|
|
||
| if (pfrom.IsPrivateBroadcastConn()) { | ||
| const auto pushed_tx_opt{m_tx_for_private_broadcast.GetTxForNode(pfrom.GetId())}; | ||
| if (pfrom.IsPrivateBroadcastConn() && m_tx_for_private_broadcast.has_value()) { |
There was a problem hiding this comment.
This change creates a situation that should be impossible: to have a private broadcast connection existent and have the optional m_tx_for_private_broadcast empty. Anyway it has to be handled somehow in the code and I think that maybe an assert() or Assume() is too strong? So here it would behave as if it is not a private broadcast connection. Maybe this is not the correct behavior?
I am ~0 on making m_tx_for_private_broadcast optional. In other words, it has some pros and some cons, I am fine either way.
There was a problem hiding this comment.
That can happen if InitiateTxBroadcastPrivate() was not called before. That could happen even without this change, and the behavior is very similar: m_tx_for_private_broadcast was initialized with an 'empty' PrivateBroadcast, so the PickTxForSend(), GetStale(), etc. methods would return nothing. However, the difference is that in that case LogDebug's are emitted. An assert might be too strong, as there is no guarantee that InitiateTxBroadcastPrivate() is called upfront, but the LogDebug messages should be emitted the same way if m_tx_for_private_broadcast none, or it is set but does not contain the expected transaction.
Another way would be to lazily init m_tx_for_private_broadcast before every access, but that may be an overkill.
There was a problem hiding this comment.
That can happen if
InitiateTxBroadcastPrivate()was not called before.
Ok, but how could pfrom.IsPrivateBroadcastConn() be true if InitiateTxBroadcastPrivate() was not called before?
There was a problem hiding this comment.
I can't answer that, maybe it can't, but there is no straightforward guarantee in the code; one is a check in CNode, one is a call in PeerManagerImpl. Regardless whether it is possible (now) or not, I'm saying that the behavior regarding logging should be the same after this change than before (even if it is there is no way to get that combination today, there may be some (incorrect) change in the future, so keeping the log is a good idea).
There was a problem hiding this comment.
Yeah, I changed it to disconnect the peer if that ever happens in the future.
src/net_processing.cpp
Outdated
|
|
||
| if (pfrom.IsPrivateBroadcastConn()) { | ||
| const auto pushed_tx_opt{m_tx_for_private_broadcast.GetTxForNode(pfrom.GetId())}; | ||
| if (pfrom.IsPrivateBroadcastConn() && m_tx_for_private_broadcast.has_value()) { |
There was a problem hiding this comment.
How about this approach to have the same LogDebug for the case when m_tx_for_private_broadcast is unset and there is not TX?
if (pfrom.IsPrivateBroadcastConn()) {
const auto pushed_tx_opt{!m_tx_for_private_broadcast.has_value() ? std::nullopt : m_tx_for_private_broadcast->GetTxForNode(pfrom.GetId())};
if (!pushed_tx_opt) {
LogInfo( ...
...
}
...
}
There was a problem hiding this comment.
Added some logs and disconnect the peer that has IsPrivateBroadcastConn() true.
|
ConceptACK |
340d10d to
c218ad8
Compare
|
|
polespinasa
left a comment
There was a problem hiding this comment.
Concept ACK
I don't understand why we check if m_tx_for_private_broadcast has value inside functions that imply that we are in private broadcast mode.
| stale_tx->GetHash().ToString(), stale_tx->GetWitnessHash().ToString(), | ||
| mempool_acceptable.m_state.ToString()); | ||
| m_tx_for_private_broadcast.Remove(stale_tx); | ||
| if (m_tx_for_private_broadcast.has_value()) { |
There was a problem hiding this comment.
is this check here necessary? ReattemptPrivateBroadcast is only called in StartScheduledTasks where it is only called if private broadcast option is enabled.
I mean if I understood correctly we should never get into this function if private broadcast mode is not set.
There was a problem hiding this comment.
Same answer to the question in the main-thread: #34271 (review) and the question from #34271 (comment)
If we don't check whether the optional has value and try to access it and it does not have a value then the program will crash (it is undefined behavior). While this shouldn't be possible in the current code nothing guarantees that future changes will keep it that way. It is not immediately obvious by reading the surrounding code. So, to be more robust, it is better to have some handling of it.
This is the downside of this change any why I am ~0 about it - it adds visual clutter and unreachable code.
| if (node.IsPrivateBroadcastConn() && | ||
| !m_tx_for_private_broadcast.DidNodeConfirmReception(nodeid) && | ||
| m_tx_for_private_broadcast.HavePendingTransactions()) { | ||
| m_tx_for_private_broadcast.has_value() && |
There was a problem hiding this comment.
Is there a case where we can have node.IsPrivateBroadcastConn() = true and m_tx_for_private_broadcast.has_value() = false? If that's the case maybe we want to close that connection as you did in PushPrivateBroadcastTx or ProcessMessage? (c218ad8#diff-6875de769e90cec84d2e8a9c1b962cdbcda44d870d42e4215827e599e11e90e3R3542)
Edit: I see that this was already discussed here #34271 (comment) maybe want to do the same?
(I'm not really familiar with the net processing code maybe I am missing something :) )
There was a problem hiding this comment.
Is there a case where we can have
node.IsPrivateBroadcastConn() = trueandm_tx_for_private_broadcast.has_value() = false
Currently "no", but it is not immediately obvious and not guaranteed to remain like this after future changes.
This code here is during the connection tear down. It is being disconnected anyway already.
c218ad8 to
e1600e0
Compare
|
|
Make `PeerManagerImpl::m_tx_for_private_broadcast` optional because it is needed for in private broadcast mode (`-privatebroadcast=1`). Requested in: bitcoin#29415 (comment) https://github.com/bitcoin/bitcoin/pull/29415/files#r2620864832
e1600e0 to
41f0bc0
Compare
|
|
|
🐙 This pull request conflicts with the target branch and needs rebase. |
Make
PeerManagerImpl::m_tx_for_private_broadcastoptional because it is needed for in private broadcast mode (-privatebroadcast=1).A followup to #29415, requested in:
#29415 (comment)
https://github.com/bitcoin/bitcoin/pull/29415/files#r2620864832