Skip to content

Commit a403bf9

Browse files
committed
lightning-block-sync: Implement ser. logic for header Cache types
During syncing, `lightning-block-sync` populates as a block header `Cache` that is crucial to be able to disconnected previously-connected headers cleanly in case of a reorg. Moreover, the `Cache` can have performance benefits as subsequently synced listeners might not necessarily need to lookup all headers again from the chain source. While this `Cache` is ~crucial to the clean operation of `lightning-block-sync`, it was previously not possible to persist it to disk due to an absence of serialization logic implementations for the corresponding sub-types. Here, we do just that (Implement said serialization logic) to allow users to persist the `Cache`. Making use of the serialization logic for all the sub-types, we also switch the `UnboundedCache` type to be a newtype wrapper around a `HashMap` (rather than a straight typedef) and implement TLV-based serialization logic on it.
1 parent 1b281f1 commit a403bf9

File tree

6 files changed

+64
-12
lines changed

6 files changed

+64
-12
lines changed

lightning-block-sync/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ rpc-client = [ "serde_json", "chunked_transfer" ]
2020
[dependencies]
2121
bitcoin = "0.32.2"
2222
lightning = { version = "0.2.0", path = "../lightning" }
23+
lightning-macros = { version = "0.2", path = "../lightning-macros" }
2324
tokio = { version = "1.35", features = [ "io-util", "net", "time", "rt" ], optional = true }
2425
serde_json = { version = "1.0", optional = true }
2526
chunked_transfer = { version = "1.4", optional = true }

