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

Migrate from protoc to rust-protobuf #3050

Closed
wants to merge 21 commits into from

Conversation

kckeiks
Copy link
Contributor

@kckeiks kckeiks commented Oct 20, 2022

Description

Closes #3024.
Fixes #2645.

Links to any relevant issues

Open Questions

I updated core and a couple of other packages. This is wip atm but I'll update the remaining crates this week.

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

Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

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

Thank you for tackling this! Very appreciated!

I left a few questions.

core/src/identity.rs Outdated Show resolved Hide resolved
core/build.rs Outdated Show resolved Hide resolved
core/build.rs Outdated Show resolved Hide resolved
core/src/identity.rs Outdated Show resolved Hide resolved
@@ -129,7 +126,7 @@ pub enum FromEnvelopeError {
/// Failed to extract the payload from the envelope.
BadPayload(signed_envelope::ReadPayloadError),
/// Failed to decode the provided bytes as a [`PeerRecord`].
InvalidPeerRecord(prost::DecodeError),
InvalidPeerRecord(protobuf::Error),
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this part of the public API? If yes, then this is actually a breaking change which is unfortunate :/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh I missed that. Yes, it is part of the public API 😞.

Copy link
Contributor

Choose a reason for hiding this comment

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

Damn okay. Well don't worry about it here for now, I'll send a PR that wraps the error here. That is still a breaking change but we can ship that separately!

Copy link
Contributor

Choose a reason for hiding this comment

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

So my idea here is to make a dedicated error like this:

#[derive(thiserror::Error, Debug)]
#[error(transparent)]
pub struct DecodeError(protobuf::Error)

This preserves the source chain but hides the concrete error type from the public API.

It'd be nice to do this in a separate PR and then put this feature on top of that. Let me know if you'd be happy to do that otherwise I'll try to get to that next week!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So my idea here is to make a dedicated error like this:

#[derive(thiserror::Error, Debug)]
#[error(transparent)]
pub struct DecodeError(protobuf::Error)

This preserves the source chain but hides the concrete error type from the public API.

That sounds good!

It'd be nice to do this in a separate PR and then put this feature on top of that. Let me know if you'd be happy to do that otherwise I'll try to get to that next week!

If you could please do that that would be great! I'll rebase once that is merged.

Copy link
Contributor

Choose a reason for hiding this comment

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

I starting working on this here: #3058

@kckeiks kckeiks force-pushed the use-rust-protobuf branch 3 times, most recently from 38b7e97 to f1f6ee4 Compare October 21, 2022 20:48
Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

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

Thanks!

core/build.rs Outdated
.unwrap();
]
)
.customize(cust.lite_runtime(true))
Copy link
Contributor

Choose a reason for hiding this comment

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

All the builder fns take self so I think we can just do this:

Suggested change
.customize(cust.lite_runtime(true))
.customize(protobuf_codegen::Customize::default().lite_runtime(true))

.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
buf
public_key.write_to_bytes().expect("Encoding failed.")
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we say something like "all fields to be initialized" given that's the invariant we are relying on?

protocols/autonat/src/protocol.rs Show resolved Hide resolved
protocols/dcutr/CHANGELOG.md Show resolved Hide resolved
@@ -28,7 +28,7 @@ pub enum PlainTextError {
IoError(IoError),

/// Failed to parse the handshake protobuf message.
InvalidPayload(Option<prost::DecodeError>),
InvalidPayload(Option<protobuf::Error>),
Copy link
Contributor

Choose a reason for hiding this comment

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

This makes it a breaking change too I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's public.

@thomaseizinger
Copy link
Contributor

I kicked CI, seems there are still a couple of compile errors 😊

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 21, 2022

I kicked CI, seems there are still a couple of compile errors blush

Yes, I need to clean up a few tests. Will fix.

@@ -13,9 +13,6 @@ categories = ["asynchronous"]
[dependencies]
asynchronous-codec = { version = "0.6" }
bytes = { version = "1" }
prost = "0.11"
protobuf = "3.2"
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't really a prost-codec anymore, now that we are replacing the implementation with protobuf 😅

@mxinden Should we publish a new crate?

Copy link
Member

Choose a reason for hiding this comment

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

👍

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 25, 2022

I think there is one crate left to do. I should have time to do it tomorrow and also take care of some of the other pending tasks.

Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

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

Only a few minor comments!

Looking forward to the full solution :)

protocols/relay/src/v2/protocol/inbound_hop.rs Outdated Show resolved Hide resolved
protocols/rendezvous/src/codec.rs Outdated Show resolved Hide resolved
protocols/rendezvous/src/codec.rs Outdated Show resolved Hide resolved
protocols/rendezvous/src/codec.rs Outdated Show resolved Hide resolved
@mxinden
Copy link
Member

mxinden commented Oct 25, 2022

