Skip to content

Commit 9860646

Browse files
committed
Add lightning-block-sync package and library
Defines an interface and related types for fetching block headers and data from a block source (e.g., Bitcoin Core). Used to keep lightning in sync with chain activity.
1 parent e4b516d commit 9860646

File tree

4 files changed

+156
-1
lines changed

4 files changed

+156
-1
lines changed

.github/workflows/build.yml

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
1.30.0,
1414
# 1.34.2 is Debian stable
1515
1.34.2,
16-
# 1.45.2 is MSRV for lightning-net-tokio and generates coverage
16+
# 1.45.2 is MSRV for lightning-net-tokio, lightning-block-sync, and coverage generation
1717
1.45.2]
1818
include:
1919
- toolchain: stable
@@ -48,6 +48,24 @@ jobs:
4848
- name: Build on Rust ${{ matrix.toolchain }}
4949
if: "! matrix.build-net-tokio"
5050
run: cargo build --verbose --color always -p lightning
51+
- name: Build Block Sync Clients on Rust ${{ matrix.toolchain }} with features
52+
if: "matrix.build-net-tokio && !matrix.coverage"
53+
run: |
54+
cd lightning-block-sync
55+
cargo build --verbose --color always --features rest-client
56+
cargo build --verbose --color always --features rpc-client
57+
cargo build --verbose --color always --features rpc-client,rest-client
58+
cargo build --verbose --color always --features rpc-client,rest-client,tokio
59+
cd ..
60+
- name: Build Block Sync Clients on Rust ${{ matrix.toolchain }} with features and full code-linking for coverage generation
61+
if: matrix.coverage
62+
run: |
63+
cd lightning-block-sync
64+
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rest-client
65+
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rpc-client
66+
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rpc-client,rest-client
67+
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rpc-client,rest-client,tokio
68+
cd ..
5169
- name: Test on Rust ${{ matrix.toolchain }} with net-tokio
5270
if: "matrix.build-net-tokio && !matrix.coverage"
5371
run: cargo test --verbose --color always
@@ -57,6 +75,24 @@ jobs:
5775
- name: Test on Rust ${{ matrix.toolchain }}
5876
if: "! matrix.build-net-tokio"
5977
run: cargo test --verbose --color always -p lightning
78+
- name: Test Block Sync Clients on Rust ${{ matrix.toolchain }} with features
79+
if: "matrix.build-net-tokio && !matrix.coverage"
80+
run: |
81+
cd lightning-block-sync
82+
cargo test --verbose --color always --features rest-client
83+
cargo test --verbose --color always --features rpc-client
84+
cargo test --verbose --color always --features rpc-client,rest-client
85+
cargo test --verbose --color always --features rpc-client,rest-client,tokio
86+
cd ..
87+
- name: Test Block Sync Clients on Rust ${{ matrix.toolchain }} with features and full code-linking for coverage generation
88+
if: matrix.coverage
89+
run: |
90+
cd lightning-block-sync
91+
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rest-client
92+
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rpc-client
93+
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rpc-client,rest-client
94+
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rpc-client,rest-client,tokio
95+
cd ..
6096
- name: Install deps for kcov
6197
if: matrix.coverage
6298
run: |

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
members = [
44
"lightning",
5+
"lightning-block-sync",
56
"lightning-net-tokio",
67
"lightning-persister",
78
]

lightning-block-sync/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "lightning-block-sync"
3+
version = "0.0.1"
4+
authors = ["Jeffrey Czyz", "Matt Corallo"]
5+
license = "Apache-2.0"
6+
edition = "2018"
7+
description = """
8+
Utilities to fetch the chain data from a block source and feed them into Rust Lightning.
9+
"""
10+
11+
[dependencies]
12+
bitcoin = "0.24"
13+
lightning = { version = "0.0.12", path = "../lightning" }

