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.
This commit is contained in:
Jeffrey Czyz 2021-01-11 10:50:54 -08:00
parent e4b516dd8a
commit 9860646e73
No known key found for this signature in database
GPG Key ID: 3A4E08275D5E96D2
4 changed files with 156 additions and 1 deletions

View File

@ -13,7 +13,7 @@ jobs:
1.30.0,
# 1.34.2 is Debian stable
1.34.2,
# 1.45.2 is MSRV for lightning-net-tokio and generates coverage
# 1.45.2 is MSRV for lightning-net-tokio, lightning-block-sync, and coverage generation
1.45.2]
include:
- toolchain: stable
@ -48,6 +48,24 @@ jobs:
- name: Build on Rust ${{ matrix.toolchain }}
if: "! matrix.build-net-tokio"
run: cargo build --verbose --color always -p lightning
- name: Build Block Sync Clients on Rust ${{ matrix.toolchain }} with features
if: "matrix.build-net-tokio && !matrix.coverage"
run: |
cd lightning-block-sync
cargo build --verbose --color always --features rest-client
cargo build --verbose --color always --features rpc-client
cargo build --verbose --color always --features rpc-client,rest-client
cargo build --verbose --color always --features rpc-client,rest-client,tokio
cd ..
- name: Build Block Sync Clients on Rust ${{ matrix.toolchain }} with features and full code-linking for coverage generation
if: matrix.coverage
run: |
cd lightning-block-sync
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rest-client
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rpc-client
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rpc-client,rest-client
RUSTFLAGS="-C link-dead-code" cargo build --verbose --color always --features rpc-client,rest-client,tokio
cd ..
- name: Test on Rust ${{ matrix.toolchain }} with net-tokio
if: "matrix.build-net-tokio && !matrix.coverage"
run: cargo test --verbose --color always
@ -57,6 +75,24 @@ jobs:
- name: Test on Rust ${{ matrix.toolchain }}
if: "! matrix.build-net-tokio"
run: cargo test --verbose --color always -p lightning
- name: Test Block Sync Clients on Rust ${{ matrix.toolchain }} with features
if: "matrix.build-net-tokio && !matrix.coverage"
run: |
cd lightning-block-sync
cargo test --verbose --color always --features rest-client
cargo test --verbose --color always --features rpc-client
cargo test --verbose --color always --features rpc-client,rest-client
cargo test --verbose --color always --features rpc-client,rest-client,tokio
cd ..
- name: Test Block Sync Clients on Rust ${{ matrix.toolchain }} with features and full code-linking for coverage generation
if: matrix.coverage
run: |
cd lightning-block-sync
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rest-client
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rpc-client
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rpc-client,rest-client
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --features rpc-client,rest-client,tokio
cd ..
- name: Install deps for kcov
if: matrix.coverage
run: |

View File

@ -2,6 +2,7 @@
members = [
"lightning",
"lightning-block-sync",
"lightning-net-tokio",
"lightning-persister",
]

View File

@ -0,0 +1,13 @@
[package]
name = "lightning-block-sync"
version = "0.0.1"
authors = ["Jeffrey Czyz", "Matt Corallo"]
license = "Apache-2.0"
edition = "2018"
description = """
Utilities to fetch the chain data from a block source and feed them into Rust Lightning.
"""
[dependencies]
bitcoin = "0.24"
lightning = { version = "0.0.12", path = "../lightning" }

View File

@ -0,0 +1,105 @@
//! A lightweight client for keeping in sync with chain activity.
//!
//! Defines a [`BlockSource`] trait, which is an asynchronous interface for retrieving block headers
//! and data.
//!
//! [`BlockSource`]: trait.BlockSource.html
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::hash_types::BlockHash;
use bitcoin::util::uint::Uint256;
use std::future::Future;
use std::pin::Pin;
/// Abstract type for retrieving block headers and data.
pub trait BlockSource : Sync + Send {
/// Returns the header for a given hash. A height hint may be provided in case a block source
/// cannot easily find headers based on a hash. This is merely a hint and thus the returned
/// header must have the same hash as was requested. Otherwise, an error must be returned.
///
/// Implementations that cannot find headers based on the hash should return a `Transient` error
/// when `height_hint` is `None`.
fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, height_hint: Option<u32>) -> AsyncBlockSourceResult<'a, BlockHeaderData>;
/// Returns the block for a given hash. A headers-only block source should return a `Transient`
/// error.
fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block>;
// TODO: Phrase in terms of `Poll` once added.
/// Returns the hash of the best block and, optionally, its height. When polling a block source,
/// the height is passed to `get_header` to allow for a more efficient lookup.
fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<(BlockHash, Option<u32>)>;
}
/// Result type for `BlockSource` requests.
type BlockSourceResult<T> = Result<T, BlockSourceError>;
// TODO: Replace with BlockSourceResult once `async` trait functions are supported. For details,
// see: https://areweasyncyet.rs.
/// Result type for asynchronous `BlockSource` requests.
type AsyncBlockSourceResult<'a, T> = Pin<Box<dyn Future<Output = BlockSourceResult<T>> + 'a + Send>>;
/// Error type for `BlockSource` requests.
///
/// Transient errors may be resolved when re-polling, but no attempt will be made to re-poll on
/// persistent errors.
pub struct BlockSourceError {
kind: BlockSourceErrorKind,
error: Box<dyn std::error::Error + Send + Sync>,
}
/// The kind of `BlockSourceError`, either persistent or transient.
#[derive(Clone, Copy)]
pub enum BlockSourceErrorKind {
/// Indicates an error that won't resolve when retrying a request (e.g., invalid data).
Persistent,
/// Indicates an error that may resolve when retrying a request (e.g., unresponsive).
Transient,
}
impl BlockSourceError {
/// Creates a new persistent error originated from the given error.
pub fn persistent<E>(error: E) -> Self
where E: Into<Box<dyn std::error::Error + Send + Sync>> {
Self {
kind: BlockSourceErrorKind::Persistent,
error: error.into(),
}
}
/// Creates a new transient error originated from the given error.
pub fn transient<E>(error: E) -> Self
where E: Into<Box<dyn std::error::Error + Send + Sync>> {
Self {
kind: BlockSourceErrorKind::Transient,
error: error.into(),
}
}
/// Returns the kind of error.
pub fn kind(&self) -> BlockSourceErrorKind {
self.kind
}
/// Converts the error into the underlying error.
pub fn into_inner(self) -> Box<dyn std::error::Error + Send + Sync> {
self.error
}
}
/// A block header and some associated data. This information should be available from most block
/// sources (and, notably, is available in Bitcoin Core's RPC and REST interfaces).
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BlockHeaderData {
/// The block header itself.
pub header: BlockHeader,
/// The block height where the genesis block has height 0.
pub height: u32,
/// The total chain work in expected number of double-SHA256 hashes required to build a chain
/// of equivalent weight.
pub chainwork: Uint256,
}