Skip to content

Implement serialize/deserialize for Router #271

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

Closed

Conversation

ariard
Copy link

@ariard ariard commented Dec 17, 2018

Will add a test and maybe more docs

Part of #57

@ariard ariard force-pushed the 2018-12-persist-route-db-on-disk branch from 47358b8 to ad45d92 Compare December 18, 2018 02:44
@@ -382,7 +382,81 @@ impl NetAddress {
}
}

#[derive(Clone)]
impl Writeable for NetAddress {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you adapt the UnsignedNodeAnnouncement write/read to use these as well?

Copy link
Author

Choose a reason for hiding this comment

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

Updated

@ariard ariard force-pushed the 2018-12-persist-route-db-on-disk branch from ad45d92 to 216edbb Compare December 19, 2018 01:01
@ariard
Copy link
Author

ariard commented Dec 19, 2018

Damn seems cc dependencies break on 1.22 and 1.29

@TheBlueMatt
Copy link
Collaborator

Looks like this accidentally changed the serialization of some messages resulting in a router_target failure:

---- tests::duplicate_crash stdout ----
thread 'tests::duplicate_crash' panicked at 'We picked the length...', fuzz_targets/router_target.rs:175:46
note: Some details are omitted, run with RUST_BACKTRACE=full for a verbose backtrace.
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
1: std::sys_common::backtrace::print
2: std::panicking::default_hook::{{closure}}
3: std::panicking::default_hook
4: std::panicking::rust_panic_with_hook
5: std::panicking::begin_panic
at libstd/panicking.rs:411
6: router_target::do_test
at fuzz_targets/router_target.rs:175
7: router_target::tests::duplicate_crash
at fuzz_targets/router_target.rs:263
8: router_target::tests::duplicate_crash::{{closure}}
at fuzz_targets/router_target.rs:262
9: core::ops::function::FnOnce::call_once
at libcore/ops/function.rs:238
10: <F as alloc::boxed::FnBox>::call_box
11: __rust_maybe_catch_panic

@ariard
Copy link
Author

ariard commented Dec 21, 2018

Sorry, stupid question, from where do you get this specific debug output ? I mean I only get crash in hfuzz_workspace/router_target/ with HONGGFUZZ.REPORT.TXT ?

@TheBlueMatt
Copy link
Collaborator

If you put the failing test's hex in the duplicate_crash test case in fuzz_targets/router_target.rs and run cargo test from the fuzz/ directory you should get a failing test just like any other cargo test.

@ariard
Copy link
Author

ariard commented Dec 22, 2018

Thanks got the same debug!

@ariard ariard force-pushed the 2018-12-persist-route-db-on-disk branch from 216edbb to 0026aec Compare January 6, 2019 15:41
excess_byte = byte;
break;
},
Err(DecodeError::ShortRead) => return Err(DecodeError::BadLengthDescriptor),
Copy link
Author

Choose a reason for hiding this comment

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

There, as serialization is implemented for NetAddress now, a ShortRead bring back by deserialization field failure should be translated as a BadLengthDescriptor as address descriptor isn't accurate seems to me (or we can change msg_node_announcement_target constraints)

src/ln/msgs.rs Outdated
port,
})
}
_ => return Err(DecodeError::UnknownVersion { byte }),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Doesn't InvalidValue make more sense here?

Copy link
Author

Choose a reason for hiding this comment

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

To me InvalidValue is data that is syntaxically incorrect at the protocol level, there address descriptor is may be right we just don't support it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We use InvalidValue mostly to track non-0/1 for bool values, which seems kinda equivalent here - the type byte isnt a "version" so much as something analogous to a 2 for a bool

src/ln/router.rs Outdated
let fee_proportional_millionths = Readable::read(reader)?;
let last_update_message = match <u8 as Readable<R>>::read(reader)? {
0 => None,
1 => Some(msgs::ChannelUpdate::read(reader)?),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we should just implement Readable/Writeable for Option<T : Readable/Writeable>? There's a bunch of places that would simplify things.

Copy link
Author

Choose a reason for hiding this comment

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

Hey right working on it

@ariard ariard force-pushed the 2018-12-persist-route-db-on-disk branch 2 times, most recently from 0f97f11 to 605b5d2 Compare January 14, 2019 03:20
@ariard
Copy link
Author

ariard commented Jan 14, 2019

Still WIP, need to dissociate between None field and optional field (e,g option_shutdown_upfront_script), should do it with an enum

@ariard ariard force-pushed the 2018-12-persist-route-db-on-disk branch 4 times, most recently from 270e387 to e3f46f3 Compare January 17, 2019 03:40
@ariard
Copy link
Author

ariard commented Jan 17, 2019

Rebased, and fix 1.22 build should be good now

src/ln/msgs.rs Outdated
port,
})
}
_ => return Err(DecodeError::InvalidValue { byte: Some(byte) }),
Copy link
Collaborator

@TheBlueMatt TheBlueMatt Jan 21, 2019

Choose a reason for hiding this comment

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

Hmm, now that I think about it more I'm rather unconvinced of this approach. If, eg, at some point we check the ed25519_pubkey is valid in OnionV3 or the ports are non-0 we may want to return an InvalidValue but not have extra bytes. Maybe it makes sense to return a Result<enum { Ok(NetAddress), UnknownType(u8) }, DecodeError>? This would also make this patch much smaller, which is nice (especially when the "byte" field in InvalidValue only sometimes makes sense, hence it being an Option).

Copy link
Author

Choose a reason for hiding this comment

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

Added a NetAddess::Unknown { descriptor }, cleaner than an enum, Agree, cleaner and better do not touch InvalidValue so let it free to be return for an invalid ed25519_pubkey, zero ports or constrained fields in future addresses.

src/ln/msgs.rs Outdated
#[derive(Clone)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not just Present(T)?

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, still learning to be a good rustacean

@ariard ariard force-pushed the 2018-12-persist-route-db-on-disk branch from e3f46f3 to 2fdff3a Compare January 22, 2019 00:55
@@ -125,9 +125,9 @@ pub fn do_test(data: &[u8]) {
match <($MsgType)>::read(&mut reader) {
Ok(msg) => msg,
Err(e) => match e {
msgs::DecodeError::UnknownVersion => return,
msgs::DecodeError::UnknownVersion { .. } => return,
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: stale.

@@ -191,7 +190,7 @@ pub struct OpenChannel {
pub(crate) htlc_basepoint: PublicKey,
pub(crate) first_per_commitment_point: PublicKey,
pub(crate) channel_flags: u8,
pub(crate) shutdown_scriptpubkey: Option<Script>,
pub(crate) shutdown_scriptpubkey: OptionalField<Script>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe you need a similar hunk in ChannelReestablish.

src/ln/msgs.rs Outdated
@@ -372,6 +371,12 @@ pub enum NetAddress {
/// The port on which the node is listenting
port: u16,
},
/// An unsupported address.
/// At deserialization, we retrieve first byte of it if needed by caller.
Unknown {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmmm, the panics introduced in get_id/len are kinda annoying. A user may deserialize a NetAddress and then try to reserialize it and get a panic. It may be easier to get a higher-level enum that selects between an unknown byte and a NetAddress for the deserialization.

Copy link
Author

Choose a reason for hiding this comment

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

But an enum doesn't fit into Readable trait signature so seems to me here we are constrained between extending NetAddress enum type with UnknownAddress (but gross because of panic) or adding an UnknownAddressDescriptor with byte field in DecodeError ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm? We can implement Readable for NetAddressReadEnum instead of for NetAddress and just map it properly in the message thats calling it.

@ariard ariard force-pushed the 2018-12-persist-route-db-on-disk branch from 2fdff3a to 58d3b14 Compare January 23, 2019 01:54
src/ln/router.rs Outdated
self.htlc_minimum_msat.write(writer)?;
self.fee_base_msat.write(writer)?;
self.fee_proportional_millionths.write(writer)?;
match &self.last_update_message {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Once you add the writer for Option, cant this switch to the impl_writeable!?

Copy link
Author

Choose a reason for hiding this comment

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

There updated with impl_writeable_len_match

self.features.write(writer)?;
self.one_to_two.write(writer)?;
self.two_to_one.write(writer)?;
match &self.announcement_message {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here - can we use impl_writeable?

Copy link
Author

Choose a reason for hiding this comment

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

And there not, I mean due to DirectionalChannelInfo having itself optional field and announcement_msg being optional we have a good chunk of pattern to cover, so if macro goal is to be hygienic I'm not sure it's reached there.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Err, would actually prefer imple_writeable!(.., 0, {}) for both as otherwise we give a wrong length descriptor.

Antoine Riard added 2 commits January 22, 2019 21:58
Extend route_test to check if serialize/deserialize of
NetworkMap works.

Add PartialEq traits on some Router's structs.

Modify also UnsignedNodeAnnouncement serialization
Add OptionalField in OpenChannel, AcceptChannel
ChannelReestablish to avoid serialization implementation
conflicts
Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

Will take as #298 with the following few comments fixed and the commit order swapped as the first commit did not compile on its own.

break;
},
Err(DecodeError::ShortRead) => return Err(DecodeError::BadLengthDescriptor),
_ => unreachable!(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could hit at least DecodeError::Io if the user is streaming the message in to be deserialized live.

self.features.write(writer)?;
self.one_to_two.write(writer)?;
self.two_to_one.write(writer)?;
match &self.announcement_message {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Err, would actually prefer imple_writeable!(.., 0, {}) for both as otherwise we give a wrong length descriptor.

impl<R: ::std::io::Read> Readable<R> for NodeInfo {
fn read(reader: &mut R) -> Result<NodeInfo, DecodeError> {
let channels_count: u64 = Readable::read(reader)?;
let mut channels = Vec::with_capacity(channels_count as usize);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Careful with_capacity()ing a u64 - this will result in corruption causing a crash instead of returning an Err.

@@ -518,6 +592,16 @@ pub enum HTLCFailChannelUpdate {
}
}

/// Messages could have optional fields to use with extended features
/// Due to serialization issues, we encapsulate it in enum
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be nice to speciy what those "serialization issues" are.

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.

2 participants