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

misc/prost-codec: Introduce codec for varint prefixed Protobuf messages #2630

Merged
merged 9 commits into from
May 5, 2022

Conversation

mxinden
Copy link
Member

@mxinden mxinden commented May 3, 2022

Description

Extracts the Protobuf en-/decoding pattern into its separate crate and applies it to libp2p-identify.

In case this is accepted, we can update the other crates.

1a8b247 also makes libp2p-identify expose an explicit UpgradeError instead of an io::Error.

Links to any relevant issues

#2500

Open Questions

Change checklist

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • A changelog entry has been made in the appropriate crates

@mxinden mxinden requested review from thomaseizinger and elenaf9 May 3, 2022 19:25
@@ -0,0 +1,21 @@
[package]
name = "prost-codec"
Copy link
Contributor

Choose a reason for hiding this comment

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

Something to include in asynchronous-codec perhaps? Feature-flagged of course.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess that would only work if we move the UviBytes into asynchronous-codec as well.

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 guess that would only work if we move the UviBytes into asynchronous-codec as well.

Yes. That is the reason why I didn't move it there. Not sure whats best. I feel like using Uvi is a libp2p thing and thus should be inside the rust-libp2p repo. Given that it is a separate crate folks outside of libp2p can still use it though.

Copy link
Contributor

@thomaseizinger thomaseizinger May 4, 2022

Choose a reason for hiding this comment

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

It would probably be cleaner to not have any specific codecs in asynchronous-codec and make it an interface-only crate. In that case it would be clear that all codecs live outside the crate :)

But, it is probably not worthwhile going through the effort of refactoring that now ...

Comment on lines +69 to +74
#[error("Failed to decode response: {0}.")]
Decode(
#[from]
#[source]
prost::DecodeError,
),
Copy link
Contributor

Choose a reason for hiding this comment

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

If you are using #[source], you shouldn't include inner error message yourself, otherwise anyhow and friends will duplicate the message!

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point. You mentioned this before, though I seem to have forgotten it :( . Thanks for the pointer!

unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] }

[dev-dependencies]
prost-build = "0.10"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
prost-build = "0.10"
prost-build = "0.10"

Nit: newline at end of file.

Comment on lines 113 to 116
.ok_or(prost_codec::Error::Io(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"",
)))??;
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe also add for dcutr a {inbound, outbound}::UpgradeError::StreamClosed like it was done for identify?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea. Done with the recent commit.


Ok(())
}

async fn recv<T>(mut socket: T) -> io::Result<IdentifyInfo>
async fn recv<T>(mut socket: T) -> Result<IdentifyInfo, UpgradeError>
where
T: AsyncRead + AsyncWrite + Unpin,
{
socket.close().await?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to help my understanding: Why do we close the socket here before creating the FramedRead, but don't do this in dcutr on upgrade_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.

The standard identify exchange (not identify push) opens a stream to a remote, never writes on it, and expects the remote to send the response on said stream. Given that the local node never writes on the stream it opened it is safe to close it early. Not sure it is strictly necessary though.

(Also given that the local node never writes on the channel, it can use a FramedRead instead of a Framed.)

In DCUtR upgrade_inbound the remote node sends a request and the local node replies with a response. Closing the stream before creating the Framed would prevent the local node from being able to respond.

Does the above explanation make sense @elenaf9?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes makes sense, thanks!

Copy link
Member Author

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

Thanks for the reviews @thomaseizinger and @elenaf9. All comments should be addressed.


Ok(())
}

async fn recv<T>(mut socket: T) -> io::Result<IdentifyInfo>
async fn recv<T>(mut socket: T) -> Result<IdentifyInfo, UpgradeError>
where
T: AsyncRead + AsyncWrite + Unpin,
{
socket.close().await?;
Copy link
Member Author

Choose a reason for hiding this comment

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

The standard identify exchange (not identify push) opens a stream to a remote, never writes on it, and expects the remote to send the response on said stream. Given that the local node never writes on the stream it opened it is safe to close it early. Not sure it is strictly necessary though.

(Also given that the local node never writes on the channel, it can use a FramedRead instead of a Framed.)

In DCUtR upgrade_inbound the remote node sends a request and the local node replies with a response. Closing the stream before creating the Framed would prevent the local node from being able to respond.

Does the above explanation make sense @elenaf9?

@mxinden mxinden merged commit bbd2f8f into libp2p:master May 5, 2022
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.

3 participants