First off, thanks @kckeiks for the work here. This will make using rust-libp2p for newcomers so much easier.

Given that Protobuf is at the core of libp2p, performance is relevant. Are there any comparisons to prost you can point me to @thomaseizinger @kckeiks? Let's make sure to test this, e.g. via a large user, before merging here.

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 25, 2022

First off, thanks @kckeiks for the work here. This will make using rust-libp2p for newcomers so much easier.

👍

Given that Protobuf is at the core of libp2p, performance is relevant. Are there any comparisons to prost you can point me to @thomaseizinger @kckeiks? Let's make sure to test this, e.g. via a large user, before merging here.

quick-proto has some performance comparisons of prost, protobuf and quick-protobuf. protobuf looks slower than the rest. However, these results are from 4 years ago.

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 25, 2022

I kicked CI, seems there are still a couple of compile errors blush

I fixed the tests.

@jxs
Copy link
Member

jxs commented Oct 25, 2022

quick-proto perfest with protobuf 3.2.0 and prost 0.11 (pushed the changes here)

         labels   rust-protobuf  quick-protobuf           prost      quick/rust      prost/rust
                        ns/iter         ns/iter         ns/iter               %               %

test1
          write             632             471             470            25.5            25.6
           read             966             448             539            53.6            44.2
    read no vec             853             330             440            61.3            48.4
     read reuse             788                              NA              NA

test_repeated_bool
          write             859            1010             890           -17.6            -3.6
           read            1617             924            1136            42.9            29.7
    read no vec            1519             902            1082            40.6            28.8
     read reuse            1027                              NA              NA

test_repeated_packed_int32
          write            1736            1753            1595            -1.0             8.1
           read            2290            1693            1655            26.1            27.7
    read no vec            2261            1622            1575            28.3            30.3
     read reuse            1708                              NA              NA

test_repeated_messages
          write            4542            6754            7764           -48.7           -70.9
           read            9943            6884            7047            30.8            29.1
    read no vec            6616            3939            4032            40.5            39.1
     read reuse            5802                              NA              NA

test_optional_messages
          write            2062            1702            1768            17.5            14.3
           read            4420            1768            2322            60.0            47.5
    read no vec            4390            1949            2626            55.6            40.2
     read reuse            4328                              NA              NA

test_strings
          write            1141             970             951            15.0            16.7
           read            3114             883            2772            71.6            11.0
    read no vec            2972             695            2727            76.6             8.2
     read reuse            2841                              NA              NA

test_small_bytearrays
          write             992             890             900            10.3             9.3
           read            1860             652            2651            64.9           -42.5
    read no vec            1783             551            2445            69.1           -37.1
     read reuse            1638                              NA              NA

test_large_bytearrays
          write           22729           14337           25541            36.9           -12.4
           read           23667            4691           27981            80.2           -18.2
    read no vec            7103             687            8872            90.3           -24.9
     read reuse            5393                              NA              NA
Also (not performance related but fun to know) - Rpc test was successful!

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 25, 2022

Thank you for running those tests @jxs !

@thomaseizinger
Copy link
Contributor

thomaseizinger commented Oct 26, 2022

@kckeiks Please decide if you want to amend commits and force-push or never force-push at all :)

We squash merge in the end so the commits will be gone anyway. But reviews can sometimes be easier by amending commits later but that is also not happening here: For example 8acaa31 would need to be squashed into ea8a303.

Force-pushing but not amending commits is kind of the worst of both worlds: I can't see a clear diff from the last push but the commits also overlap, making it hard to review patch-by-patch :)

Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

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

Thanks!

A few more comments, plus the CI workflow needs adjusting to remove the installation of protoc!

@@ -174,32 +176,33 @@ impl Keypair {
}
};

Ok(pk.encode_to_vec())
Ok(pk.write_to_bytes().map_err(|e| DecodingError::new("Failed to decode.").source(e))?)
Copy link
Contributor

Choose a reason for hiding this comment

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

We discovered that this can never fail right? Let's panic here for consistency.

Comment on lines +179 to +180
pk.write_to_bytes()
.map_err(|e| DecodingError::new("Failed to decode.").source(e))
Copy link
Contributor

Choose a reason for hiding this comment

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

Please panic here for consistency.

Comment on lines +192 to +195
let key_type =
keys_proto::KeyType::from_i32(private_key.Type().value()).ok_or_else(|| {
DecodingError::new(format!("unknown key type: {:?}", private_key.Type()))
})?;
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like another round-trip to me? Wouldn't Type() already give you the enum value?


let (payload, signing_key) =
envelope.payload_and_signing_key(String::from(DOMAIN_SEP), PAYLOAD_TYPE.as_bytes())?;
let record = peer_record_proto::PeerRecord::decode(payload)?;
let record = peer_record_proto::PeerRecord::parse_from_bytes(payload)
.map_err(FromEnvelopeError::from)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need the map_err now?