lightning-block-sync/src/init.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,8 @@ mod tests {
321321
(fork_chain_3.tip().block_hash, &listener_3 as &dyn chain::Listen),
322322
];
323323
let mut cache = fork_chain_1.header_cache(2..=4);
324-
cache.extend(fork_chain_2.header_cache(3..=4));
325-
cache.extend(fork_chain_3.header_cache(4..=4));
324+
cache.inner.extend(fork_chain_2.header_cache(3..=4).inner);
325+
cache.inner.extend(fork_chain_3.header_cache(4..=4).inner);
326326
match synchronize_listeners(&main_chain, Network::Bitcoin, &mut cache, listeners).await {
327327
Ok(header) => assert_eq!(header, main_chain.tip()),
328328
Err(e) => panic!("Unexpected error: {:?}", e),
@@ -364,8 +364,8 @@ mod tests {
364364
(fork_chain_3.tip().block_hash, &listener_3 as &dyn chain::Listen),
365365
];
366366
let mut cache = fork_chain_1.header_cache(2..=4);
367-
cache.extend(fork_chain_2.header_cache(3..=4));
368-
cache.extend(fork_chain_3.header_cache(4..=4));
367+
cache.inner.extend(fork_chain_2.header_cache(3..=4).inner);
368+
cache.inner.extend(fork_chain_3.header_cache(4..=4).inner);
369369
match synchronize_listeners(&main_chain, Network::Bitcoin, &mut cache, listeners).await {
370370
Ok(header) => assert_eq!(header, main_chain.tip()),
371371
Err(e) => panic!("Unexpected error: {:?}", e),
@@ -387,8 +387,8 @@ mod tests {
387387
let mut cache = fork_chain.header_cache(2..=2);
388388
match synchronize_listeners(&main_chain, Network::Bitcoin, &mut cache, listeners).await {
389389
Ok(_) => {
390-
assert!(cache.contains_key(&new_tip.block_hash));
391-
assert!(cache.contains_key(&old_tip.block_hash));
390+
assert!(cache.inner.contains_key(&new_tip.block_hash));
391+
assert!(cache.inner.contains_key(&old_tip.block_hash));
392392
},
393393
Err(e) => panic!("Unexpected error: {:?}", e),
394394
}

lightning-block-sync/src/lib.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ use bitcoin::block::{Block, Header};
4848
use bitcoin::hash_types::BlockHash;
4949
use bitcoin::pow::Work;
5050

51-
use lightning::chain;
5251
use lightning::chain::Listen;
52+
use lightning::util::hash_tables::{new_hash_map, HashMap};
53+
use lightning::{chain, impl_writeable_tlv_based};
5354

5455
use std::future::Future;
5556
use std::ops::Deref;
@@ -155,6 +156,12 @@ pub struct BlockHeaderData {
155156
pub chainwork: Work,
156157
}
157158

159+
impl_writeable_tlv_based!(BlockHeaderData, {
160+
(0, header, required),
161+
(2, height, required),
162+
(2, chainwork, required),
163+
});
164+
158165
/// A block including either all its transactions or only the block header.
159166
///
160167
/// [`BlockSource`] may be implemented to either always return full blocks or, in the case of
@@ -212,22 +219,36 @@ pub trait Cache {
212219
}
213220

214221
/// Unbounded cache of block headers keyed by block hash.
215-
pub type UnboundedCache = std::collections::HashMap<BlockHash, ValidatedBlockHeader>;
222+
pub struct UnboundedCache {
223+
pub(crate) inner: HashMap<BlockHash, ValidatedBlockHeader>,
224+
}
225+
226+
impl UnboundedCache {
227+
/// Returns a new `UnboundedCache`
228+
pub fn new() -> Self {
229+
let inner = new_hash_map();
230+
Self { inner }
231+
}
232+
}
216233

217234
impl Cache for UnboundedCache {
218235
fn look_up(&self, block_hash: &BlockHash) -> Option<&ValidatedBlockHeader> {
219-
self.get(block_hash)
236+
self.inner.get(block_hash)
220237
}
221238

222239
fn block_connected(&mut self, block_hash: BlockHash, block_header: ValidatedBlockHeader) {
223-
self.insert(block_hash, block_header);
240+
self.inner.insert(block_hash, block_header);
224241
}
225242

226243
fn block_disconnected(&mut self, block_hash: &BlockHash) -> Option<ValidatedBlockHeader> {
227-
self.remove(block_hash)
244+
self.inner.remove(block_hash)
228245
}
229246
}
230247

248+
impl_writeable_tlv_based!(UnboundedCache, {
249+
(0, inner, required),
250+
});
251+
231252
impl<'a, P: Poll, C: Cache, L: Deref> SpvClient<'a, P, C, L>
232253
where
233254
L::Target: chain::Listen,

lightning-block-sync/src/poll.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use crate::{
77

88
use bitcoin::hash_types::BlockHash;
99
use bitcoin::network::Network;
10+
1011
use lightning::chain::BestBlock;
12+
use lightning::impl_writeable_tlv_based;
1113

1214
use std::ops::Deref;
1315

@@ -171,6 +173,11 @@ impl ValidatedBlockHeader {
171173
}
172174
}
173175

176+
impl_writeable_tlv_based!(ValidatedBlockHeader, {
177+
(0, block_hash, required),
178+
(2, inner, required),
179+
});
180+
174181
/// A block with validated data against its transaction list and corresponding block hash.
175182
pub struct ValidatedBlock {
176183
pub(crate) block_hash: BlockHash,

lightning-block-sync/src/test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl Blockchain {
131131
for i in heights {
132132
let value = self.at_height(i);
133133
let key = value.header.block_hash();
134-
assert!(cache.insert(key, value).is_none());
134+
assert!(cache.inner.insert(key, value).is_none());
135135
}
136136
cache
137137
}

lightning/src/util/ser.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ use core::ops::Deref;
2424
use alloc::collections::BTreeMap;
2525

2626
use bitcoin::amount::Amount;
27+
use bitcoin::block::Header;
2728
use bitcoin::consensus::Encodable;
2829
use bitcoin::constants::ChainHash;
2930
use bitcoin::hash_types::{BlockHash, Txid};
3031
use bitcoin::hashes::hmac::Hmac;
3132
use bitcoin::hashes::sha256::Hash as Sha256;
3233
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
34+
use bitcoin::pow::Work;
3335
use bitcoin::script::{self, ScriptBuf};
3436
use bitcoin::secp256k1::constants::{
3537
COMPACT_SIGNATURE_SIZE, PUBLIC_KEY_SIZE, SCHNORR_SIGNATURE_SIZE, SECRET_KEY_SIZE,
@@ -1220,6 +1222,26 @@ impl Readable for Sha256dHash {
12201222
}
12211223
}
12221224

1225+
const WORK_SIZE: usize = 32;
1226+
1227+
impl Writeable for Work {
1228+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1229+
self.to_be_bytes().write(w)
1230+
}
1231+
1232+
#[inline]
1233+
fn serialized_length(&self) -> usize {
1234+
WORK_SIZE
1235+
}
1236+
}
1237+
1238+
impl Readable for Work {
1239+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1240+
let buf: [u8; WORK_SIZE] = Readable::read(r)?;
1241+
Ok(Work::from_be_bytes(buf))
1242+
}
1243+
}
1244+
12231245
impl Writeable for ecdsa::Signature {
12241246
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
12251247
self.serialize_compact().write(w)
@@ -1429,6 +1451,7 @@ macro_rules! impl_consensus_ser {
14291451
}
14301452
};
14311453
}
1454+
impl_consensus_ser!(Header);
14321455
impl_consensus_ser!(Transaction);
14331456
impl_consensus_ser!(TxOut);
14341457
impl_consensus_ser!(Witness);

0 commit comments

Comments
 (0)