Skip to content

Commit ca24a9e

Browse files
committed
Create first unit test.
1 parent a615a39 commit ca24a9e

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed

src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ mod verifier;
3939

4040
pub mod types;
4141

42+
#[cfg(test)]
43+
mod tests;
44+
4245
/// The purpose of this prefix is to identify the serialization format, should other rapid gossip
4346
/// sync formats arise in the future.
4447
///

src/tests/mod.rs

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//! Multi-module tests that use database fixtures
2+
3+
use std::sync::Arc;
4+
use std::time::{SystemTime, UNIX_EPOCH};
5+
use bitcoin::{BlockHash, Network};
6+
use bitcoin::secp256k1::ecdsa::Signature;
7+
use bitcoin::secp256k1::{Secp256k1, SecretKey};
8+
use bitcoin::hashes::Hash;
9+
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
10+
use lightning::ln::features::ChannelFeatures;
11+
use lightning::ln::msgs::{ChannelAnnouncement, ChannelUpdate, UnsignedChannelAnnouncement, UnsignedChannelUpdate};
12+
use lightning::routing::gossip::{NetworkGraph, NodeId};
13+
use lightning::util::ser::Writeable;
14+
use lightning_rapid_gossip_sync::RapidGossipSync;
15+
use tokio_postgres::NoTls;
16+
use crate::{config, serialize_delta};
17+
use crate::persistence::GossipPersister;
18+
use crate::types::{GossipMessage, tests::TestLogger};
19+
20+
const CLIENT_BACKDATE_INTERVAL: u32 = 3600 * 24 * 7; // client backdates RGS by a week
21+
22+
fn blank_signature() -> Signature {
23+
Signature::from_compact(&[0u8; 64]).unwrap()
24+
}
25+
26+
fn genesis_hash() -> BlockHash {
27+
bitcoin::blockdata::constants::genesis_block(Network::Bitcoin).block_hash()
28+
}
29+
30+
fn current_time() -> u32 {
31+
SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() as u32
32+
}
33+
34+
fn generate_announcement(short_channel_id: u64) -> ChannelAnnouncement {
35+
let secp_context = Secp256k1::new();
36+
37+
let random_private_key_1 = SecretKey::from_slice(&[1; 32]).unwrap();
38+
let random_public_key_1 = random_private_key_1.public_key(&secp_context);
39+
let node_id_1 = NodeId::from_pubkey(&random_public_key_1);
40+
41+
let random_private_key_2 = SecretKey::from_slice(&[2; 32]).unwrap();
42+
let random_public_key_2 = random_private_key_2.public_key(&secp_context);
43+
let node_id_2 = NodeId::from_pubkey(&random_public_key_2);
44+
45+
let announcement = UnsignedChannelAnnouncement {
46+
features: ChannelFeatures::empty(),
47+
chain_hash: genesis_hash(),
48+
short_channel_id,
49+
node_id_1,
50+
node_id_2,
51+
bitcoin_key_1: node_id_1,
52+
bitcoin_key_2: node_id_2,
53+
excess_data: vec![],
54+
};
55+
56+
let msg_hash = bitcoin::secp256k1::Message::from_slice(&Sha256dHash::hash(&announcement.encode()[..])[..]).unwrap();
57+
let node_signature_1 = secp_context.sign_ecdsa(&msg_hash, &random_private_key_1);
58+
let node_signature_2 = secp_context.sign_ecdsa(&msg_hash, &random_private_key_2);
59+
60+
ChannelAnnouncement {
61+
node_signature_1,
62+
node_signature_2,
63+
bitcoin_signature_1: node_signature_1,
64+
bitcoin_signature_2: node_signature_2,
65+
contents: announcement,
66+
}
67+
}
68+
69+
fn generate_update(scid: u64, direction: bool, timestamp: u32, expiry_delta: u16, min_msat: u64, max_msat: u64, base_msat: u32, fee_rate: u32) -> ChannelUpdate {
70+
let flag_mask = if direction { 1 } else { 0 };
71+
ChannelUpdate {
72+
signature: blank_signature(),
73+
contents: UnsignedChannelUpdate {
74+
chain_hash: genesis_hash(),
75+
short_channel_id: scid,
76+
timestamp,
77+
flags: 0 | flag_mask,
78+
cltv_expiry_delta: expiry_delta,
79+
htlc_minimum_msat: min_msat,
80+
htlc_maximum_msat: max_msat,
81+
fee_base_msat: base_msat,
82+
fee_proportional_millionths: fee_rate,
83+
excess_data: vec![],
84+
},
85+
}
86+
}
87+
88+
async fn clean_test_db() {
89+
let connection_config = config::db_connection_config();
90+
let (client, connection) = connection_config.connect(NoTls).await.unwrap();
91+
92+
tokio::spawn(async move {
93+
if let Err(e) = connection.await {
94+
panic!("connection error: {}", e);
95+
}
96+
});
97+
98+
client.query("TRUNCATE TABLE channel_announcements RESTART IDENTITY CASCADE", &[]).await.unwrap();
99+
client.query("TRUNCATE TABLE channel_updates RESTART IDENTITY CASCADE", &[]).await.unwrap();
100+
client.query("TRUNCATE TABLE config RESTART IDENTITY CASCADE", &[]).await.unwrap();
101+
}
102+
103+
#[tokio::test]
104+
async fn test_trivial_setup() {
105+
// start off with a clean slate
106+
clean_test_db().await;
107+
108+
let logger = Arc::new(TestLogger::new());
109+
let network_graph = NetworkGraph::new(Network::Bitcoin, logger.clone());
110+
let network_graph_arc = Arc::new(network_graph);
111+
let (mut persister, receiver) = GossipPersister::new(network_graph_arc.clone(), logger.clone());
112+
113+
let short_channel_id = 1;
114+
let timestamp = current_time() - 10;
115+
println!("timestamp: {}", timestamp);
116+
117+
{ // seed the db
118+
let announcement = generate_announcement(short_channel_id);
119+
let update_1 = generate_update(short_channel_id, false, timestamp, 0, 0, 0, 5, 0);
120+
let update_2 = generate_update(short_channel_id, true, timestamp, 0, 0, 0, 10, 0);
121+
122+
network_graph_arc.update_channel_from_announcement_no_lookup(&announcement).unwrap();
123+
network_graph_arc.update_channel_unsigned(&update_1.contents).unwrap();
124+
network_graph_arc.update_channel_unsigned(&update_2.contents).unwrap();
125+
126+
receiver.send(GossipMessage::ChannelAnnouncement(announcement)).await.unwrap();
127+
receiver.send(GossipMessage::ChannelUpdate(update_1)).await.unwrap();
128+
receiver.send(GossipMessage::ChannelUpdate(update_2)).await.unwrap();
129+
drop(receiver);
130+
persister.persist_gossip().await;
131+
}
132+
133+
let serialization = serialize_delta(network_graph_arc.clone(), 0, logger.clone()).await;
134+
logger.assert_log_contains("rapid_gossip_sync_server", "announcement channel count: 1", 1);
135+
clean_test_db().await;
136+
137+
let channel_count = network_graph_arc.read_only().channels().len();
138+
139+
assert_eq!(channel_count, 1);
140+
assert_eq!(serialization.message_count, 3);
141+
assert_eq!(serialization.announcement_count, 1);
142+
assert_eq!(serialization.update_count, 2);
143+
144+
let client_graph = NetworkGraph::new(Network::Bitcoin, logger.clone());
145+
let client_graph_arc = Arc::new(client_graph);
146+
let rgs = RapidGossipSync::new(client_graph_arc.clone(), logger.clone());
147+
let update_result = rgs.update_network_graph(&serialization.data).unwrap();
148+
println!("update result: {}", update_result);
149+
// the update result must be a multiple of our snapshot granularity
150+
assert_eq!(update_result % config::SNAPSHOT_CALCULATION_INTERVAL, 0);
151+
assert!(update_result < timestamp);
152+
153+
let timestamp_delta = timestamp - update_result;
154+
println!("timestamp delta: {}", timestamp_delta);
155+
assert!(timestamp_delta < config::SNAPSHOT_CALCULATION_INTERVAL);
156+
157+
let readonly_graph = client_graph_arc.read_only();
158+
let channels = readonly_graph.channels();
159+
let client_channel_count = channels.len();
160+
assert_eq!(client_channel_count, 1);
161+
162+
let first_channel = channels.get(&short_channel_id).unwrap();
163+
assert!(&first_channel.announcement_message.is_none());
164+
assert_eq!(first_channel.one_to_two.as_ref().unwrap().fees.base_msat, 5);
165+
assert_eq!(first_channel.two_to_one.as_ref().unwrap().fees.base_msat, 10);
166+
let last_update_seen_a = first_channel.one_to_two.as_ref().unwrap().last_update;
167+
let last_update_seen_b = first_channel.two_to_one.as_ref().unwrap().last_update;
168+
println!("last update a: {}", last_update_seen_a);
169+
println!("last update b: {}", last_update_seen_b);
170+
assert_eq!(last_update_seen_a, update_result - CLIENT_BACKDATE_INTERVAL);
171+
assert_eq!(last_update_seen_b, update_result - CLIENT_BACKDATE_INTERVAL);
172+
}

0 commit comments

Comments
 (0)