Replies: 3 comments
-
|
I just submitted libp2p/unified-testing#48 with correct relay and peer code. I kept it as minimal and straightforward as possible. The dcutr example in this repo works because it does nothing other than to log the behaviour events that, if handled incorrectly, can mess up the dcutr state. |
Beta Was this translation helpful? Give feedback.
-
|
Hey @dhuseby. Looking at the relay code, I dont see anywhere where it is adding the address as an external address as it is done in the relay example, pretty much letting the local node what address is reachable. EDIT: Just saw part of the post about EDIT2: To add another comment, if you are listening on the address directly or using |
Beta Was this translation helpful? Give feedback.
-
|
@dariusc93 this is the networking setup that the hole-punch test uses:
The point of the original post was to point out that calling |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm writing this as a public service announcement. I don't think there is a bug here otherwise I would have filed an issue, but I do want to call this out so others can learn from my digging.
I've been trying to get the hole-punch test working in the new unified-testing framework. I wrote a rust-v0.56 relay and a rust-v0.56 peer that acts as both dialer and listener. The test framework uses Docker to set up three networks and five containers and a separate network with a redis server in it for OOB coordination and testing purposes. The relay is in one network, a peer instance in dialer mode is another and a peer instance in listener mode is in the last. Then there are two linux containers set up with NAT/firewall and two network interfaces, one interface on the relay's network and one interface on the dialer/listener networks. The code for these is here.
I just couldn't get the thing to work. I kept getting a DCUtR failure in the dialer (
InboundError(Protocol(NoAddress))) and another in the listener (OutboundError(Io(Kind(UnexpectedEof)))).After doing some deep root cause analysis, I discovered the listener's DCUtR CONNECT message contains zero addresses because DCUtR never receives the listener's external address. The cause is a subtle interaction between
swarm.add_external_address()and identify's event ordering:GenerateEvent(Received)first, thenNewExternalAddrCandidatelast.Identify::Receivedhandler calledswarm.add_external_address(observed_addr). This inserts the address into the swarm'sconfirmed_external_addrset and emitsFromSwarm::ExternalAddrConfirmed.ToSwarm::NewExternalAddrCandidatearrives next, the swarm checks if!self.confirmed_external_addr.contains(&addr)-- since we already confirmed it, both theFromSwarm::NewExternalAddrCandidatebroadcast to behaviours AND theSwarmEvent::NewExternalAddrCandidateemission are skipped.FromSwarm::NewExternalAddrCandidateinon_swarm_event(ignoresExternalAddrConfirmed). Since the broadcast was suppressed, DCUtR'saddress_candidatesremains empty which leads to the empty CONNECT andNoAddresseserror.What is the correct way to do DCUtR?
The short answer is never call
swarm.add_external_address(address.clone())in theswarm::SwarmEvent::NewExternalAddrCandidate { address }arm. You should also never callswarm.add_external_address(observed_addr.clone())in theswarm::SwarmEvent::Behaviour(BehaviourEvent::Identify(identify::Event::Received { info: identify::Info { observed_addr, ..}, .. }))arm. I think you should just never callswarm.add_external_address. Because without letting theFromSwarmevent to propagate, there's no way for DCUtR to get the external address it requires to succeed.So maybe there is a bug-ish thing here?
Beta Was this translation helpful? Give feedback.
All reactions