Conversation
2fbed48 to
20c4769
Compare
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. 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. Coverage
Updated at: 2022-05-10T14:16:22.523123. |
6c2b134 to
90cd7a9
Compare
90cd7a9 to
c866831
Compare
ariard
left a comment
There was a problem hiding this comment.
Reviewed until 85992f3. So far only minor comments.
c866831 to
5ba375e
Compare
ariard
left a comment
There was a problem hiding this comment.
Finished a first parse, including verifying unit test coverage of the new TxReconciliationTracker class. LGTM
|
5ba375e to
6a79aae
Compare
|
|
cdaabda to
ea3b87a
Compare
mzumsande
left a comment
There was a problem hiding this comment.
Did you think about a -disablerecon command or something similar, to not activate Erlay until all the parts have been merged?
Providing the opportunity to opt in/out would probably make sense anyway, but it would also make the review process of its parts independent from releases - e.g. I also don't think it makes sense to have nodes running master exchange SENDRECON before Erlay has been fully merged.
Yeah I was also thinking about how it's weird to send SENDRECON messages while they don't mean anything, but couldn't come up with any good solution. I guess a flag is better if someone wants to test this stuff via functional tests (without modifying the source code), so yeah, that's probably an ultimate solution. I'll add a commit for that. |
glozow
left a comment
There was a problem hiding this comment.
Concept ACK, thanks for splitting it up. I did a first pass, mostly comparing to the BIP330 specification, looking at test coverage, and a little bit of implementation.
|
utACK ea3b87a Code review, everything looks good to me outside nits raised by others. Will run the fuzzer for some cycles, and report back results. |
There was a problem hiding this comment.
Approach ACK, code review until 103e52d - didn't look at tests yet.
This PR introduces the logic to register newly connected peers as peers that support transaction reconciliation, and initialize the necessary data structures required to do the reconciliation later on.
I think everything is well laid out and implemented, so most of my comments are quite nitty and focus on readability etc. They're subjective, feel free to ignore.
Some general thoughts/suggestions:
- "SENDRECON" does not hint that it corresponds to transactions, would it make sense to rename this to "SENDTXRECON" so people can quickly understand what it's about without know the Erlay code?
- I understand you're renaming the two roles to "initiator" & "responder", there are still quite a few instances of "requestor", "sender", "receiver" throughout the code and in BIP300. Would suggest to replace them all in both documentation and variable names, consistent naming makes it much easier to follow.
jnewbery
left a comment
There was a problem hiding this comment.
Did you think about a -disablerecon command or something similar, to not activate Erlay until all the parts have been merged?
I agree that this should be added, although to bikeshed I'd call it -erlay and default to false.
5136f50 to
07b9357
Compare
|
Still going through comments, beware it's not the final shape from my side. |
| argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ||
| argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ||
| argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ||
| argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); |
There was a problem hiding this comment.
nit: "per BIP 330" looks too opaque for this help text, it is too long and technical to read the BIP itself in order to understand what this option is about.
| argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); | |
| argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations for more efficient transaction propagation (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); |
There are other BIP xyz mentions in the help texts, feel free to ignore.
|
|
||
| // We do this exactly once per peer (which are unique by NodeId, see GetNewNodeId) so it's | ||
| // safe to assume we don't have this record yet. | ||
| Assert(m_states.emplace(peer_id, local_salt).second); |
There was a problem hiding this comment.
You can remove this assert() from above:
assert(m_states.find(peer_id) == m_states.end());
They both check for the same thing. That way we will do one lookup instead of two, maybe insignificant wrt performance but will be less code.
PS why use assert() in one place and Assert() in another? Did you intend to use Assume()?
| class TxReconciliationTracker::Impl | ||
| { | ||
| private: | ||
| mutable Mutex m_txreconciliation_mutex; |
There was a problem hiding this comment.
nit: "txreconciliation" is already in the name of the class TxReconciliationTracker. This can be just m_mutex.
For example, another member is called m_states, not m_txreconciliation_states.
There was a problem hiding this comment.
This was the initial version, but then @jonatack asked for the more verbose name, and I didn't care much... Maybe he has to say something.
There was a problem hiding this comment.
The rationale is that m_txreconciliation_mutex returns more useful results than m_mutex when git grepping the codebase, and the more specific mutex naming seems to be a convention in the codebase as much as the generic naming.
| return; | ||
| } | ||
|
|
||
| if (!peer->GetTxRelay()) { |
There was a problem hiding this comment.
Yeah, the code and the comments disagree:
if (!peer->GetTxRelay()) {
// Disconnect peers that send a SENDTXRCNCL message even though we indicated we don't
// support transaction relay.We set txrelay (thus GetTxRelay() will be true) on this condition:
!pfrom.IsBlockOnlyConn() && (fRelay || (peer->m_our_services & NODE_BLOOM)) // fRelay comes from the peerbut we indicate transaction relay support on this condition:
!m_ignore_incoming_txs && !pnode.IsBlockOnlyConn() && !pnode.IsFeelerConn();They are not the same.
| if (recon_state == m_states.end()) return NOT_FOUND; | ||
| uint64_t* local_salt = std::get_if<uint64_t>(&recon_state->second); | ||
| // A peer is already registered. This should be checked by the caller. | ||
| Assume(local_salt); |
There was a problem hiding this comment.
This should be assert() since we dereference local_salt below. It will crash anyway if it is nullptr. Better crash with a meaningful message produced by the assert().
|
|
||
| BOOST_AUTO_TEST_CASE(RegisterPeerTest) | ||
| { | ||
| TxReconciliationTracker tracker(1); |
There was a problem hiding this comment.
Use TXRECONCILIATION_VERSION instead of 1?
| tracker.PreRegisterPeer(0); | ||
|
|
||
| // Both roles are false, don't register. | ||
| BOOST_CHECK(tracker.RegisterPeer(/*peer_id=*/0, /*is_peer_inbound=*/true, |
There was a problem hiding this comment.
Here and elsewhere, BOOST_CHECK_EQUAL(x, y) is preferred over BOOST_CHECK(x == y) because the former gives a better message should the check fail.
|
In the OP:
|
If we're connecting to the peer which might support transaction reconciliation, we announce we want to reconcile with them. We store the reconciliation salt so that when the peer responds with their salt, we are able to compute the full reconciliation salt. This behavior is enabled with a CLI flag.
Once we received a reconciliation announcement support message from a peer and it doesn't violate our protocol, we store the negotiated parameters which will be used for future reconciliations.
We optimistically pre-register a peer for txreconciliations upon sending txreconciliation support announcement. But if, at VERACK, we realize that the peer never sent WTXIDRELAY message, we should unregister the peer from txreconciliations, because txreconciliations rely on wtxids.
|
Looks like rebased for #25667. |
|
The newly added test |
|
re-ACK e56d1d2 |
Job: https://cirrus-ci.com/task/6088863331385344 |
|
The reason was likely
https://cirrus-ci.com/task/6088863331385344?logs=functional_tests#L605 However, I can't see how this could possibly happen in the framework. (peer8 is a python node) |
|
re-ACK e56d1d2 |
|
Thank you all for making this happen! I will create a PR for fixups, and finish the second PR shortly. |
|
Post-Merge ACK e91690e |
| // - we intended to exchange transactions over this connection while establishing it | ||
| // and the peer indicated support for transaction relay in the VERSION message; | ||
| // - we are not in -blocksonly mode. | ||
| if (pfrom.m_relays_txs && !m_ignore_incoming_txs) { |
There was a problem hiding this comment.
Is this going to send SENDTXRCNCL to feeler connections?
| argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ||
| argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ||
| argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ||
| argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); |
There was a problem hiding this comment.
Probably unrelated, but it might be good to split the connection section into net and net_processing options. (This one would go into net_processing)
This is a part of the Erlay project:
This PR adds a new p2p message
sendtxrcnclsignaling for reconciliation support.Before sending that message, a node is supposed to "pre-register" the peer by generating and storing an associated reconciliation salt component.
Once the salts are exchanged within this new message, nodes "register" each other for future reconciliations by computing and storing the aggregate salt, along with the reconciliation parameters based on the connection direction.