-
Notifications
You must be signed in to change notification settings - Fork 946
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
Rework libp2p-identify #116
Conversation
81bc5f7
to
c40cf3b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think everything here is a nit and so I'd probably be OK with approving this if you would rather not make these changes (I'd expect you to make the changes on #117 and not here). That being said, a couple of the changes would probably make this code somewhat nicer.
.peer(&peer_id) | ||
.into_iter() | ||
.flat_map(|peer| peer.addrs()) | ||
.collect::<Vec<_>>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we take ownership of self.peerstore
in this function, why can't we just do:
self.peerstore
.deref()
.peer(&peer_id)
.into_iter()
.flat_map(|peer| peer.addrs())
.into_iter()
.flat_map::<_, fn(_) -> _>(|peer| peer.addrs())
and save a traversal and allocation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that deref()
borrows, therefore we would have a reference to self.peerstore
stored in the closure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right. That's obvious now. We don't have deref_move
yet, ugh.
@@ -191,9 +186,9 @@ impl Transport for BrowserWsConfig { | |||
}); | |||
}; | |||
|
|||
Ok(open_rx.then(|result| { | |||
Ok(Box::new(open_rx.then(|result| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we add a Box
here if it wasn't necessary before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR modifies the item produced by dial
, and writing the type explicitly would become too much of a clusterfuck, therefore I changed the associated type Dial
to a Box
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I'd write the full type when possible (i.e. when it doesn't use closures) even if it's a clusterfuck but that's me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After looking more at it, I think the problem is that the closure now takes ownership of original_addr
, which wasn't needed before. Therefore we can either use a closure, or write a custom modifier that makes the code much more difficult to read.
libp2p-identify/src/protocol.rs
Outdated
} | ||
|
||
// Turn a `Vec<u8>` into a `Multiaddr`. If something bad happens, turn it into an `IoError`. | ||
fn bytes_to_multiaddr(bytes: Vec<u8>) -> Result<Multiaddr, IoError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be defined inside parse_proto_msg
because it's very specific to that function. Better still would be to impl Into<io::Error> for multiaddr::errors::Error
and then just do Multiaddr::from_bytes(bytes)?
and let the ?
machinery add the into
call.
libp2p-identify/src/transport.rs
Outdated
use std::ops::Deref; | ||
use std::time::Duration; | ||
|
||
/// Implementation of `Transport`. See the crate root description. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe link the crate root here. Ideally I'd move the relevant text to this docstring but mirroring the readme and crate root doc is too valuable for maintainance so just linking is enough.
libp2p-identify/src/transport.rs
Outdated
|
||
impl<T, Pr, P> Transport for IdentifyTransport<T, Pr> | ||
where | ||
T: Transport + Clone + 'static, // TODO: 'static :( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For nontrivial uses of generics can we give proper names to the type parameters like we would arguments? You wouldn't get away with naming nontrivial arguments a
and b
, why should type parameters get a free pass? My personal choice would be impl<Trans, PStoreRef, PStore>
. Also, ideally PStore
would be before PStoreRef
and the where
bounds reordered accordingly since that makes it more readable in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, it's a bad habit I have now.
original_addr, | ||
addr_ttl, | ||
)?, | ||
_ => unreachable!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like if we allowed protocols to define that they only work on servers or clients or both so that we could have a seperate IdentifyServer
and IdentifyClient
type and didn't need hacks like this, but that's a major change and not necessary for this PR.
Ok(transport | ||
.dial(old_addr) | ||
.unwrap_or_else(|_| { | ||
panic!("the same multiaddr was determined to be valid earlier") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this panic/message is a sign that we should have a way to dial using an already-parsed Multiaddr
, since this is always infallible if the multiaddr is already verified. It'd be nice to express that in the API instead of relying on the user to know that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand, I don't see any other situation where we would dial the same multiaddress twice in a row, and adding such an API would add a lot of complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the use-case of compile-time checked constant multiaddrs that are parsed by a macro? I think enforcing strings to be the canonical representation of multiaddrs at API boundaries is a poor choice and we should probably have a trait akin to ToSocketAddrs
(it would be possible to have the dial
call be infallible for types that can infallibly be converted to a Multiaddr
using type hackery but I'd prefer if we just added an associated Error
type to this trait and made type Error = !
when that lands). I don't think that's necessary for this PR though, I'll write up another PR with that in it.
libp2p-swarm/src/transport.rs
Outdated
@@ -384,6 +383,37 @@ where | |||
} | |||
} | |||
|
|||
/// > **Note**: This type is needed because of the lack of `-> impl Trait` in Rust. It can be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that actually true? It's an enum and I don't think impl Trait
allows for anonymous sum types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Rust had impl Trait
we could use the Either
enum from the futures
crate and add some modifiers to it. This custom enum is a combination of Either
and these modifiers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe say that here then because as it stands this note isn't much more than a TODO
and doesn't have any place in the docs.
* Implement ConnectionReuse correctly * Add some tests and fixes * Remove useless boolean in active_connections * Correctly run tests * Optimize the processing * Next incoming is now in two steps * Remove log * Fix dialing a node even if we already have a connection * Add a proper PeerId to Peerstore * Turn identify into a transport layer * Expose the dialed multiaddress * Add identified nodes to the peerstore * Allow configuring the TTL of the addresses * Split identify in two modules * Some comments and tweaks * Run rustfmt * Add test and bugfix * Fix wrong address reported when dialing * Fix websocket browser code * Ignore errors in the swarm * Fix multiplex test * Fix some style concerns * Fix concerns
Added peer discovery tests
Based over #115
Slightly reworks the existing code of
libp2p-identify
. Instead of producing anOption<IdentifyInfo>
, we now produce anIdentifyOutput
that contains either anIdentifyInfo
or aIdentifySender
that can be used to send back the information to the remote. TheIdentifyInfo
is no longer part of the configuration of the connection upgrade.Adds an
IdentifyTransport
type that wraps around aTransport
and aPeerstore
. Whenever we receive an incoming connection, we dial back to the node in order to identify it and store its identity in the peerstore. Whenever we dial a node with an address of type/ipfs/...
, we look inside thePeerstore
for a known multiaddress. Due to this behaviour, it is strongly recommended to run theIdentifyTransport
on top of aConnectionReuse
. TheIdentifyTransport
essentially exists to expose addresses of the form/ipfs/...
instead of raw multiaddresses.Changes the
Transport
trait so that dialing now also produces the multiaddress that was dialed in addition to the socket. This is because theIdentifyTransport
can change the multiaddress of the dialed node to be/ipfs/...
.Changes the
Transport
trait so that the multiaddress of an incoming client is known only after the connection upgrade. This is required because of theIdentifyTransport
which changes the multiaddr of the client after identifying it.