From df908d584c6488be7d60e47dc51c4d2dd2976d99 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 3 Feb 2021 12:21:59 -0800 Subject: [PATCH] Initial draft of blockchain data guide --- docs/assets/ldk-block-processing.svg | 1 + docs/blockdata.md | 187 ++++++++++++++++++++++++++- docusaurus.config.js | 3 + 3 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 docs/assets/ldk-block-processing.svg diff --git a/docs/assets/ldk-block-processing.svg b/docs/assets/ldk-block-processing.svg new file mode 100644 index 000000000..b0705f6d6 --- /dev/null +++ b/docs/assets/ldk-block-processing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/blockdata.md b/docs/blockdata.md index a6c58b92f..4a053d868 100644 --- a/docs/blockdata.md +++ b/docs/blockdata.md @@ -3,4 +3,189 @@ id: blockdata title: Blockchain Data --- -TODO +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Introduction + +In this guide, we'll explore how to provide chain data to LDK upon startup and +as new blocks are mined. This allows LDK to maintain channel state and monitor +for on-chain channel activity. + +## Overview + +LDK maintains channels with your node's peers during the course of node +operation. When a new channel is opened, the `ChannelManager` will keep track of +the channel's state and tell the `ChainMonitor` that a new channel should be +watched. The `ChainMonitor` does so by maintaining a `ChannelMonitor` for each +channel. + +When a new block is mined, it is connected to the chain while other blocks may +be disconnected. LDK will process such events as they are fed into it from a +`BlockSource` by: + +* Updating channel state +* Signaling back transactions to filter +* Broadcasting transactions if necessary + +We will walk through this process as depicted here: + +![LDK block processing](assets/ldk-block-processing.svg) + +## Block Source + +Initially, our node doesn't have any channels and hence has no data to monitor +for on-chain. When a channel is opened with a peer, the `ChannelManager` creates + a `ChannelMonitor` and passes it to the `ChainMonitor` to watch. + +At this point, LDK needs to be fed chain data of interest so that it can respond +accordingly. It supports receiving either full blocks or pre-filtered blocks. +Block data can sourced from anywhere, but it is your responsibility to ensure +that the necessary `block_connected` and `block_disconnected` methods are called +on `ChannelManager` and `ChainMonitor`. This allows them to update channel state +and respond to on-chain events, respectively. + +LDK comes with a `lightning-block-sync` utility that handles polling a block +source for the best chain tip, detecting chain forks, and notifying listeners +when blocks are connected and disconnected. It can be configured to: + +* Poll a custom `BlockSource` +* Notify `ChannelManager` and `ChainMonitor` of block events + +It is your choice as to whether you use this utility or your own to feed the +required chain data to LDK. If you choose to use it, you will need to implement +the `BlockSource` interface or use one of the samples that it provides. + +:::note +Currently, `lightning-block-sync` is only available in Rust. +::: + +Implementing the `BlockSource` interface requires defining methods for fetching +headers, blocks, and the best block hash. + + + + +```rust +impl BlockSource for Blockchain { + fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, _height: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { + // + } + + fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> { + // + } + + fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { + // + } +} +``` + + + + +```java +// TODO +``` + + + + +For instance, you may implement this interface by querying Bitcoin Core's JSON +RPC interface, which happens to be a sample implementation provided by +`lightning-block-sync`. + +Let's walk through the use case where LDK receives full blocks. + +### Full Blocks + +If your Lightning node is backed by a Bitcoin full node, the operation is +straight forward: call the appropriate methods on `ChannelManager` and +`ChainMonitor` as blocks are connected and disconnected. LDK will handle the +rest! + +So what happens? The `ChannelManager` examines the blocks transactions and +updates the internal channel state as needed. The `ChainMonitor` will detect +any spends of the channel funding transaction or any pertinent transaction +outputs, tracking them as necessary. + +If necessary, LDK will broadcast a transaction on your behalf. More on that +later. For now, let's look at the more interesting case of pre-filtered blocks. + +### Pre-filtered Blocks + +For environments that are resource constrained, receiving and processing all +transaction data may not be feasible. LDK handles this case by signaling back +which transactions and outputs it is interested in. This information can then be +used to filter blocks prior to sending them to your node. + +For example, if your block source is an Electrum client, you can pass along this +information to it. Or if you are making use of a BIP 157 client, you can check +if a block contains relevant transactions before fetching it. + +So how does this work in practice? `ChainMonitor` is parameterized by an +optional type that implements `chain::Filter`: + + + + +```rust +impl chain::Filter for Blockchain { + fn register_tx(&self, txid: &Txid, script_pubkey: &Script) { + // + } + + fn register_output(&self, outpoint: &OutPoint, script_pubkey: &Script) { + // + } +} +``` + + + + +```java +Filter tx_filter = Filter.new_impl(new Filter.FilterInterface() { + @Override + public void register_tx(byte[] txid, byte[] script_pubkey) { + // + } + + @Override + void register_output(OutPoint outpoint, byte[] script_pubkey) { + // + } +}); +``` + + + + +When this is provided, `ChainMonitor` will call back to the filter as channels +are opened and blocks connected. This gives the opportunity for the source to +pre-filter blocks as desired. + +Regardless, when a block is connected, its header must be processed by LDK. + +## Transaction Broadcast + +Inevitably, LDK will need to broadcast transactions on your behalf. As you +notify it of blocks, it will determine if it should broadcast a transaction and +do so using an implementation of `BroadcasterInterface` that you have provided. + +And as those transactions or those from your peers are confirmed on-chain, they +will be likewise processed when notified of a connected block. Thus, continuing +the cycle. diff --git a/docusaurus.config.js b/docusaurus.config.js index 7aaee803b..f5607635d 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -75,6 +75,9 @@ module.exports = { ], copyright: `Copyright © ${new Date().getFullYear()} Square Crypto, Inc.`, }, + prism: { + additionalLanguages: ['rust'], + }, }, presets: [ [