5 use bitcoin::BlockHash;
6 use bitcoin::secp256k1::PublicKey;
8 use lightning::ln::msgs::{
9 DecodeError, ErrorAction, LightningError, OptionalField, UnsignedChannelUpdate,
11 use lightning::routing::network_graph;
12 use lightning::util::ser::{BigSize, Readable};
14 use crate::error::GraphSyncError;
16 /// The purpose of this prefix is to identify the serialization format, should other rapid gossip
17 /// sync formats arise in the future.
19 /// The fourth byte is the protocol version in case our format gets updated.
20 const GOSSIP_PREFIX: [u8; 4] = [76, 68, 75, 1];
22 /// Maximum vector allocation capacity for distinct node IDs. This constraint is necessary to
23 /// avoid malicious updates being able to trigger excessive memory allocation.
24 const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY: u32 = 50_000;
26 /// Update network graph from binary data.
27 /// Returns the last sync timestamp to be used the next time rapid sync data is queried.
29 /// `network_graph`: network graph to be updated
31 /// `update_data`: `&[u8]` binary stream that comprises the update data
32 pub fn update_network_graph(
33 network_graph: &network_graph::NetworkGraph,
35 ) -> Result<u32, GraphSyncError> {
36 let mut read_cursor = io::Cursor::new(update_data);
37 update_network_graph_from_byte_stream(&network_graph, &mut read_cursor)
40 pub(crate) fn update_network_graph_from_byte_stream<R: Read>(
41 network_graph: &network_graph::NetworkGraph,
42 mut read_cursor: &mut R,
43 ) -> Result<u32, GraphSyncError> {
44 let mut prefix = [0u8; 4];
45 read_cursor.read_exact(&mut prefix)?;
50 return Err(DecodeError::UnknownVersion.into());
54 let chain_hash: BlockHash = Readable::read(read_cursor)?;
55 let latest_seen_timestamp: u32 = Readable::read(read_cursor)?;
56 // backdate the applied timestamp by a week
57 let backdated_timestamp = latest_seen_timestamp.saturating_sub(24 * 3600 * 7);
59 let node_id_count: u32 = Readable::read(read_cursor)?;
60 let mut node_ids: Vec<PublicKey> = Vec::with_capacity(std::cmp::min(
62 MAX_INITIAL_NODE_ID_VECTOR_CAPACITY,
64 for _ in 0..node_id_count {
65 let current_node_id = Readable::read(read_cursor)?;
66 node_ids.push(current_node_id);
69 let mut previous_scid: u64 = 0;
70 let announcement_count: u32 = Readable::read(read_cursor)?;
71 for _ in 0..announcement_count {
72 let features = Readable::read(read_cursor)?;
75 let scid_delta: BigSize = Readable::read(read_cursor)?;
76 let short_channel_id = previous_scid
77 .checked_add(scid_delta.0)
78 .ok_or(DecodeError::InvalidValue)?;
79 previous_scid = short_channel_id;
81 let node_id_1_index: BigSize = Readable::read(read_cursor)?;
82 let node_id_2_index: BigSize = Readable::read(read_cursor)?;
83 if max(node_id_1_index.0, node_id_2_index.0) >= node_id_count as u64 {
84 return Err(DecodeError::InvalidValue.into());
86 let node_id_1 = node_ids[node_id_1_index.0 as usize];
87 let node_id_2 = node_ids[node_id_2_index.0 as usize];
89 let announcement_result = network_graph.add_channel_from_partial_announcement(
91 backdated_timestamp as u64,
96 if let Err(lightning_error) = announcement_result {
97 if let ErrorAction::IgnoreDuplicateGossip = lightning_error.action {
98 // everything is fine, just a duplicate channel announcement
100 return Err(lightning_error.into());
105 previous_scid = 0; // updates start at a new scid
107 let update_count: u32 = Readable::read(read_cursor)?;
108 if update_count == 0 {
109 return Ok(latest_seen_timestamp);
112 // obtain default values for non-incremental updates
113 let default_cltv_expiry_delta: u16 = Readable::read(&mut read_cursor)?;
114 let default_htlc_minimum_msat: u64 = Readable::read(&mut read_cursor)?;
115 let default_fee_base_msat: u32 = Readable::read(&mut read_cursor)?;
116 let default_fee_proportional_millionths: u32 = Readable::read(&mut read_cursor)?;
117 let tentative_default_htlc_maximum_msat: u64 = Readable::read(&mut read_cursor)?;
118 let default_htlc_maximum_msat = if tentative_default_htlc_maximum_msat == u64::max_value() {
119 OptionalField::Absent
121 OptionalField::Present(tentative_default_htlc_maximum_msat)
124 for _ in 0..update_count {
125 let scid_delta: BigSize = Readable::read(read_cursor)?;
126 let short_channel_id = previous_scid
127 .checked_add(scid_delta.0)
128 .ok_or(DecodeError::InvalidValue)?;
129 previous_scid = short_channel_id;
131 let channel_flags: u8 = Readable::read(read_cursor)?;
133 // flags are always sent in full, and hence always need updating
134 let standard_channel_flags = channel_flags & 0b_0000_0011;
136 let mut synthetic_update = if channel_flags & 0b_1000_0000 == 0 {
137 // full update, field flags will indicate deviations from the default
138 UnsignedChannelUpdate {
141 timestamp: backdated_timestamp,
142 flags: standard_channel_flags,
143 cltv_expiry_delta: default_cltv_expiry_delta,
144 htlc_minimum_msat: default_htlc_minimum_msat,
145 htlc_maximum_msat: default_htlc_maximum_msat.clone(),
146 fee_base_msat: default_fee_base_msat,
147 fee_proportional_millionths: default_fee_proportional_millionths,
151 // incremental update, field flags will indicate mutated values
152 let read_only_network_graph = network_graph.read_only();
153 let channel = read_only_network_graph
155 .get(&short_channel_id)
156 .ok_or(LightningError {
157 err: "Couldn't find channel for update".to_owned(),
158 action: ErrorAction::IgnoreError,
161 let directional_info = channel
162 .get_directional_info(channel_flags)
163 .ok_or(LightningError {
164 err: "Couldn't find previous directional data for update".to_owned(),
165 action: ErrorAction::IgnoreError,
168 let htlc_maximum_msat =
169 if let Some(htlc_maximum_msat) = directional_info.htlc_maximum_msat {
170 OptionalField::Present(htlc_maximum_msat)
172 OptionalField::Absent
175 UnsignedChannelUpdate {
178 timestamp: backdated_timestamp,
179 flags: standard_channel_flags,
180 cltv_expiry_delta: directional_info.cltv_expiry_delta,
181 htlc_minimum_msat: directional_info.htlc_minimum_msat,
183 fee_base_msat: directional_info.fees.base_msat,
184 fee_proportional_millionths: directional_info.fees.proportional_millionths,
189 if channel_flags & 0b_0100_0000 > 0 {
190 let cltv_expiry_delta: u16 = Readable::read(read_cursor)?;
191 synthetic_update.cltv_expiry_delta = cltv_expiry_delta;
194 if channel_flags & 0b_0010_0000 > 0 {
195 let htlc_minimum_msat: u64 = Readable::read(read_cursor)?;
196 synthetic_update.htlc_minimum_msat = htlc_minimum_msat;
199 if channel_flags & 0b_0001_0000 > 0 {
200 let fee_base_msat: u32 = Readable::read(read_cursor)?;
201 synthetic_update.fee_base_msat = fee_base_msat;
204 if channel_flags & 0b_0000_1000 > 0 {
205 let fee_proportional_millionths: u32 = Readable::read(read_cursor)?;
206 synthetic_update.fee_proportional_millionths = fee_proportional_millionths;
209 if channel_flags & 0b_0000_0100 > 0 {
210 let tentative_htlc_maximum_msat: u64 = Readable::read(read_cursor)?;
211 synthetic_update.htlc_maximum_msat = if tentative_htlc_maximum_msat == u64::max_value()
213 OptionalField::Absent
215 OptionalField::Present(tentative_htlc_maximum_msat)
219 network_graph.update_channel_unsigned(&synthetic_update)?;
222 Ok(latest_seen_timestamp)
227 use bitcoin::blockdata::constants::genesis_block;
228 use bitcoin::Network;
230 use lightning::ln::msgs::DecodeError;
231 use lightning::routing::network_graph::NetworkGraph;
233 use crate::error::GraphSyncError;
234 use crate::processing::update_network_graph;
237 fn network_graph_fails_to_update_from_clipped_input() {
238 let block_hash = genesis_block(Network::Bitcoin).block_hash();
239 let network_graph = NetworkGraph::new(block_hash);
241 let example_input = vec![
242 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
243 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218,
244 0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251,
245 187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125,
246 157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136,
247 88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106,
248 204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138,
249 181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175,
250 110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128,
251 76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68,
252 226, 0, 6, 11, 0, 1, 2, 3, 0, 0, 0, 2, 0, 40, 0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 0, 100,
253 0, 0, 2, 224, 0, 0, 0, 0, 29, 129, 25, 192, 255, 8, 153, 192, 0, 2, 27, 0, 0, 36, 0, 0,
254 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,
257 let update_result = update_network_graph(&network_graph, &example_input[..]);
258 assert!(update_result.is_err());
259 if let Err(GraphSyncError::DecodeError(DecodeError::ShortRead)) = update_result {
260 // this is the expected error type
262 panic!("Unexpected update result: {:?}", update_result)
267 fn incremental_only_update_fails_without_prior_announcements() {
268 let incremental_update_input = vec![
269 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
270 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 229, 183, 167,
271 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,
272 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,
273 68, 226, 0, 6, 11, 0, 1, 128,
276 let block_hash = genesis_block(Network::Bitcoin).block_hash();
277 let network_graph = NetworkGraph::new(block_hash);
279 assert_eq!(network_graph.read_only().channels().len(), 0);
281 let update_result = update_network_graph(&network_graph, &incremental_update_input[..]);
282 assert!(update_result.is_err());
283 if let Err(GraphSyncError::LightningError(lightning_error)) = update_result {
284 assert_eq!(lightning_error.err, "Couldn't find channel for update");
286 panic!("Unexpected update result: {:?}", update_result)
291 fn incremental_only_update_fails_without_prior_updates() {
292 let announced_update_input = vec![
293 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
294 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 229, 183, 167,
295 0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251,
296 187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125,
297 157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136,
298 88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106,
299 204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138,
300 181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175,
301 110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128,
302 76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68,
303 226, 0, 6, 11, 0, 1, 2, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
304 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,
305 2, 68, 226, 0, 6, 11, 0, 1, 128,
308 let block_hash = genesis_block(Network::Bitcoin).block_hash();
309 let network_graph = NetworkGraph::new(block_hash);
311 assert_eq!(network_graph.read_only().channels().len(), 0);
313 let update_result = update_network_graph(&network_graph, &announced_update_input[..]);
314 assert!(update_result.is_err());
315 if let Err(GraphSyncError::LightningError(lightning_error)) = update_result {
318 "Couldn't find previous directional data for update"
321 panic!("Unexpected update result: {:?}", update_result)
326 fn incremental_only_update_fails_without_prior_same_direction_updates() {
327 let initialization_input = vec![
328 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
329 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218,
330 0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251,
331 187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125,
332 157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136,
333 88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106,
334 204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138,
335 181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175,
336 110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128,
337 76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68,
338 226, 0, 6, 11, 0, 1, 2, 3, 0, 0, 0, 2, 0, 40, 0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 3, 232,
339 0, 0, 0, 1, 0, 0, 0, 0, 58, 85, 116, 216, 255, 8, 153, 192, 0, 2, 27, 0, 0, 25, 0, 0,
340 0, 1, 0, 0, 0, 125, 255, 2, 68, 226, 0, 6, 11, 0, 1, 5, 0, 0, 0, 0, 29, 129, 25, 192,
343 let block_hash = genesis_block(Network::Bitcoin).block_hash();
344 let network_graph = NetworkGraph::new(block_hash);
346 assert_eq!(network_graph.read_only().channels().len(), 0);
348 let initialization_result = update_network_graph(&network_graph, &initialization_input[..]);
349 if initialization_result.is_err() {
351 "Unexpected initialization result: {:?}",
352 initialization_result
356 assert_eq!(network_graph.read_only().channels().len(), 2);
357 let initialized = network_graph.to_string();
359 .contains("021607cfce19a4c5e7e6e738663dfafbbbac262e4ff76c2c9b30dbeefc35c00643"));
361 .contains("02247d9db0dfafea745ef8c9e161eb322f73ac3f8858d8730b6fd97254747ce76b"));
363 .contains("029e01f279986acc83ba235d46d80aede0b7595f410353b93a8ab540bb677f4432"));
365 .contains("02c913118a8895b9e29c89af6e20ed00d95a1f64e4952edbafa84d048f26804c61"));
366 assert!(initialized.contains("619737530008010752"));
367 assert!(initialized.contains("783241506229452801"));
369 let opposite_direction_incremental_update_input = vec![
370 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
371 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 229, 183, 167,
372 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,
373 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,
374 68, 226, 0, 6, 11, 0, 1, 128,
376 let update_result = update_network_graph(
378 &opposite_direction_incremental_update_input[..],
380 assert!(update_result.is_err());
381 if let Err(GraphSyncError::LightningError(lightning_error)) = update_result {
384 "Couldn't find previous directional data for update"
387 panic!("Unexpected update result: {:?}", update_result)
392 fn incremental_update_succeeds_with_prior_announcements_and_full_updates() {
393 let initialization_input = vec![
394 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
395 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218,
396 0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251,
397 187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125,
398 157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136,
399 88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106,
400 204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138,
401 181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175,
402 110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128,
403 76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68,
404 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,
405 0, 0, 0, 1, 0, 0, 0, 0, 58, 85, 116, 216, 255, 8, 153, 192, 0, 2, 27, 0, 0, 56, 0, 0,
406 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,
407 68, 226, 0, 6, 11, 0, 1, 4, 0, 0, 0, 0, 29, 129, 25, 192, 0, 5, 0, 0, 0, 0, 29, 129,
411 let block_hash = genesis_block(Network::Bitcoin).block_hash();
412 let network_graph = NetworkGraph::new(block_hash);
414 assert_eq!(network_graph.read_only().channels().len(), 0);
416 let initialization_result = update_network_graph(&network_graph, &initialization_input[..]);
417 assert!(initialization_result.is_ok());
419 let single_direction_incremental_update_input = vec![
420 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
421 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 229, 183, 167,
422 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,
423 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,
424 68, 226, 0, 6, 11, 0, 1, 128,
426 let update_result = update_network_graph(
428 &single_direction_incremental_update_input[..],
430 if update_result.is_err() {
431 panic!("Unexpected update result: {:?}", update_result)
434 assert_eq!(network_graph.read_only().channels().len(), 2);
435 let after = network_graph.to_string();
437 after.contains("021607cfce19a4c5e7e6e738663dfafbbbac262e4ff76c2c9b30dbeefc35c00643")
440 after.contains("02247d9db0dfafea745ef8c9e161eb322f73ac3f8858d8730b6fd97254747ce76b")
443 after.contains("029e01f279986acc83ba235d46d80aede0b7595f410353b93a8ab540bb677f4432")
446 after.contains("02c913118a8895b9e29c89af6e20ed00d95a1f64e4952edbafa84d048f26804c61")
448 assert!(after.contains("619737530008010752"));
449 assert!(after.contains("783241506229452801"));
453 fn full_update_succeeds() {
454 let valid_input = vec![
455 76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
456 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218,
457 0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251,
458 187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125,
459 157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136,
460 88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106,
461 204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138,
462 181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175,
463 110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128,
464 76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68,
465 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,
466 0, 0, 0, 1, 0, 0, 0, 0, 29, 129, 25, 192, 255, 8, 153, 192, 0, 2, 27, 0, 0, 60, 0, 0,
467 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,
468 0, 0, 1, 0, 0, 0, 125, 0, 0, 0, 0, 58, 85, 116, 216, 255, 2, 68, 226, 0, 6, 11, 0, 1,
472 let block_hash = genesis_block(Network::Bitcoin).block_hash();
473 let network_graph = NetworkGraph::new(block_hash);
475 assert_eq!(network_graph.read_only().channels().len(), 0);
477 let update_result = update_network_graph(&network_graph, &valid_input[..]);
478 if update_result.is_err() {
479 panic!("Unexpected update result: {:?}", update_result)
482 assert_eq!(network_graph.read_only().channels().len(), 2);
483 let after = network_graph.to_string();
485 after.contains("021607cfce19a4c5e7e6e738663dfafbbbac262e4ff76c2c9b30dbeefc35c00643")
488 after.contains("02247d9db0dfafea745ef8c9e161eb322f73ac3f8858d8730b6fd97254747ce76b")
491 after.contains("029e01f279986acc83ba235d46d80aede0b7595f410353b93a8ab540bb677f4432")
494 after.contains("02c913118a8895b9e29c89af6e20ed00d95a1f64e4952edbafa84d048f26804c61")
496 assert!(after.contains("619737530008010752"));
497 assert!(after.contains("783241506229452801"));