Skip to content

Commit e104c21

Browse files
authored
Merge pull request #70 from tnull/2023-04-add-rgs-support
Implement configurable `GossipSource` to allow RGS gossip updates
2 parents 02a4b08 + f3aeeee commit e104c21

File tree

8 files changed

+315
-43
lines changed

8 files changed

+315
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ categories = ["cryptography::cryptocurrencies"]
1414
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1515

1616
[lib]
17-
crate-type = ["staticlib", "cdylib"]
17+
crate-type = ["lib", "staticlib", "cdylib"]
1818
name = "ldk_node"
1919

2020
[[bin]]

bindings/ldk_node.udl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ enum NodeError {
7777
"WalletOperationFailed",
7878
"WalletSigningFailed",
7979
"TxSyncFailed",
80+
"GossipUpdateFailed",
8081
"InvalidAddress",
8182
"InvalidPublicKey",
8283
"InvalidPaymentHash",

src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub enum Error {
2929
WalletSigningFailed,
3030
/// A transaction sync operation failed.
3131
TxSyncFailed,
32+
/// A gossip updating operation failed.
33+
GossipUpdateFailed,
3234
/// The given address is invalid.
3335
InvalidAddress,
3436
/// The given public key is invalid.
@@ -71,6 +73,7 @@ impl fmt::Display for Error {
7173
Self::WalletOperationFailed => write!(f, "Failed to conduct wallet operation."),
7274
Self::WalletSigningFailed => write!(f, "Failed to sign given transaction."),
7375
Self::TxSyncFailed => write!(f, "Failed to sync transactions."),
76+
Self::GossipUpdateFailed => write!(f, "Failed to update gossip data."),
7477
Self::InvalidAddress => write!(f, "The given address is invalid."),
7578
Self::InvalidPublicKey => write!(f, "The given public key is invalid."),
7679
Self::InvalidPaymentHash => write!(f, "The given payment hash is invalid."),

src/gossip.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use crate::logger::{log_trace, FilesystemLogger, Logger};
2+
use crate::types::{GossipSync, NetworkGraph, P2PGossipSync, RapidGossipSync};
3+
use crate::Error;
4+
5+
use lightning::routing::utxo::UtxoLookup;
6+
7+
use std::sync::atomic::{AtomicU32, Ordering};
8+
use std::sync::Arc;
9+
10+
pub(crate) enum GossipSource {
11+
P2PNetwork {
12+
gossip_sync: Arc<P2PGossipSync>,
13+
},
14+
RapidGossipSync {
15+
gossip_sync: Arc<RapidGossipSync>,
16+
server_url: String,
17+
latest_sync_timestamp: AtomicU32,
18+
logger: Arc<FilesystemLogger>,
19+
},
20+
}
21+
22+
impl GossipSource {
23+
pub fn new_p2p(network_graph: Arc<NetworkGraph>, logger: Arc<FilesystemLogger>) -> Self {
24+
let gossip_sync = Arc::new(P2PGossipSync::new(
25+
network_graph,
26+
None::<Arc<dyn UtxoLookup + Send + Sync>>,
27+
logger,
28+
));
29+
Self::P2PNetwork { gossip_sync }
30+
}
31+
32+
pub fn new_rgs(
33+
server_url: String, latest_sync_timestamp: u32, network_graph: Arc<NetworkGraph>,
34+
logger: Arc<FilesystemLogger>,
35+
) -> Self {
36+
let gossip_sync = Arc::new(RapidGossipSync::new(network_graph, Arc::clone(&logger)));
37+
let latest_sync_timestamp = AtomicU32::new(latest_sync_timestamp);
38+
Self::RapidGossipSync { gossip_sync, server_url, latest_sync_timestamp, logger }
39+
}
40+
41+
pub fn is_rgs(&self) -> bool {
42+
if let Self::RapidGossipSync { .. } = self {
43+
true
44+
} else {
45+
false
46+
}
47+
}
48+
49+
pub fn as_gossip_sync(&self) -> GossipSync {
50+
match self {
51+
Self::RapidGossipSync { gossip_sync, .. } => {
52+
GossipSync::Rapid(Arc::clone(&gossip_sync))
53+
}
54+
Self::P2PNetwork { gossip_sync, .. } => GossipSync::P2P(Arc::clone(&gossip_sync)),
55+
}
56+
}
57+
58+
pub async fn update_rgs_snapshot(&self) -> Result<u32, Error> {
59+
match self {
60+
Self::P2PNetwork { gossip_sync: _ } => Ok(0),
61+
Self::RapidGossipSync { gossip_sync, server_url, latest_sync_timestamp, logger } => {
62+
let query_timestamp = latest_sync_timestamp.load(Ordering::Acquire);
63+
let query_url = format!("{}/{}", server_url, query_timestamp);
64+
let response = reqwest::get(query_url).await.map_err(|e| {
65+
log_trace!(logger, "Failed to retrieve RGS gossip update: {}", e);
66+
Error::GossipUpdateFailed
67+
})?;
68+
69+
match response.error_for_status() {
70+
Ok(res) => {
71+
let update_data = res.bytes().await.map_err(|e| {
72+
log_trace!(logger, "Failed to retrieve RGS gossip update: {}", e);
73+
Error::GossipUpdateFailed
74+
})?;
75+
76+
let new_latest_sync_timestamp = gossip_sync
77+
.update_network_graph(&update_data)
78+
.map_err(|_| Error::GossipUpdateFailed)?;
79+
latest_sync_timestamp.store(new_latest_sync_timestamp, Ordering::Release);
80+
Ok(new_latest_sync_timestamp)
81+
}
82+
Err(e) => {
83+
log_trace!(logger, "Failed to retrieve RGS gossip update: {}", e);
84+
Err(Error::GossipUpdateFailed)
85+
}
86+
}
87+
}
88+
}
89+
}
90+
}

src/io/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ pub(crate) const PEER_INFO_PERSISTENCE_KEY: &str = "peers";
2626
/// The payment information will be persisted under this prefix.
2727
pub(crate) const PAYMENT_INFO_PERSISTENCE_NAMESPACE: &str = "payments";
2828

29+
/// RapidGossipSync's `latest_sync_timestamp` will be persisted under this key.
30+
pub(crate) const RGS_LATEST_SYNC_TIMESTAMP_NAMESPACE: &str = "";
31+
pub(crate) const RGS_LATEST_SYNC_TIMESTAMP_KEY: &str = "rgs_latest_sync_timestamp";
32+
2933
/// Provides an interface that allows to store and retrieve persisted values that are associated
3034
/// with given keys.
3135
///

src/io/utils.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use super::*;
22
use crate::WALLET_KEYS_SEED_LEN;
33

4+
use crate::logger::log_error;
45
use crate::peer_store::PeerStore;
5-
use crate::{EventQueue, PaymentDetails};
6+
use crate::{Error, EventQueue, PaymentDetails};
67

78
use lightning::chain::channelmonitor::ChannelMonitor;
89
use lightning::chain::keysinterface::{EntropySource, SignerProvider};
910
use lightning::routing::gossip::NetworkGraph;
1011
use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
1112
use lightning::util::logger::Logger;
12-
use lightning::util::ser::{Readable, ReadableArgs};
13+
use lightning::util::ser::{Readable, ReadableArgs, Writeable};
1314

1415
use bitcoin::hash_types::{BlockHash, Txid};
1516
use bitcoin::hashes::hex::FromHex;
@@ -172,3 +173,58 @@ where
172173
}
173174
Ok(res)
174175
}
176+
177+
pub(crate) fn read_rgs_latest_sync_timestamp<K: Deref>(kv_store: K) -> Result<u32, std::io::Error>
178+
where
179+
K::Target: KVStore,
180+
{
181+
let mut reader =
182+
kv_store.read(RGS_LATEST_SYNC_TIMESTAMP_NAMESPACE, RGS_LATEST_SYNC_TIMESTAMP_KEY)?;
183+
u32::read(&mut reader).map_err(|_| {
184+
std::io::Error::new(
185+
std::io::ErrorKind::InvalidData,
186+
"Failed to deserialize latest RGS sync timestamp",
187+
)
188+
})
189+
}
190+
191+
pub(crate) fn write_rgs_latest_sync_timestamp<K: Deref, L: Deref>(
192+
updated_timestamp: u32, kv_store: K, logger: L,
193+
) -> Result<(), Error>
194+
where
195+
K::Target: KVStore,
196+
L::Target: Logger,
197+
{
198+
let mut writer = kv_store
199+
.write(RGS_LATEST_SYNC_TIMESTAMP_NAMESPACE, RGS_LATEST_SYNC_TIMESTAMP_KEY)
200+
.map_err(|e| {
201+
log_error!(
202+
logger,
203+
"Getting writer for key {}/{} failed due to: {}",
204+
RGS_LATEST_SYNC_TIMESTAMP_NAMESPACE,
205+
RGS_LATEST_SYNC_TIMESTAMP_KEY,
206+
e
207+
);
208+
Error::PersistenceFailed
209+
})?;
210+
updated_timestamp.write(&mut writer).map_err(|e| {
211+
log_error!(
212+
logger,
213+
"Writing data to key {}/{} failed due to: {}",
214+
RGS_LATEST_SYNC_TIMESTAMP_NAMESPACE,
215+
RGS_LATEST_SYNC_TIMESTAMP_KEY,
216+
e
217+
);
218+
Error::PersistenceFailed
219+
})?;
220+
writer.commit().map_err(|e| {
221+
log_error!(
222+
logger,
223+
"Committing data to key {}/{} failed due to: {}",
224+
RGS_LATEST_SYNC_TIMESTAMP_NAMESPACE,
225+
RGS_LATEST_SYNC_TIMESTAMP_KEY,
226+
e
227+
);
228+
Error::PersistenceFailed
229+
})
230+
}

0 commit comments

Comments
 (0)