-
Notifications
You must be signed in to change notification settings - Fork 277
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
noise: specify proto2 #456
Conversation
Can you include some context here too please. Why do we want to use proto2 instead of proto3? Also do you have an example test program you used to verify the bytes are the same over the wire? Thanks! |
@MarcoPolo I added the code and a short motivation. |
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.
Very grateful for this change! @marten-seemann thanks for investigating here.
I think this deserves a revision bump.
I also tested this on the rust-libp2p side.
To reproduce
diff --git a/transports/noise/build.rs b/transports/noise/build.rs
index c9cf6041..c1bda422 100644
--- a/transports/noise/build.rs
+++ b/transports/noise/build.rs
@@ -20,4 +20,5 @@
fn main() {
prost_build::compile_protos(&["src/io/handshake/payload.proto"], &["src"]).unwrap();
+ prost_build::compile_protos(&["src/io/handshake/payload2.proto"], &["src"]).unwrap();
}
diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs
index 35099ea8..a1207ee6 100644
--- a/transports/noise/src/io/handshake.rs
+++ b/transports/noise/src/io/handshake.rs
@@ -24,6 +24,10 @@
mod payload_proto {
include!(concat!(env!("OUT_DIR"), "/payload.proto.rs"));
}
+#[allow(clippy::derive_partial_eq_without_eq)]
+mod payload_proto_2 {
+ include!(concat!(env!("OUT_DIR"), "/payload2.proto.rs"));
+}
use crate::error::NoiseError;
use crate::io::{framed::NoiseFramed, NoiseOutput};
@@ -449,3 +453,38 @@ where
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use quickcheck::*;
+
+ #[test]
+ fn proto_2_3_round_trip() {
+ fn prop(identity_key: Vec<u8>, identity_sig: Vec<u8>, data: Vec<u8>) {
+ let pb3 = payload_proto::NoiseHandshakePayload {
+ identity_key: identity_key.clone(),
+ identity_sig: identity_sig.clone(),
+ data: data.clone(),
+ };
+
+ let mut buf = vec![];
+ pb3.encode(&mut buf).unwrap();
+
+ let pb2 = payload_proto_2::NoiseHandshakePayload::decode(&buf[..]).unwrap();
+
+ assert_eq!(pb2.identity_sig, identity_sig);
+ assert_eq!(pb2.identity_key, identity_key);
+ assert_eq!(pb2.data, data);
+
+ pb2.encode(&mut buf).unwrap();
+ let pb3 = payload_proto::NoiseHandshakePayload::decode(&buf[..]).unwrap();
+
+ assert_eq!(pb3.identity_sig, identity_sig);
+ assert_eq!(pb3.identity_key, identity_key);
+ assert_eq!(pb3.data, data);
+ }
+
+ quickcheck(prop as fn(_, _, _));
+ }
+}
diff --git a/transports/noise/src/io/handshake/payload2.proto b/transports/noise/src/io/handshake/payload2.proto
new file mode 100644
index 00000000..8437738e
--- /dev/null
+++ b/transports/noise/src/io/handshake/payload2.proto
@@ -0,0 +1,11 @@
+syntax = "proto2";
+
+package payload2.proto;
+
+// Payloads for Noise handshake messages.
+
+message NoiseHandshakePayload {
+ required bytes identity_key = 1;
+ required bytes identity_sig = 2;
+ required bytes data = 3;
+}
\ No newline at end of file
noise/README.md
Outdated
@@ -217,6 +217,8 @@ When decrypted, the payload contains a serialized [protobuf][protobuf] | |||
`NoiseHandshakePayload` message with the following schema: | |||
|
|||
``` protobuf | |||
syntax = "proto2"; | |||
|
|||
message NoiseHandshakePayload { | |||
bytes identity_key = 1; |
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.
bytes identity_key = 1; | |
required bytes identity_key = 1; |
If I am not mistaken proto2
requires either required
, optional
or repeated
.
https://developers.google.com/protocol-buffers/docs/proto#specifying-rules
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.
Any objections against making them all optional? If we ever want to send early data with the first handshake message, we can then use this Protobuf.
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 the record, a proto3 encoder will simply provide the default value to the user in case any of these fields are optional
and are not set before encoding with a proto2 encoder.
I am fine with these fields being optional
. Though keep in mind that that would allow the above incompatibility at the schema level. I.e. a proto2 implementation could send a message to an old proto3 implementation that is incompatible.
How about making them optional
and documenting that some implementations (using proto3) expect these fields to be set on the second and third Noise handshake message?
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.
How about making them optional and documenting that some implementations (using proto3) expect these fields to be set on the second and third Noise handshake message?
I think our handshake description specifies exactly that. Not sure if we need to add any text, mind suggesting something if you feel strongly?
Sending this Protobuf in the first handshake is forbidden by this spec anyway (although we don't enforce it), so using this Protobuf for that purpose would require a spec change anyway.
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 our handshake description specifies exactly that.
Yes, you are right. Sorry for that.
Missing this one though, right? |
Sorry, missed that. I bumped it. Not sure if it technically requires one, since this should be a backwards-compatible change, but then it doesn't hurt either. |
If I am not mistaken, a non-breaking change qualifies as a revision bump:
https://github.com/libp2p/specs/blob/master/00-framework-02-document-header.md |
Indeed, that's what the document says. We should change that. It doesn't make sense to bump the version for every change, e.g. in the extreme case fixing a typo. |
The protocol buffers v3 spec says of the optional keyword (emphasis mine):
This seems to contradict the above sentence from the OP? Is it just the generated go code that doesn't let you check to see if a value was explicitly set? If so it sounds more like
|
Proto2 allows us to distinguish between unset and default values, which Proto3 doesn't. Since the protobuf we used for Noise was that simple, the serialization is compatible, so we can change to Proto2, even though some implementations interpreted the Protobuf defined here as Proto3.
I confirmed that a node running v0.22.0 (using a proto3 protobuf) can connect to a node using the proto2 protobuf, and vice versa.
Server
client (using the ID printed by the server):