X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-rapid-gossip-sync%2Fsrc%2Fprocessing.rs;h=3e001ec45c4be1aa7becbaa6da9f9158f3d217fa;hb=15b79f8fb5040d56b21683bc906c63fb8bb3c92c;hp=ceb8b82295336406c142a376f325070bc9255f3e;hpb=a534a5e7af4923122a359005a99f01cfb33b451c;p=rust-lightning diff --git a/lightning-rapid-gossip-sync/src/processing.rs b/lightning-rapid-gossip-sync/src/processing.rs index ceb8b822..3e001ec4 100644 --- a/lightning-rapid-gossip-sync/src/processing.rs +++ b/lightning-rapid-gossip-sync/src/processing.rs @@ -1,17 +1,23 @@ -use std::cmp::max; -use std::io; -use std::io::Read; +use core::cmp::max; +use core::ops::Deref; +use core::sync::atomic::Ordering; use bitcoin::BlockHash; use bitcoin::secp256k1::PublicKey; use lightning::ln::msgs::{ - DecodeError, ErrorAction, LightningError, OptionalField, UnsignedChannelUpdate, + DecodeError, ErrorAction, LightningError, UnsignedChannelUpdate, }; -use lightning::routing::network_graph; +use lightning::routing::gossip::NetworkGraph; +use lightning::util::logger::Logger; use lightning::util::ser::{BigSize, Readable}; +use lightning::io; use crate::error::GraphSyncError; +use crate::RapidGossipSync; + +#[cfg(not(feature = "std"))] +use alloc::{vec::Vec, borrow::ToOwned}; /// The purpose of this prefix is to identify the serialization format, should other rapid gossip /// sync formats arise in the future. @@ -23,203 +29,180 @@ const GOSSIP_PREFIX: [u8; 4] = [76, 68, 75, 1]; /// avoid malicious updates being able to trigger excessive memory allocation. const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY: u32 = 50_000; -/// Update network graph from binary data. -/// Returns the last sync timestamp to be used the next time rapid sync data is queried. -/// -/// `network_graph`: network graph to be updated -/// -/// `update_data`: `&[u8]` binary stream that comprises the update data -pub fn update_network_graph( - network_graph: &network_graph::NetworkGraph, - update_data: &[u8], -) -> Result { - let mut read_cursor = io::Cursor::new(update_data); - update_network_graph_from_byte_stream(&network_graph, &mut read_cursor) -} - -pub(crate) fn update_network_graph_from_byte_stream( - network_graph: &network_graph::NetworkGraph, - mut read_cursor: &mut R, -) -> Result { - let mut prefix = [0u8; 4]; - read_cursor.read_exact(&mut prefix)?; +impl>, L: Deref> RapidGossipSync where L::Target: Logger { + pub(crate) fn update_network_graph_from_byte_stream( + &self, + mut read_cursor: &mut R, + ) -> Result { + let mut prefix = [0u8; 4]; + read_cursor.read_exact(&mut prefix)?; - match prefix { - GOSSIP_PREFIX => {}, - _ => { + if prefix != GOSSIP_PREFIX { return Err(DecodeError::UnknownVersion.into()); } - }; - - let chain_hash: BlockHash = Readable::read(read_cursor)?; - let latest_seen_timestamp: u32 = Readable::read(read_cursor)?; - // backdate the applied timestamp by a week - let backdated_timestamp = latest_seen_timestamp.saturating_sub(24 * 3600 * 7); - - let node_id_count: u32 = Readable::read(read_cursor)?; - let mut node_ids: Vec = Vec::with_capacity(std::cmp::min( - node_id_count, - MAX_INITIAL_NODE_ID_VECTOR_CAPACITY, - ) as usize); - for _ in 0..node_id_count { - let current_node_id = Readable::read(read_cursor)?; - node_ids.push(current_node_id); - } - let mut previous_scid: u64 = 0; - let announcement_count: u32 = Readable::read(read_cursor)?; - for _ in 0..announcement_count { - let features = Readable::read(read_cursor)?; - - // handle SCID - let scid_delta: BigSize = Readable::read(read_cursor)?; - let short_channel_id = previous_scid - .checked_add(scid_delta.0) - .ok_or(DecodeError::InvalidValue)?; - previous_scid = short_channel_id; - - let node_id_1_index: BigSize = Readable::read(read_cursor)?; - let node_id_2_index: BigSize = Readable::read(read_cursor)?; - if max(node_id_1_index.0, node_id_2_index.0) >= node_id_count as u64 { - return Err(DecodeError::InvalidValue.into()); - }; - let node_id_1 = node_ids[node_id_1_index.0 as usize]; - let node_id_2 = node_ids[node_id_2_index.0 as usize]; - - let announcement_result = network_graph.add_channel_from_partial_announcement( - short_channel_id, - backdated_timestamp as u64, - features, - node_id_1, - node_id_2, - ); - if let Err(lightning_error) = announcement_result { - if let ErrorAction::IgnoreDuplicateGossip = lightning_error.action { - // everything is fine, just a duplicate channel announcement - } else { - return Err(lightning_error.into()); + let chain_hash: BlockHash = Readable::read(read_cursor)?; + let latest_seen_timestamp: u32 = Readable::read(read_cursor)?; + // backdate the applied timestamp by a week + let backdated_timestamp = latest_seen_timestamp.saturating_sub(24 * 3600 * 7); + + let node_id_count: u32 = Readable::read(read_cursor)?; + let mut node_ids: Vec = Vec::with_capacity(core::cmp::min( + node_id_count, + MAX_INITIAL_NODE_ID_VECTOR_CAPACITY, + ) as usize); + for _ in 0..node_id_count { + let current_node_id = Readable::read(read_cursor)?; + node_ids.push(current_node_id); + } + + let network_graph = &self.network_graph; + + let mut previous_scid: u64 = 0; + let announcement_count: u32 = Readable::read(read_cursor)?; + for _ in 0..announcement_count { + let features = Readable::read(read_cursor)?; + + // handle SCID + let scid_delta: BigSize = Readable::read(read_cursor)?; + let short_channel_id = previous_scid + .checked_add(scid_delta.0) + .ok_or(DecodeError::InvalidValue)?; + previous_scid = short_channel_id; + + let node_id_1_index: BigSize = Readable::read(read_cursor)?; + let node_id_2_index: BigSize = Readable::read(read_cursor)?; + + if max(node_id_1_index.0, node_id_2_index.0) >= node_id_count as u64 { + return Err(DecodeError::InvalidValue.into()); + }; + let node_id_1 = node_ids[node_id_1_index.0 as usize]; + let node_id_2 = node_ids[node_id_2_index.0 as usize]; + + let announcement_result = network_graph.add_channel_from_partial_announcement( + short_channel_id, + backdated_timestamp as u64, + features, + node_id_1, + node_id_2, + ); + if let Err(lightning_error) = announcement_result { + if let ErrorAction::IgnoreDuplicateGossip = lightning_error.action { + // everything is fine, just a duplicate channel announcement + } else { + return Err(lightning_error.into()); + } } } - } - previous_scid = 0; // updates start at a new scid + previous_scid = 0; // updates start at a new scid - let update_count: u32 = Readable::read(read_cursor)?; - if update_count == 0 { - return Ok(latest_seen_timestamp); - } + let update_count: u32 = Readable::read(read_cursor)?; + if update_count == 0 { + return Ok(latest_seen_timestamp); + } + + // obtain default values for non-incremental updates + let default_cltv_expiry_delta: u16 = Readable::read(&mut read_cursor)?; + let default_htlc_minimum_msat: u64 = Readable::read(&mut read_cursor)?; + let default_fee_base_msat: u32 = Readable::read(&mut read_cursor)?; + let default_fee_proportional_millionths: u32 = Readable::read(&mut read_cursor)?; + let default_htlc_maximum_msat: u64 = Readable::read(&mut read_cursor)?; + + for _ in 0..update_count { + let scid_delta: BigSize = Readable::read(read_cursor)?; + let short_channel_id = previous_scid + .checked_add(scid_delta.0) + .ok_or(DecodeError::InvalidValue)?; + previous_scid = short_channel_id; - // obtain default values for non-incremental updates - let default_cltv_expiry_delta: u16 = Readable::read(&mut read_cursor)?; - let default_htlc_minimum_msat: u64 = Readable::read(&mut read_cursor)?; - let default_fee_base_msat: u32 = Readable::read(&mut read_cursor)?; - let default_fee_proportional_millionths: u32 = Readable::read(&mut read_cursor)?; - let tentative_default_htlc_maximum_msat: u64 = Readable::read(&mut read_cursor)?; - let default_htlc_maximum_msat = if tentative_default_htlc_maximum_msat == u64::max_value() { - OptionalField::Absent - } else { - OptionalField::Present(tentative_default_htlc_maximum_msat) - }; - - for _ in 0..update_count { - let scid_delta: BigSize = Readable::read(read_cursor)?; - let short_channel_id = previous_scid - .checked_add(scid_delta.0) - .ok_or(DecodeError::InvalidValue)?; - previous_scid = short_channel_id; - - let channel_flags: u8 = Readable::read(read_cursor)?; - - // flags are always sent in full, and hence always need updating - let standard_channel_flags = channel_flags & 0b_0000_0011; - - let mut synthetic_update = if channel_flags & 0b_1000_0000 == 0 { - // full update, field flags will indicate deviations from the default - UnsignedChannelUpdate { + let channel_flags: u8 = Readable::read(read_cursor)?; + + // flags are always sent in full, and hence always need updating + let standard_channel_flags = channel_flags & 0b_0000_0011; + + let mut synthetic_update = UnsignedChannelUpdate { chain_hash, short_channel_id, timestamp: backdated_timestamp, flags: standard_channel_flags, cltv_expiry_delta: default_cltv_expiry_delta, htlc_minimum_msat: default_htlc_minimum_msat, - htlc_maximum_msat: default_htlc_maximum_msat.clone(), + htlc_maximum_msat: default_htlc_maximum_msat, fee_base_msat: default_fee_base_msat, fee_proportional_millionths: default_fee_proportional_millionths, - excess_data: vec![], - } - } else { - // incremental update, field flags will indicate mutated values - let read_only_network_graph = network_graph.read_only(); - let channel = read_only_network_graph - .channels() - .get(&short_channel_id) - .ok_or(LightningError { - err: "Couldn't find channel for update".to_owned(), - action: ErrorAction::IgnoreError, - })?; - - let directional_info = channel - .get_directional_info(channel_flags) - .ok_or(LightningError { - err: "Couldn't find previous directional data for update".to_owned(), - action: ErrorAction::IgnoreError, - })?; - - let htlc_maximum_msat = - if let Some(htlc_maximum_msat) = directional_info.htlc_maximum_msat { - OptionalField::Present(htlc_maximum_msat) + excess_data: Vec::new(), + }; + + let mut skip_update_for_unknown_channel = false; + + if (channel_flags & 0b_1000_0000) != 0 { + // incremental update, field flags will indicate mutated values + let read_only_network_graph = network_graph.read_only(); + if let Some(channel) = read_only_network_graph + .channels() + .get(&short_channel_id) { + + let directional_info = channel + .get_directional_info(channel_flags) + .ok_or(LightningError { + err: "Couldn't find previous directional data for update".to_owned(), + action: ErrorAction::IgnoreError, + })?; + + synthetic_update.cltv_expiry_delta = directional_info.cltv_expiry_delta; + synthetic_update.htlc_minimum_msat = directional_info.htlc_minimum_msat; + synthetic_update.htlc_maximum_msat = directional_info.htlc_maximum_msat; + synthetic_update.fee_base_msat = directional_info.fees.base_msat; + synthetic_update.fee_proportional_millionths = directional_info.fees.proportional_millionths; + } else { - OptionalField::Absent - }; + skip_update_for_unknown_channel = true; + } + }; - UnsignedChannelUpdate { - chain_hash, - short_channel_id, - timestamp: backdated_timestamp, - flags: standard_channel_flags, - cltv_expiry_delta: directional_info.cltv_expiry_delta, - htlc_minimum_msat: directional_info.htlc_minimum_msat, - htlc_maximum_msat, - fee_base_msat: directional_info.fees.base_msat, - fee_proportional_millionths: directional_info.fees.proportional_millionths, - excess_data: vec![], + if channel_flags & 0b_0100_0000 > 0 { + let cltv_expiry_delta: u16 = Readable::read(read_cursor)?; + synthetic_update.cltv_expiry_delta = cltv_expiry_delta; } - }; - if channel_flags & 0b_0100_0000 > 0 { - let cltv_expiry_delta: u16 = Readable::read(read_cursor)?; - synthetic_update.cltv_expiry_delta = cltv_expiry_delta; - } + if channel_flags & 0b_0010_0000 > 0 { + let htlc_minimum_msat: u64 = Readable::read(read_cursor)?; + synthetic_update.htlc_minimum_msat = htlc_minimum_msat; + } - if channel_flags & 0b_0010_0000 > 0 { - let htlc_minimum_msat: u64 = Readable::read(read_cursor)?; - synthetic_update.htlc_minimum_msat = htlc_minimum_msat; - } + if channel_flags & 0b_0001_0000 > 0 { + let fee_base_msat: u32 = Readable::read(read_cursor)?; + synthetic_update.fee_base_msat = fee_base_msat; + } - if channel_flags & 0b_0001_0000 > 0 { - let fee_base_msat: u32 = Readable::read(read_cursor)?; - synthetic_update.fee_base_msat = fee_base_msat; - } + if channel_flags & 0b_0000_1000 > 0 { + let fee_proportional_millionths: u32 = Readable::read(read_cursor)?; + synthetic_update.fee_proportional_millionths = fee_proportional_millionths; + } - if channel_flags & 0b_0000_1000 > 0 { - let fee_proportional_millionths: u32 = Readable::read(read_cursor)?; - synthetic_update.fee_proportional_millionths = fee_proportional_millionths; - } + if channel_flags & 0b_0000_0100 > 0 { + let htlc_maximum_msat: u64 = Readable::read(read_cursor)?; + synthetic_update.htlc_maximum_msat = htlc_maximum_msat; + } - if channel_flags & 0b_0000_0100 > 0 { - let tentative_htlc_maximum_msat: u64 = Readable::read(read_cursor)?; - synthetic_update.htlc_maximum_msat = if tentative_htlc_maximum_msat == u64::max_value() - { - OptionalField::Absent - } else { - OptionalField::Present(tentative_htlc_maximum_msat) - }; + if skip_update_for_unknown_channel { + continue; + } + + match network_graph.update_channel_unsigned(&synthetic_update) { + Ok(_) => {}, + Err(LightningError { action: ErrorAction::IgnoreDuplicateGossip, .. }) => {}, + Err(LightningError { action: ErrorAction::IgnoreAndLog(_), .. }) => {}, + Err(LightningError { action: ErrorAction::IgnoreError, .. }) => {}, + Err(e) => return Err(e.into()), + } } - network_graph.update_channel_unsigned(&synthetic_update)?; + self.network_graph.set_last_rapid_gossip_sync_timestamp(latest_seen_timestamp); + self.is_initial_sync_complete.store(true, Ordering::Release); + Ok(latest_seen_timestamp) } - - Ok(latest_seen_timestamp) } #[cfg(test)] @@ -228,15 +211,17 @@ mod tests { use bitcoin::Network; use lightning::ln::msgs::DecodeError; - use lightning::routing::network_graph::NetworkGraph; + use lightning::routing::gossip::NetworkGraph; + use lightning::util::test_utils::TestLogger; use crate::error::GraphSyncError; - use crate::processing::update_network_graph; + use crate::RapidGossipSync; #[test] fn network_graph_fails_to_update_from_clipped_input() { let block_hash = genesis_block(Network::Bitcoin).block_hash(); - let network_graph = NetworkGraph::new(block_hash); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); let example_input = vec![ 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, @@ -254,7 +239,8 @@ mod tests { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 58, 85, 116, 216, 255, 2, 68, 226, 0, 6, 11, 0, 1, 24, 0, 0, 3, 232, 0, 0, 0, ]; - let update_result = update_network_graph(&network_graph, &example_input[..]); + let rapid_sync = RapidGossipSync::new(&network_graph); + let update_result = rapid_sync.update_network_graph(&example_input[..]); assert!(update_result.is_err()); if let Err(GraphSyncError::DecodeError(DecodeError::ShortRead)) = update_result { // this is the expected error type @@ -264,7 +250,7 @@ mod tests { } #[test] - fn incremental_only_update_fails_without_prior_announcements() { + fn incremental_only_update_ignores_missing_channel() { let incremental_update_input = vec![ 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 229, 183, 167, @@ -274,17 +260,14 @@ mod tests { ]; let block_hash = genesis_block(Network::Bitcoin).block_hash(); - let network_graph = NetworkGraph::new(block_hash); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); assert_eq!(network_graph.read_only().channels().len(), 0); - let update_result = update_network_graph(&network_graph, &incremental_update_input[..]); - assert!(update_result.is_err()); - if let Err(GraphSyncError::LightningError(lightning_error)) = update_result { - assert_eq!(lightning_error.err, "Couldn't find channel for update"); - } else { - panic!("Unexpected update result: {:?}", update_result) - } + let rapid_sync = RapidGossipSync::new(&network_graph); + let update_result = rapid_sync.update_network_graph(&incremental_update_input[..]); + assert!(update_result.is_ok()); } #[test] @@ -306,11 +289,13 @@ mod tests { ]; let block_hash = genesis_block(Network::Bitcoin).block_hash(); - let network_graph = NetworkGraph::new(block_hash); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); assert_eq!(network_graph.read_only().channels().len(), 0); - let update_result = update_network_graph(&network_graph, &announced_update_input[..]); + let rapid_sync = RapidGossipSync::new(&network_graph); + let update_result = rapid_sync.update_network_graph(&announced_update_input[..]); assert!(update_result.is_err()); if let Err(GraphSyncError::LightningError(lightning_error)) = update_result { assert_eq!( @@ -341,11 +326,13 @@ mod tests { ]; let block_hash = genesis_block(Network::Bitcoin).block_hash(); - let network_graph = NetworkGraph::new(block_hash); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); assert_eq!(network_graph.read_only().channels().len(), 0); - let initialization_result = update_network_graph(&network_graph, &initialization_input[..]); + let rapid_sync = RapidGossipSync::new(&network_graph); + let initialization_result = rapid_sync.update_network_graph(&initialization_input[..]); if initialization_result.is_err() { panic!( "Unexpected initialization result: {:?}", @@ -373,10 +360,7 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 136, 0, 0, 0, 221, 255, 2, 68, 226, 0, 6, 11, 0, 1, 128, ]; - let update_result = update_network_graph( - &network_graph, - &opposite_direction_incremental_update_input[..], - ); + let update_result = rapid_sync.update_network_graph(&opposite_direction_incremental_update_input[..]); assert!(update_result.is_err()); if let Err(GraphSyncError::LightningError(lightning_error)) = update_result { assert_eq!( @@ -409,11 +393,13 @@ mod tests { ]; let block_hash = genesis_block(Network::Bitcoin).block_hash(); - let network_graph = NetworkGraph::new(block_hash); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); assert_eq!(network_graph.read_only().channels().len(), 0); - let initialization_result = update_network_graph(&network_graph, &initialization_input[..]); + let rapid_sync = RapidGossipSync::new(&network_graph); + let initialization_result = rapid_sync.update_network_graph(&initialization_input[..]); assert!(initialization_result.is_ok()); let single_direction_incremental_update_input = vec![ @@ -423,10 +409,7 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 136, 0, 0, 0, 221, 255, 2, 68, 226, 0, 6, 11, 0, 1, 128, ]; - let update_result = update_network_graph( - &network_graph, - &single_direction_incremental_update_input[..], - ); + let update_result = rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]); if update_result.is_err() { panic!("Unexpected update result: {:?}", update_result) } @@ -449,6 +432,50 @@ mod tests { assert!(after.contains("783241506229452801")); } + #[test] + fn update_succeeds_when_duplicate_gossip_is_applied() { + let initialization_input = vec![ + 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, + 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218, + 0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251, + 187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125, + 157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136, + 88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106, + 204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138, + 181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175, + 110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128, + 76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68, + 226, 0, 6, 11, 0, 1, 2, 3, 0, 0, 0, 4, 0, 40, 0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 3, 232, + 0, 0, 0, 1, 0, 0, 0, 0, 58, 85, 116, 216, 255, 8, 153, 192, 0, 2, 27, 0, 0, 56, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 100, 0, 0, 2, 224, 0, 25, 0, 0, 0, 1, 0, 0, 0, 125, 255, 2, + 68, 226, 0, 6, 11, 0, 1, 4, 0, 0, 0, 0, 29, 129, 25, 192, 0, 5, 0, 0, 0, 0, 29, 129, + 25, 192, + ]; + + let block_hash = genesis_block(Network::Bitcoin).block_hash(); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); + + assert_eq!(network_graph.read_only().channels().len(), 0); + + let rapid_sync = RapidGossipSync::new(&network_graph); + let initialization_result = rapid_sync.update_network_graph(&initialization_input[..]); + assert!(initialization_result.is_ok()); + + let single_direction_incremental_update_input = vec![ + 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, + 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 229, 183, 167, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 136, 0, 0, 0, 221, 255, 2, + 68, 226, 0, 6, 11, 0, 1, 128, + ]; + let update_result_1 = rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]); + // Apply duplicate update + let update_result_2 = rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]); + assert!(update_result_1.is_ok()); + assert!(update_result_2.is_ok()); + } + #[test] fn full_update_succeeds() { let valid_input = vec![ @@ -470,11 +497,13 @@ mod tests { ]; let block_hash = genesis_block(Network::Bitcoin).block_hash(); - let network_graph = NetworkGraph::new(block_hash); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); assert_eq!(network_graph.read_only().channels().len(), 0); - let update_result = update_network_graph(&network_graph, &valid_input[..]); + let rapid_sync = RapidGossipSync::new(&network_graph); + let update_result = rapid_sync.update_network_graph(&valid_input[..]); if update_result.is_err() { panic!("Unexpected update result: {:?}", update_result) } @@ -496,4 +525,39 @@ mod tests { assert!(after.contains("619737530008010752")); assert!(after.contains("783241506229452801")); } + + #[test] + pub fn update_fails_with_unknown_version() { + let unknown_version_input = vec![ + 76, 68, 75, 2, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, + 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218, + 0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251, + 187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125, + 157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136, + 88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106, + 204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138, + 181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175, + 110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128, + 76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68, + 226, 0, 6, 11, 0, 1, 2, 3, 0, 0, 0, 4, 0, 40, 0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 3, 232, + 0, 0, 0, 1, 0, 0, 0, 0, 29, 129, 25, 192, 255, 8, 153, 192, 0, 2, 27, 0, 0, 60, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 100, 0, 0, 2, 224, 0, 0, 0, 0, 58, 85, 116, 216, 0, 29, 0, + 0, 0, 1, 0, 0, 0, 125, 0, 0, 0, 0, 58, 85, 116, 216, 255, 2, 68, 226, 0, 6, 11, 0, 1, + 0, 0, 1, + ]; + + let block_hash = genesis_block(Network::Bitcoin).block_hash(); + let logger = TestLogger::new(); + let network_graph = NetworkGraph::new(block_hash, &logger); + let rapid_sync = RapidGossipSync::new(&network_graph); + let update_result = rapid_sync.update_network_graph(&unknown_version_input[..]); + + assert!(update_result.is_err()); + + if let Err(GraphSyncError::DecodeError(DecodeError::UnknownVersion)) = update_result { + // this is the expected error type + } else { + panic!("Unexpected update result: {:?}", update_result) + } + } }