m.msg_sent(&topic_hash, msg_bytes);
m.msg_sent(
&topic_hash,
usize::try_from(msg_bytes).expect("Size of sent messages fit in usize."),
Copy link
Contributor

Choose a reason for hiding this comment

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

If we panic here, we might as well also panic on line 621.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think as regular cast could do as well.

@thomaseizinger
Copy link
Contributor

quick-proto perfest with protobuf 3.2.0 and prost 0.11 (pushed the changes here)

         labels   rust-protobuf  quick-protobuf           prost      quick/rust      prost/rust
                        ns/iter         ns/iter         ns/iter               %               %

test1
          write             632             471             470            25.5            25.6
           read             966             448             539            53.6            44.2
    read no vec             853             330             440            61.3            48.4
     read reuse             788                              NA              NA

test_repeated_bool
          write             859            1010             890           -17.6            -3.6
           read            1617             924            1136            42.9            29.7
    read no vec            1519             902            1082            40.6            28.8
     read reuse            1027                              NA              NA

test_repeated_packed_int32
          write            1736            1753            1595            -1.0             8.1
           read            2290            1693            1655            26.1            27.7
    read no vec            2261            1622            1575            28.3            30.3
     read reuse            1708                              NA              NA

test_repeated_messages
          write            4542            6754            7764           -48.7           -70.9
           read            9943            6884            7047            30.8            29.1
    read no vec            6616            3939            4032            40.5            39.1
     read reuse            5802                              NA              NA

test_optional_messages
          write            2062            1702            1768            17.5            14.3
           read            4420            1768            2322            60.0            47.5
    read no vec            4390            1949            2626            55.6            40.2
     read reuse            4328                              NA              NA

test_strings
          write            1141             970             951            15.0            16.7
           read            3114             883            2772            71.6            11.0
    read no vec            2972             695            2727            76.6             8.2
     read reuse            2841                              NA              NA

test_small_bytearrays
          write             992             890             900            10.3             9.3
           read            1860             652            2651            64.9           -42.5
    read no vec            1783             551            2445            69.1           -37.1
     read reuse            1638                              NA              NA

test_large_bytearrays
          write           22729           14337           25541            36.9           -12.4
           read           23667            4691           27981            80.2           -18.2
    read no vec            7103             687            8872            90.3           -24.9
     read reuse            5393                              NA              NA
Also (not performance related but fun to know) - Rpc test was successful!

Those relative numbers aren't exactly great. I'd be willing to take that hit though for the removal of the protoc dependency.

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 26, 2022

@kckeiks Please decide if you want to amend commits and force-push or never force-push at all :)

We squash merge in the end so the commits will be gone anyway. But reviews can sometimes be easier by amending commits later but that is also not happening here: For example 8acaa31 would need to be squashed into ea8a303.

Force-pushing but not amending commits is kind of the worst of both worlds: I can't see a clear diff from the last push but the commits also overlap, making it hard to review patch-by-patch :)

Sorry, I've been relying on my command history too much while amending and force-pushing so I inadvertently force-pushed. I will cut that out 😸 .

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 26, 2022

Any thoughts on using quick-protobuf instead? Here is a list of some of its missing features tafia/quick-protobuf#12. I tried it out and the API seems simpler than protobuf. There hasn't been much recent activity/development though.

@thomaseizinger
Copy link
Contributor

Any thoughts on using quick-protobuf instead? Here is a list of some of its missing features tafia/quick-protobuf#12. I tried it out and the API seems simpler than protobuf. There hasn't been much recent activity/development though.

Can you share an example of what quick-protobuf looks like if we were to integrate it into our codebase? I don't mind much which implementation we are using, as long as we get rid of the protoc dependency :)

@jxs
Copy link
Member

jxs commented Oct 26, 2022

Those relative numbers aren't exactly great. I'd be willing to take that hit though for the removal of the protoc dependency.

yeah agree Thomas.

Any thoughts on using quick-protobuf instead? Here is a list of some of its missing features tafia/quick-protobuf#12. I tried it out and the API seems simpler than protobuf. There hasn't been much recent activity/development though.

rust-protobuf also seems to be looking for maintainers

@kckeiks
Copy link
Contributor Author

kckeiks commented Oct 26, 2022

Any thoughts on using quick-protobuf instead? Here is a list of some of its missing features tafia/quick-protobuf#12. I tried it out and the API seems simpler than protobuf. There hasn't been much recent activity/development though.

Can you share an example of what quick-protobuf looks like if we were to integrate it into our codebase? I don't mind much which implementation we are using, as long as we get rid of the protoc dependency :)

This PR #3066 uses quick-proto in libp2p-core.

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.

Migrate from protoc to quick-protobuf and remove the buildscripts Missing cmake
4 participants