Skip to content
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

test: add tests for non-unilateral DCUtR over TCP #1932

Closed
wants to merge 19 commits into from

Conversation

SgtPooki
Copy link
Member

@SgtPooki SgtPooki commented Aug 3, 2023

  • fix: get DCUtR test passing for TCP

This change builds on top of #1928 and adds a lot more debugging output that is
probably not as necessary for someone more familiar (aka @achingbrain)

@SgtPooki SgtPooki changed the base branch from master to feat/dcutr August 3, 2023 23:43
Copy link
Member Author

@SgtPooki SgtPooki left a comment

Choose a reason for hiding this comment

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

self review and some comments/questions for @achingbrain

Comment on lines 89 to 90
// TODO: Why is this outbound? This is supposed to be A, handling an incoming connection from B
// which means on A, data.connection.direction should be 'inbound'
Copy link
Member Author

Choose a reason for hiding this comment

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

@achingbrain this is confusing. maybe i'm misunderstanding how registrar and topology works. Is this supposed to be handleOutgoingUpgrade ?

Copy link
Member

Choose a reason for hiding this comment

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

When you register a protocol handler with the registrar, it's invoked when a stream for that protocol is opened by the remote peer.

To do it in the other direction you'd call connection.openStream(multicodec) if you already have a connection or libp2p.dialProtocol(peer, multicodec) if you don't.

The actual connection direction isn't taken into account, but in this case the protocol is clear on which end opens the stream.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm still confused why we're calling handleIncomingUpgrade when direction === outbound. that direction implies that the current node is B.. I'm missing something and could probably benefit from a live chat

Copy link
Member

Choose a reason for hiding this comment

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

Why is this outbound? This is supposed to be A, handling an incoming connection from B

The spec says:

B opens a stream to A using the /libp2p/dcutr protocol

So this is A, handling the incoming stream opened by B.

The connection was originally opened in the other direction, from A to B.

The Incoming in handleIncomingUpgrade refers to what's happening in the protocol, not the connection direction.

packages/libp2p/src/dcutr/dcutr.ts Outdated Show resolved Hide resolved
Comment on lines 148 to 157
// Upon observing the new connection, the inbound peer (here B) checks the
// addresses advertised by A via identify.
//
// If that set includes public addresses, then A may be reachable by a direct
// connection, in which case B attempts a unilateral connection upgrade by
// initiating a direct connection to A.
if (await this.attemptUnilateralConnectionUpgrade(relayedConnection)) {
if (await this.attemptUnilateralConnectionUpgrade(connection)) {
debugLog('unilateral connection upgrade succeeded')
return
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved this into the dcutr proto registration's onConnect instead of in the DCUtR process itself, since the spec also breaks this step out as something to be attempted prior to DCUtR instead of as a part of the DCUtR process.

Copy link
Member

Choose a reason for hiding this comment

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

The onConnectAttempt function is bound to this and set as the onConnect topology callback - it's an async function but onConnect's signature is sync.

This is flagged by the linter.

Comment on lines +24 to +25
const logA = logger('libp2p:dcutr:A')
const logB = logger('libp2p:dcutr:B')
Copy link
Member Author

Choose a reason for hiding this comment

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

I found these to be much more helpful in debugging than prefixing with "A this" "B that" because we know who the one in control of operations is when we logA or logB, no matter what we put in the message.


const log = logger('libp2p:dcutr')
const logA = logger('libp2p:dcutr:A')
const logB = logger('libp2p:dcutr:B')
const debugLog = logger('libp2p:dcutr:debug')
Copy link
Member Author

Choose a reason for hiding this comment

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

why doesn't libp2p/logger let us call .extend() to add debug...? log{A,B}.debug would be much more useful

Copy link
Member

@achingbrain achingbrain Aug 4, 2023

Choose a reason for hiding this comment

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

Usually you use .trace for debug-level logging.

Please can you replace all instances of debugLog with debug.trace and log happy-path messages with .trace, errors with .error and anything notable with debug().

To see the trace-level logging you have to turn it on explicitly with DEBUG=*:trace.

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe this is done but let me know if I misused the logs

Copy link
Member Author

Choose a reason for hiding this comment

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

Comment on lines 258 to 261
await relayedConnection.close(options)
logB('closed relayed connection')
// stop the for loop.
break;
Copy link
Member Author

Choose a reason for hiding this comment

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

If the connection here is successful, there is no further need to retry, so we need to break out of the loop.

packages/libp2p/src/dcutr/dcutr.ts Show resolved Hide resolved
packages/libp2p/src/dcutr/dcutr.ts Outdated Show resolved Hide resolved
packages/libp2p/test/dcutr/dcutr.node.ts Outdated Show resolved Hide resolved
packages/libp2p/test/dcutr/dcutr.node.ts Outdated Show resolved Hide resolved
@SgtPooki SgtPooki requested a review from achingbrain August 4, 2023 00:26
@SgtPooki
Copy link
Member Author

SgtPooki commented Aug 4, 2023

two other things:

  1. I can't seem to run lint locally because node is out of memory. will try a restart
  2. We should add a test that emulates the gateway -> browser node scenario, but I can't think of a way to do that.

Based on ipfs/helia#182 (comment), it seems like we could just enable/disable some transports on each node to get the effect we want, but I don't believe the third item in that comment is accurate

the gateway does not need to be able to dial the browser (e.g. WebRTC)

In the spec, and in this code, both of the following are true (B=browser, A=gateway):

  1. A tells B the multiaddrs it's available at, and B attempts to dial them
  2. B tells A the multiaddrs it's available at, and A attempts to dial them

@achingbrain achingbrain changed the title fix: non-unilateral tests DCUtR for TCP pass test: add tests for non-unilateral DCUtR over TCP Aug 4, 2023
@achingbrain
Copy link
Member

I don't believe the third item in that comment is accurate

the gateway does not need to be able to dial the browser (e.g. WebRTC)

In the spec, and in this code, both of the following are true (B=browser, A=gateway):

  1. A tells B the multiaddrs it's available at, and B attempts to dial them
  2. B tells A the multiaddrs it's available at, and A attempts to dial them

The scenario is:

  1. Browser (B) has a relay address
  2. B adds a block to itself, gets a CID, publishes a provider record containing the relay address
  3. Gateway (A) looks up the provider record, dials B over the relay address
  4. Identify happens
  5. B's onConnect handler is notified that A supports DCUtR
  6. B attempts to unilaterally upgrade the incoming connection
  7. B checks the reported addresses of A, notices it listens on a public wss address (cos it's the gateway) and dials the wss address
  8. B closes the relayed connection to A
  9. Identify happens on the non-relayed connection
  10. Bitswap is reported as supported
  11. Bitswap happens and the block is sent from the browser to the gateway
  12. ???
  13. Profit

@SgtPooki

This comment was marked as outdated.

SgtPooki added a commit to SgtPooki/helia-playground that referenced this pull request Aug 10, 2023
Base automatically changed from feat/dcutr to master August 16, 2023 06:52
@achingbrain achingbrain force-pushed the main branch 29 times, most recently from 242fd96 to bca8d6e Compare November 30, 2023 21:12
@SgtPooki SgtPooki closed this Mar 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants