X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=src%2Fln%2Fmsgs.rs;h=2c89acf2387686ac8c74a1197109ef07d1daad2f;hb=712051a9fca1b9b2946e9af395036b904b255d32;hp=034a580c018aa727e50d29292aaea8d9e5bca4e5;hpb=f78d7299d66387dbb531cf925483e2f826fdb910;p=rust-lightning diff --git a/src/ln/msgs.rs b/src/ln/msgs.rs index 034a580c..2c89acf2 100644 --- a/src/ln/msgs.rs +++ b/src/ln/msgs.rs @@ -7,9 +7,11 @@ use bitcoin::blockdata::script::Script; use std::error::Error; use std::{cmp, fmt}; +use std::io::Read; use std::result::Result; use util::{byte_utils, internal_traits, events}; +use util::ser::{Readable, Writeable, Writer}; pub trait MsgEncodable { fn encode(&self) -> Vec; @@ -43,6 +45,10 @@ pub enum DecodeError { /// A length descriptor in the packet didn't describe the later data correctly /// (currently only generated in node_announcement) BadLengthDescriptor, + /// Error from std::io + Io(::std::io::Error), + /// 1 or 0 is not found for boolean value + InvalidValue, } pub trait MsgDecodable: Sized { fn decode(v: &[u8]) -> Result; @@ -451,13 +457,17 @@ pub trait ChannelMessageHandler : events::EventsProvider + Send + Sync { // Channel-to-announce: fn handle_announcement_signatures(&self, their_node_id: &PublicKey, msg: &AnnouncementSignatures) -> Result<(), HandleError>; - // Error conditions: + // Connection loss/reestablish: /// Indicates a connection to the peer failed/an existing connection was lost. If no connection /// is believed to be possible in the future (eg they're sending us messages we don't /// understand or indicate they require unknown feature bits), no_connection_possible is set /// and any outstanding channels should be failed. fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool); + fn peer_connected(&self, their_node_id: &PublicKey) -> Vec; + fn handle_channel_reestablish(&self, their_node_id: &PublicKey, msg: &ChannelReestablish) -> Result<(Option, Option, Option), HandleError>; + + // Error: fn handle_error(&self, their_node_id: &PublicKey, msg: &ErrorMessage); } @@ -519,6 +529,8 @@ impl Error for DecodeError { DecodeError::ShortRead => "Packet extended beyond the provided bytes", DecodeError::ExtraAddressesPerType => "More than one address of a single type", DecodeError::BadLengthDescriptor => "A length descriptor in the packet didn't describe the later data correctly", + DecodeError::Io(ref e) => e.description(), + DecodeError::InvalidValue => "0 or 1 is not found for boolean", } } } @@ -534,6 +546,16 @@ impl fmt::Debug for HandleError { } } +impl From<::std::io::Error> for DecodeError { + fn from(e: ::std::io::Error) -> Self { + if e.kind() == ::std::io::ErrorKind::UnexpectedEof { + DecodeError::ShortRead + } else { + DecodeError::Io(e) + } + } +} + macro_rules! secp_pubkey { ( $ctx: expr, $slice: expr ) => { match PublicKey::from_slice($ctx, $slice) { @@ -681,10 +703,11 @@ impl MsgDecodable for OpenChannel { } shutdown_scriptpubkey = Some(Script::from(v[321..321+len].to_vec())); } - + let mut temp_channel_id = [0; 32]; + temp_channel_id[..].copy_from_slice(&v[32..64]); Ok(OpenChannel { chain_hash: deserialize(&v[0..32]).unwrap(), - temporary_channel_id: deserialize(&v[32..64]).unwrap(), + temporary_channel_id: temp_channel_id, funding_satoshis: byte_utils::slice_to_be64(&v[64..72]), push_msat: byte_utils::slice_to_be64(&v[72..80]), dust_limit_satoshis: byte_utils::slice_to_be64(&v[80..88]), @@ -1681,6 +1704,628 @@ impl MsgDecodable for ErrorMessage { } } +impl_writeable_len_match!(AcceptChannel, { + {AcceptChannel{ shutdown_scriptpubkey: Some(ref script), ..}, 270 + 2 + script.len()}, + {_, 270} + }, { + temporary_channel_id, + dust_limit_satoshis, + max_htlc_value_in_flight_msat, + channel_reserve_satoshis, + htlc_minimum_msat, + minimum_depth, + to_self_delay, + max_accepted_htlcs, + funding_pubkey, + revocation_basepoint, + payment_basepoint, + delayed_payment_basepoint, + htlc_basepoint, + first_per_commitment_point, + shutdown_scriptpubkey +}); + +impl_writeable!(AnnouncementSignatures, 32+8+64*2, { + channel_id, + short_channel_id, + node_signature, + bitcoin_signature +}); + +impl Writeable for ChannelReestablish { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(if self.data_loss_protect.is_some() { 32+2*8+33+32 } else { 32+2*8 }); + self.channel_id.write(w)?; + self.next_local_commitment_number.write(w)?; + self.next_remote_commitment_number.write(w)?; + if let Some(ref data_loss_protect) = self.data_loss_protect { + data_loss_protect.your_last_per_commitment_secret.write(w)?; + data_loss_protect.my_current_per_commitment_point.write(w)?; + } + Ok(()) + } +} + +impl Readable for ChannelReestablish{ + fn read(r: &mut R) -> Result { + Ok(Self { + channel_id: Readable::read(r)?, + next_local_commitment_number: Readable::read(r)?, + next_remote_commitment_number: Readable::read(r)?, + data_loss_protect: { + match <[u8; 32] as Readable>::read(r) { + Ok(your_last_per_commitment_secret) => + Some(DataLossProtect { + your_last_per_commitment_secret, + my_current_per_commitment_point: Readable::read(r)?, + }), + Err(DecodeError::ShortRead) => None, + Err(e) => return Err(e) + } + } + }) + } +} + +impl_writeable!(ClosingSigned, 32+8+64, { + channel_id, + fee_satoshis, + signature +}); + +impl_writeable_len_match!(CommitmentSigned, { + { CommitmentSigned { ref htlc_signatures, .. }, 32+64+2+htlc_signatures.len()*64 } + }, { + channel_id, + signature, + htlc_signatures +}); + +impl_writeable_len_match!(DecodedOnionErrorPacket, { + { DecodedOnionErrorPacket { ref failuremsg, ref pad, .. }, 32 + 4 + failuremsg.len() + pad.len() } + }, { + hmac, + failuremsg, + pad +}); + +impl_writeable!(FundingCreated, 32+32+2+64, { + temporary_channel_id, + funding_txid, + funding_output_index, + signature +}); + +impl_writeable!(FundingSigned, 32+64, { + channel_id, + signature +}); + +impl_writeable!(FundingLocked, 32+33, { + channel_id, + next_per_commitment_point +}); + +impl_writeable_len_match!(GlobalFeatures, { + { GlobalFeatures { ref flags }, flags.len() + 2 } + }, { + flags +}); + +impl_writeable_len_match!(LocalFeatures, { + { LocalFeatures { ref flags }, flags.len() + 2 } + }, { + flags +}); + +impl_writeable_len_match!(Init, { + { Init { ref global_features, ref local_features }, global_features.flags.len() + local_features.flags.len() + 4 } + }, { + global_features, + local_features +}); + +impl_writeable_len_match!(OpenChannel, { + { OpenChannel { shutdown_scriptpubkey: Some(ref script), .. }, 319 + 2 + script.len() }, + { OpenChannel { shutdown_scriptpubkey: None, .. }, 319 } + }, { + chain_hash, + temporary_channel_id, + funding_satoshis, + push_msat, + dust_limit_satoshis, + max_htlc_value_in_flight_msat, + channel_reserve_satoshis, + htlc_minimum_msat, + feerate_per_kw, + to_self_delay, + max_accepted_htlcs, + funding_pubkey, + revocation_basepoint, + payment_basepoint, + delayed_payment_basepoint, + htlc_basepoint, + first_per_commitment_point, + channel_flags, + shutdown_scriptpubkey +}); + +impl_writeable!(RevokeAndACK, 32+32+33, { + channel_id, + per_commitment_secret, + next_per_commitment_point +}); + +impl_writeable_len_match!(Shutdown, { + { Shutdown { ref scriptpubkey, .. }, 32 + 2 + scriptpubkey.len() } + }, { + channel_id, + scriptpubkey +}); + +impl_writeable_len_match!(UpdateFailHTLC, { + { UpdateFailHTLC { ref reason, .. }, 32 + 10 + reason.data.len() } + }, { + channel_id, + htlc_id, + reason +}); + +impl_writeable!(UpdateFailMalformedHTLC, 32+8+32+2, { + channel_id, + htlc_id, + sha256_of_onion, + failure_code +}); + +impl_writeable!(UpdateFee, 32+4, { + channel_id, + feerate_per_kw +}); + +impl_writeable!(UpdateFulfillHTLC, 32+8+32, { + channel_id, + htlc_id, + payment_preimage +}); + +impl_writeable_len_match!(OnionErrorPacket, { + { OnionErrorPacket { ref data, .. }, 2 + data.len() } + }, { + data +}); + +impl Writeable for OnionPacket { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(1 + 33 + 20*65 + 32); + self.version.write(w)?; + match self.public_key { + Ok(pubkey) => pubkey.write(w)?, + Err(_) => [0u8;33].write(w)?, + } + w.write_all(&self.hop_data)?; + self.hmac.write(w)?; + Ok(()) + } +} + +impl Readable for OnionPacket { + fn read(r: &mut R) -> Result { + Ok(OnionPacket { + version: Readable::read(r)?, + public_key: { + let mut buf = [0u8;33]; + r.read_exact(&mut buf)?; + PublicKey::from_slice(&Secp256k1::without_caps(), &buf) + }, + hop_data: Readable::read(r)?, + hmac: Readable::read(r)?, + }) + } +} + +impl_writeable!(UpdateAddHTLC, 32+8+8+32+4+1366, { + channel_id, + htlc_id, + amount_msat, + payment_hash, + cltv_expiry, + onion_routing_packet +}); + +impl Writeable for OnionRealm0HopData { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(32); + self.short_channel_id.write(w)?; + self.amt_to_forward.write(w)?; + self.outgoing_cltv_value.write(w)?; + w.write_all(&[0;12])?; + Ok(()) + } +} + +impl Readable for OnionRealm0HopData { + fn read(r: &mut R) -> Result { + Ok(OnionRealm0HopData { + short_channel_id: Readable::read(r)?, + amt_to_forward: Readable::read(r)?, + outgoing_cltv_value: { + let v: u32 = Readable::read(r)?; + r.read_exact(&mut [0; 12])?; + v + } + }) + } +} + +impl Writeable for OnionHopData { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(65); + self.realm.write(w)?; + self.data.write(w)?; + self.hmac.write(w)?; + Ok(()) + } +} + +impl Readable for OnionHopData { + fn read(r: &mut R) -> Result { + Ok(OnionHopData { + realm: { + let r: u8 = Readable::read(r)?; + if r != 0 { + return Err(DecodeError::UnknownRealmByte); + } + r + }, + data: Readable::read(r)?, + hmac: Readable::read(r)?, + }) + } +} + +impl Writeable for Ping { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(self.byteslen as usize + 4); + self.ponglen.write(w)?; + vec![0u8; self.byteslen as usize].write(w)?; // size-unchecked write + Ok(()) + } +} + +impl Readable for Ping { + fn read(r: &mut R) -> Result { + Ok(Ping { + ponglen: Readable::read(r)?, + byteslen: { + let byteslen = Readable::read(r)?; + r.read_exact(&mut vec![0u8; byteslen as usize][..])?; + byteslen + } + }) + } +} + +impl Writeable for Pong { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(self.byteslen as usize + 2); + vec![0u8; self.byteslen as usize].write(w)?; // size-unchecked write + Ok(()) + } +} + +impl Readable for Pong { + fn read(r: &mut R) -> Result { + Ok(Pong { + byteslen: { + let byteslen = Readable::read(r)?; + r.read_exact(&mut vec![0u8; byteslen as usize][..])?; + byteslen + } + }) + } +} + +impl Writeable for UnsignedChannelAnnouncement { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(2 + 2*32 + 4*33 + self.features.flags.len() + self.excess_data.len()); + self.features.write(w)?; + self.chain_hash.write(w)?; + self.short_channel_id.write(w)?; + self.node_id_1.write(w)?; + self.node_id_2.write(w)?; + self.bitcoin_key_1.write(w)?; + self.bitcoin_key_2.write(w)?; + w.write_all(&self.excess_data[..])?; + Ok(()) + } +} + +impl Readable for UnsignedChannelAnnouncement { + fn read(r: &mut R) -> Result { + Ok(Self { + features: { + let f: GlobalFeatures = Readable::read(r)?; + if f.requires_unknown_bits() { + return Err(DecodeError::UnknownRequiredFeature); + } + f + }, + chain_hash: Readable::read(r)?, + short_channel_id: Readable::read(r)?, + node_id_1: Readable::read(r)?, + node_id_2: Readable::read(r)?, + bitcoin_key_1: Readable::read(r)?, + bitcoin_key_2: Readable::read(r)?, + excess_data: { + let mut excess_data = vec![]; + r.read_to_end(&mut excess_data)?; + excess_data + }, + }) + } +} + +impl_writeable_len_match!(ChannelAnnouncement, { + { ChannelAnnouncement { contents: UnsignedChannelAnnouncement {ref features, ref excess_data, ..}, .. }, + 2 + 2*32 + 4*33 + features.flags.len() + excess_data.len() + 4*64 } + }, { + node_signature_1, + node_signature_2, + bitcoin_signature_1, + bitcoin_signature_2, + contents +}); + +impl Writeable for UnsignedChannelUpdate { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(64 + self.excess_data.len()); + self.chain_hash.write(w)?; + self.short_channel_id.write(w)?; + self.timestamp.write(w)?; + self.flags.write(w)?; + self.cltv_expiry_delta.write(w)?; + self.htlc_minimum_msat.write(w)?; + self.fee_base_msat.write(w)?; + self.fee_proportional_millionths.write(w)?; + w.write_all(&self.excess_data[..])?; + Ok(()) + } +} + +impl Readable for UnsignedChannelUpdate { + fn read(r: &mut R) -> Result { + Ok(Self { + chain_hash: Readable::read(r)?, + short_channel_id: Readable::read(r)?, + timestamp: Readable::read(r)?, + flags: Readable::read(r)?, + cltv_expiry_delta: Readable::read(r)?, + htlc_minimum_msat: Readable::read(r)?, + fee_base_msat: Readable::read(r)?, + fee_proportional_millionths: Readable::read(r)?, + excess_data: { + let mut excess_data = vec![]; + r.read_to_end(&mut excess_data)?; + excess_data + }, + }) + } +} + +impl_writeable_len_match!(ChannelUpdate, { + { ChannelUpdate { contents: UnsignedChannelUpdate {ref excess_data, ..}, .. }, + 64 + excess_data.len() + 64 } + }, { + signature, + contents +}); + +impl Writeable for ErrorMessage { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(32 + 2 + self.data.len()); + self.channel_id.write(w)?; + (self.data.len() as u16).write(w)?; + w.write_all(self.data.as_bytes())?; + Ok(()) + } +} + +impl Readable for ErrorMessage { + fn read(r: &mut R) -> Result { + Ok(Self { + channel_id: Readable::read(r)?, + data: { + let mut sz: usize = >::read(r)? as usize; + let mut data = vec![]; + let data_len = r.read_to_end(&mut data)?; + sz = cmp::min(data_len, sz); + match String::from_utf8(data[..sz as usize].to_vec()) { + Ok(s) => s, + Err(_) => return Err(DecodeError::BadText), + } + } + }) + } +} + +impl Writeable for UnsignedNodeAnnouncement { + fn write(&self, w: &mut W) -> Result<(), DecodeError> { + w.size_hint(64 + 76 + self.features.flags.len() + self.addresses.len()*38 + self.excess_address_data.len() + self.excess_data.len()); + self.features.write(w)?; + self.timestamp.write(w)?; + self.node_id.write(w)?; + w.write_all(&self.rgb)?; + self.alias.write(w)?; + + let mut addr_slice = Vec::with_capacity(self.addresses.len() * 18); + let mut addrs_to_encode = self.addresses.clone(); + addrs_to_encode.sort_unstable_by(|a, b| { a.get_id().cmp(&b.get_id()) }); + addrs_to_encode.dedup_by(|a, b| { a.get_id() == b.get_id() }); + for addr in addrs_to_encode.iter() { + match addr { + &NetAddress::IPv4{addr, port} => { + addr_slice.push(1); + addr_slice.extend_from_slice(&addr); + addr_slice.extend_from_slice(&byte_utils::be16_to_array(port)); + }, + &NetAddress::IPv6{addr, port} => { + addr_slice.push(2); + addr_slice.extend_from_slice(&addr); + addr_slice.extend_from_slice(&byte_utils::be16_to_array(port)); + }, + &NetAddress::OnionV2{addr, port} => { + addr_slice.push(3); + addr_slice.extend_from_slice(&addr); + addr_slice.extend_from_slice(&byte_utils::be16_to_array(port)); + }, + &NetAddress::OnionV3{ed25519_pubkey, checksum, version, port} => { + addr_slice.push(4); + addr_slice.extend_from_slice(&ed25519_pubkey); + addr_slice.extend_from_slice(&byte_utils::be16_to_array(checksum)); + addr_slice.push(version); + addr_slice.extend_from_slice(&byte_utils::be16_to_array(port)); + }, + } + } + ((addr_slice.len() + self.excess_address_data.len()) as u16).write(w)?; + w.write_all(&addr_slice[..])?; + w.write_all(&self.excess_address_data[..])?; + w.write_all(&self.excess_data[..])?; + Ok(()) + } +} + +impl Readable for UnsignedNodeAnnouncement { + fn read(r: &mut R) -> Result { + let features: GlobalFeatures = Readable::read(r)?; + if features.requires_unknown_bits() { + return Err(DecodeError::UnknownRequiredFeature); + } + let timestamp: u32 = Readable::read(r)?; + let node_id: PublicKey = Readable::read(r)?; + let mut rgb = [0; 3]; + r.read_exact(&mut rgb)?; + let alias: [u8; 32] = Readable::read(r)?; + + let addrlen: u16 = Readable::read(r)?; + let mut addr_readpos = 0; + let mut addresses = Vec::with_capacity(4); + let mut f: u8 = 0; + let mut excess = 0; + loop { + if addrlen <= addr_readpos { break; } + f = Readable::read(r)?; + match f { + 1 => { + if addresses.len() > 0 { + return Err(DecodeError::ExtraAddressesPerType); + } + if addrlen < addr_readpos + 1 + 6 { + return Err(DecodeError::BadLengthDescriptor); + } + addresses.push(NetAddress::IPv4 { + addr: { + let mut addr = [0; 4]; + r.read_exact(&mut addr)?; + addr + }, + port: Readable::read(r)?, + }); + addr_readpos += 1 + 6 + }, + 2 => { + if addresses.len() > 1 || (addresses.len() == 1 && addresses[0].get_id() != 1) { + return Err(DecodeError::ExtraAddressesPerType); + } + if addrlen < addr_readpos + 1 + 18 { + return Err(DecodeError::BadLengthDescriptor); + } + addresses.push(NetAddress::IPv6 { + addr: { + let mut addr = [0; 16]; + r.read_exact(&mut addr)?; + addr + }, + port: Readable::read(r)?, + }); + addr_readpos += 1 + 18 + }, + 3 => { + if addresses.len() > 2 || (addresses.len() > 0 && addresses.last().unwrap().get_id() > 2) { + return Err(DecodeError::ExtraAddressesPerType); + } + if addrlen < addr_readpos + 1 + 12 { + return Err(DecodeError::BadLengthDescriptor); + } + addresses.push(NetAddress::OnionV2 { + addr: { + let mut addr = [0; 10]; + r.read_exact(&mut addr)?; + addr + }, + port: Readable::read(r)?, + }); + addr_readpos += 1 + 12 + }, + 4 => { + if addresses.len() > 3 || (addresses.len() > 0 && addresses.last().unwrap().get_id() > 3) { + return Err(DecodeError::ExtraAddressesPerType); + } + if addrlen < addr_readpos + 1 + 37 { + return Err(DecodeError::BadLengthDescriptor); + } + addresses.push(NetAddress::OnionV3 { + ed25519_pubkey: Readable::read(r)?, + checksum: Readable::read(r)?, + version: Readable::read(r)?, + port: Readable::read(r)?, + }); + addr_readpos += 1 + 37 + }, + _ => { excess = 1; break; } + } + } + + let mut excess_data = vec![]; + let excess_address_data = if addr_readpos < addrlen { + let mut excess_address_data = vec![0; (addrlen - addr_readpos) as usize]; + r.read_exact(&mut excess_address_data[excess..])?; + if excess == 1 { + excess_address_data[0] = f; + } + excess_address_data + } else { + if excess == 1 { + excess_data.push(f); + } + Vec::new() + }; + + Ok(UnsignedNodeAnnouncement { + features: features, + timestamp: timestamp, + node_id: node_id, + rgb: rgb, + alias: alias, + addresses: addresses, + excess_address_data: excess_address_data, + excess_data: { + r.read_to_end(&mut excess_data)?; + excess_data + }, + }) + } +} + +impl_writeable_len_match!(NodeAnnouncement, { + { NodeAnnouncement { contents: UnsignedNodeAnnouncement { ref features, ref addresses, ref excess_address_data, ref excess_data, ..}, .. }, + 64 + 76 + features.flags.len() + addresses.len()*38 + excess_address_data.len() + excess_data.len() } + }, { + signature, + contents +}); + #[cfg(test)] mod tests { use hex;