lightning-block-sync/src/lib.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//! A lightweight client for keeping in sync with chain activity.
2+
//!
3+
//! Defines a [`BlockSource`] trait, which is an asynchronous interface for retrieving block headers
4+
//! and data.
5+
//!
6+
//! [`BlockSource`]: trait.BlockSource.html
7+
8+
use bitcoin::blockdata::block::{Block, BlockHeader};
9+
use bitcoin::hash_types::BlockHash;
10+
use bitcoin::util::uint::Uint256;
11+
12+
use std::future::Future;
13+
use std::pin::Pin;
14+
15+
/// Abstract type for retrieving block headers and data.
16+
pub trait BlockSource : Sync + Send {
17+
/// Returns the header for a given hash. A height hint may be provided in case a block source
18+
/// cannot easily find headers based on a hash. This is merely a hint and thus the returned
19+
/// header must have the same hash as was requested. Otherwise, an error must be returned.
20+
///
21+
/// Implementations that cannot find headers based on the hash should return a `Transient` error
22+
/// when `height_hint` is `None`.
23+
fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, height_hint: Option<u32>) -> AsyncBlockSourceResult<'a, BlockHeaderData>;
24+
25+
/// Returns the block for a given hash. A headers-only block source should return a `Transient`
26+
/// error.
27+
fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block>;
28+
29+
// TODO: Phrase in terms of `Poll` once added.
30+
/// Returns the hash of the best block and, optionally, its height. When polling a block source,
31+
/// the height is passed to `get_header` to allow for a more efficient lookup.
32+
fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<(BlockHash, Option<u32>)>;
33+
}
34+
35+
/// Result type for `BlockSource` requests.
36+
type BlockSourceResult<T> = Result<T, BlockSourceError>;
37+
38+
// TODO: Replace with BlockSourceResult once `async` trait functions are supported. For details,
39+
// see: https://areweasyncyet.rs.
40+
/// Result type for asynchronous `BlockSource` requests.
41+
type AsyncBlockSourceResult<'a, T> = Pin<Box<dyn Future<Output = BlockSourceResult<T>> + 'a + Send>>;
42+
43+
/// Error type for `BlockSource` requests.
44+
///
45+
/// Transient errors may be resolved when re-polling, but no attempt will be made to re-poll on
46+
/// persistent errors.
47+
pub struct BlockSourceError {
48+
kind: BlockSourceErrorKind,
49+
error: Box<dyn std::error::Error + Send + Sync>,
50+
}
51+
52+
/// The kind of `BlockSourceError`, either persistent or transient.
53+
#[derive(Clone, Copy)]
54+
pub enum BlockSourceErrorKind {
55+
/// Indicates an error that won't resolve when retrying a request (e.g., invalid data).
56+
Persistent,
57+
58+
/// Indicates an error that may resolve when retrying a request (e.g., unresponsive).
59+
Transient,
60+
}
61+
62+
impl BlockSourceError {
63+
/// Creates a new persistent error originated from the given error.
64+
pub fn persistent<E>(error: E) -> Self
65+
where E: Into<Box<dyn std::error::Error + Send + Sync>> {
66+
Self {
67+
kind: BlockSourceErrorKind::Persistent,
68+
error: error.into(),
69+
}
70+
}
71+
72+
/// Creates a new transient error originated from the given error.
73+
pub fn transient<E>(error: E) -> Self
74+
where E: Into<Box<dyn std::error::Error + Send + Sync>> {
75+
Self {
76+
kind: BlockSourceErrorKind::Transient,
77+
error: error.into(),
78+
}
79+
}
80+
81+
/// Returns the kind of error.
82+
pub fn kind(&self) -> BlockSourceErrorKind {
83+
self.kind
84+
}
85+
86+
/// Converts the error into the underlying error.
87+
pub fn into_inner(self) -> Box<dyn std::error::Error + Send + Sync> {
88+
self.error
89+
}
90+
}
91+
92+
/// A block header and some associated data. This information should be available from most block
93+
/// sources (and, notably, is available in Bitcoin Core's RPC and REST interfaces).
94+
#[derive(Clone, Copy, Debug, PartialEq)]
95+
pub struct BlockHeaderData {
96+
/// The block header itself.
97+
pub header: BlockHeader,
98+
99+
/// The block height where the genesis block has height 0.
100+
pub height: u32,
101+
102+
/// The total chain work in expected number of double-SHA256 hashes required to build a chain
103+
/// of equivalent weight.
104+
pub chainwork: Uint256,
105+
}

0 commit comments

Comments
 (0)