-
Notifications
You must be signed in to change notification settings - Fork 399
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
Introduce graph sync crate #1155
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
[*] | ||
indent_style = tab | ||
insert_final_newline = true | ||
trim_trailing_whitespace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// This file is Copyright its original authors, visible in version control | ||
// history. | ||
// | ||
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE | ||
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. | ||
// You may not use this file except in accordance with one or both of these | ||
// licenses. | ||
|
||
// This file is auto-generated by gen_target.sh based on target_template.txt | ||
// To modify it, modify target_template.txt and run gen_target.sh instead. | ||
|
||
#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] | ||
|
||
#[cfg(not(fuzzing))] | ||
compile_error!("Fuzz targets need cfg=fuzzing"); | ||
|
||
extern crate lightning_fuzz; | ||
use lightning_fuzz::process_network_graph::*; | ||
|
||
#[cfg(feature = "afl")] | ||
#[macro_use] extern crate afl; | ||
#[cfg(feature = "afl")] | ||
fn main() { | ||
fuzz!(|data| { | ||
process_network_graph_run(data.as_ptr(), data.len()); | ||
}); | ||
} | ||
|
||
#[cfg(feature = "honggfuzz")] | ||
#[macro_use] extern crate honggfuzz; | ||
#[cfg(feature = "honggfuzz")] | ||
fn main() { | ||
loop { | ||
fuzz!(|data| { | ||
process_network_graph_run(data.as_ptr(), data.len()); | ||
}); | ||
} | ||
} | ||
|
||
#[cfg(feature = "libfuzzer_fuzz")] | ||
#[macro_use] extern crate libfuzzer_sys; | ||
#[cfg(feature = "libfuzzer_fuzz")] | ||
fuzz_target!(|data: &[u8]| { | ||
process_network_graph_run(data.as_ptr(), data.len()); | ||
}); | ||
|
||
#[cfg(feature = "stdin_fuzz")] | ||
fn main() { | ||
use std::io::Read; | ||
|
||
let mut data = Vec::with_capacity(8192); | ||
std::io::stdin().read_to_end(&mut data).unwrap(); | ||
process_network_graph_run(data.as_ptr(), data.len()); | ||
} | ||
|
||
#[test] | ||
fn run_test_cases() { | ||
use std::fs; | ||
use std::io::Read; | ||
use lightning_fuzz::utils::test_logger::StringBuffer; | ||
|
||
use std::sync::{atomic, Arc}; | ||
{ | ||
let data: Vec<u8> = vec![0]; | ||
process_network_graph_run(data.as_ptr(), data.len()); | ||
} | ||
let mut threads = Vec::new(); | ||
let threads_running = Arc::new(atomic::AtomicUsize::new(0)); | ||
if let Ok(tests) = fs::read_dir("test_cases/process_network_graph") { | ||
for test in tests { | ||
let mut data: Vec<u8> = Vec::new(); | ||
let path = test.unwrap().path(); | ||
fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); | ||
threads_running.fetch_add(1, atomic::Ordering::AcqRel); | ||
|
||
let thread_count_ref = Arc::clone(&threads_running); | ||
let main_thread_ref = std::thread::current(); | ||
threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), | ||
std::thread::spawn(move || { | ||
let string_logger = StringBuffer::new(); | ||
|
||
let panic_logger = string_logger.clone(); | ||
let res = if ::std::panic::catch_unwind(move || { | ||
process_network_graph_test(&data, panic_logger); | ||
}).is_err() { | ||
Some(string_logger.into_string()) | ||
} else { None }; | ||
thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); | ||
main_thread_ref.unpark(); | ||
res | ||
}) | ||
)); | ||
while threads_running.load(atomic::Ordering::Acquire) > 32 { | ||
std::thread::park(); | ||
} | ||
} | ||
} | ||
let mut failed_outputs = Vec::new(); | ||
for (test, thread) in threads.drain(..) { | ||
if let Some(output) = thread.join().unwrap() { | ||
println!("\nOutput of {}:\n{}\n", test, output); | ||
failed_outputs.push(test); | ||
} | ||
} | ||
if !failed_outputs.is_empty() { | ||
println!("Test cases which failed: "); | ||
for case in failed_outputs { | ||
println!("{}", case); | ||
} | ||
panic!(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Import that needs to be added manually | ||
use utils::test_logger; | ||
|
||
/// Actual fuzz test, method signature and name are fixed | ||
fn do_test(data: &[u8]) { | ||
let block_hash = bitcoin::BlockHash::default(); | ||
let network_graph = lightning::routing::network_graph::NetworkGraph::new(block_hash); | ||
lightning_rapid_gossip_sync::processing::update_network_graph(&network_graph, data); | ||
} | ||
|
||
/// Method that needs to be added manually, {name}_test | ||
pub fn process_network_graph_test<Out: test_logger::Output>(data: &[u8], _out: Out) { | ||
do_test(data); | ||
} | ||
|
||
/// Method that needs to be added manually, {name}_run | ||
#[no_mangle] | ||
pub extern "C" fn process_network_graph_run(data: *const u8, datalen: usize) { | ||
do_test(unsafe { std::slice::from_raw_parts(data, datalen) }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "lightning-rapid-gossip-sync" | ||
version = "0.0.104" | ||
authors = ["Arik Sosman <[email protected]>"] | ||
license = "MIT OR Apache-2.0" | ||
repository = "https://github.com/lightningdevkit/rust-lightning" | ||
edition = "2018" | ||
description = """ | ||
Utility to process gossip routing data from Rapid Gossip Sync Server. | ||
""" | ||
|
||
[features] | ||
_bench_unstable = [] | ||
|
||
[dependencies] | ||
lightning = { version = "0.0.106", path = "../lightning" } | ||
bitcoin = { version = "0.28.1", default-features = false } | ||
|
||
[dev-dependencies] | ||
lightning = { version = "0.0.106", path = "../lightning", features = ["_test_utils"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
# lightning-rapid-gossip-sync | ||
|
||
This crate exposes functionality for rapid gossip graph syncing, aimed primarily at mobile clients. | ||
Its server counterpart is the | ||
[rapid-gossip-sync-server](https://github.com/lightningdevkit/rapid-gossip-sync-server) repository. | ||
|
||
## Mechanism | ||
|
||
The (presumed) server sends a compressed gossip response containing gossip data. The gossip data is | ||
formatted compactly, omitting signatures and opportunistically incremental where previous channel | ||
updates are known. | ||
|
||
Essentially, the serialization structure is as follows: | ||
|
||
1. Fixed prefix bytes `76, 68, 75, 1` (the first three bytes are ASCII for `LDK`) | ||
- The purpose of this prefix is to identify the serialization format, should other rapid gossip | ||
sync formats arise in the future | ||
- The fourth byte is the protocol version in case our format gets updated | ||
2. Chain hash (32 bytes) | ||
3. Latest seen timestamp (`u32`) | ||
4. An unsigned int indicating the number of node IDs to follow | ||
5. An array of compressed node ID pubkeys (all pubkeys are presumed to be standard | ||
compressed 33-byte-serializations) | ||
6. An unsigned int indicating the number of channel announcement messages to follow | ||
7. An array of significantly stripped down customized channel announcements | ||
8. An unsigned int indicating the number of channel update messages to follow | ||
9. A series of default values used for non-incremental channel updates | ||
- The values are defined as follows: | ||
1. `default_cltv_expiry_delta` | ||
2. `default_htlc_minimum_msat` | ||
3. `default_fee_base_msat` | ||
4. `default_fee_proportional_millionths` | ||
5. `default_htlc_maximum_msat` (`u64`, and if the default is no maximum, `u64::MAX`) | ||
- The defaults are calculated by the server based on the frequency among non-incremental | ||
updates within a given delta set | ||
10. An array of customized channel updates | ||
|
||
You will also notice that `NodeAnnouncement` messages are omitted altogether as the node IDs are | ||
implicitly extracted from the channel announcements and updates. | ||
|
||
The data is then applied to the current network graph, artificially dated to the timestamp of the | ||
latest seen message less one week, be it an announcement or an update, from the server's | ||
perspective. The network graph should not be pruned until the graph sync completes. | ||
|
||
### Custom Channel Announcement | ||
|
||
To achieve compactness and avoid data repetition, we're sending a significantly stripped down | ||
version of the channel announcement message, which contains only the following data: | ||
|
||
1. `channel_features`: `u16` + `n`, where `n` is the number of bytes indicated by the first `u16` | ||
2. `short_channel_id`: `CompactSize` (incremental `CompactSize` deltas starting from 0) | ||
3. `node_id_1_index`: `CompactSize` (index of node id within the previously sent sequence) | ||
4. `node_id_2_index`: `CompactSize` (index of node id within the previously sent sequence) | ||
|
||
### Custom Channel Update | ||
|
||
For the purpose of rapid syncing, we have deviated from the channel update format specified in | ||
BOLT 7 significantly. Our custom channel updates are structured as follows: | ||
|
||
1. `short_channel_id`: `CompactSize` (incremental `CompactSize` deltas starting at 0) | ||
2. `custom_channel_flags`: `u8` | ||
3. `update_data` | ||
|
||
Specifically, our custom channel flags break down like this: | ||
|
||
| 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | | ||
|---------------------|----|----|----|---|---|------------------|-----------| | ||
| Incremental update? | | | | | | Disable channel? | Direction | | ||
|
||
If the most significant bit is set to `1`, indicating an incremental update, the intermediate bit | ||
flags assume the following meaning: | ||
|
||
| 64 | 32 | 16 | 8 | 4 | | ||
|---------------------------------|---------------------------------|-----------------------------|-------------------------------------------|---------------------------------| | ||
| `cltv_expiry_delta` has changed | `htlc_minimum_msat` has changed | `fee_base_msat` has changed | `fee_proportional_millionths` has changed | `htlc_maximum_msat` has changed | | ||
|
||
If the most significant bit is set to `0`, the meaning is almost identical, except instead of a | ||
change, the flags now represent a deviation from the defaults sent at the beginning of the update | ||
sequence. | ||
|
||
In both cases, `update_data` only contains the fields that are indicated by the channel flags to be | ||
non-default or to have mutated. | ||
|
||
## Delta Calculation | ||
|
||
The way a server is meant to calculate this rapid gossip sync data is by taking the latest time | ||
any change, be it either an announcement or an update, was seen. That timestamp is included in each | ||
rapid sync message, so all the client needs to do is cache one variable. | ||
|
||
If a particular channel update had never occurred before, the full update is sent. If a channel has | ||
had updates prior to the provided timestamp, the latest update prior to the timestamp is taken as a | ||
reference, and the delta is calculated against it. | ||
|
||
Depending on whether the rapid sync message is calculated on the fly or a snapshotted version is | ||
returned, intermediate changes between the latest update seen by the client and the latest update | ||
broadcast on the network may be taken into account when calculating the delta. | ||
|
||
## Performance | ||
|
||
Given the primary purpose of this utility is a faster graph sync, we thought it might be helpful to | ||
provide some examples of various delta sets. These examples were calculated as of May 19th 2022 | ||
with a network graph comprised of 80,000 channel announcements and 160,000 directed channel updates. | ||
|
||
| Full sync | | | ||
|-----------------------------|--------| | ||
| Message Length | 4.7 MB | | ||
| Gzipped Message Length | 2.0 MB | | ||
| Client-side Processing Time | 1.4 s | | ||
|
||
| Week-old sync | | | ||
|-----------------------------|--------| | ||
| Message Length | 2.7 MB | | ||
| Gzipped Message Length | 862 kB | | ||
| Client-side Processing Time | 907 ms | | ||
|
||
| Day-old sync | | | ||
|-----------------------------|---------| | ||
| Message Length | 191 kB | | ||
| Gzipped Message Length | 92.8 kB | | ||
| Client-side Processing Time | 196 ms | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
* | ||
!.gitignore |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
no idea what you mean? Clients have to store the full graph, not just one variable?