UNPKG

lightningdevkit

Version:
160 lines (159 loc) 9.17 kB
import { Logger } from '../structs/Logger.mjs'; import { BroadcasterInterface } from '../structs/BroadcasterInterface.mjs'; import { EntropySource } from '../structs/EntropySource.mjs'; import { SignerProvider } from '../structs/SignerProvider.mjs'; import { FeeEstimator } from '../structs/FeeEstimator.mjs'; import { Result_NoneIOErrorZ } from '../structs/Result_NoneIOErrorZ.mjs'; import { Result_CVec_C2Tuple_ThirtyTwoBytesChannelMonitorZZIOErrorZ } from '../structs/Result_CVec_C2Tuple_ThirtyTwoBytesChannelMonitorZZIOErrorZ.mjs'; import { Result_C2Tuple_ThirtyTwoBytesChannelMonitorZIOErrorZ } from '../structs/Result_C2Tuple_ThirtyTwoBytesChannelMonitorZIOErrorZ.mjs'; import { KVStore } from '../structs/KVStore.mjs'; import { Persist } from '../structs/Persist.mjs'; import { CommonBase } from './CommonBase.mjs'; /** * Implements [`Persist`] in a way that writes and reads both [`ChannelMonitor`]s and * [`ChannelMonitorUpdate`]s. * * # Overview * * The main benefit this provides over the [`KVStore`]'s [`Persist`] implementation is decreased * I/O bandwidth and storage churn, at the expense of more IOPS (including listing, reading, and * deleting) and complexity. This is because it writes channel monitor differential updates, * whereas the other (default) implementation rewrites the entire monitor on each update. For * routing nodes, updates can happen many times per second to a channel, and monitors can be tens * of megabytes (or more). Updates can be as small as a few hundred bytes. * * Note that monitors written with `MonitorUpdatingPersister` are _not_ backward-compatible with * the default [`KVStore`]'s [`Persist`] implementation. They have a prepended byte sequence, * [`MONITOR_UPDATING_PERSISTER_PREPEND_SENTINEL`], applied to prevent deserialization with other * persisters. This is because monitors written by this struct _may_ have unapplied updates. In * order to downgrade, you must ensure that all updates are applied to the monitor, and remove the * sentinel bytes. * * # Storing monitors * * Monitors are stored by implementing the [`Persist`] trait, which has two functions: * * - [`Persist::persist_new_channel`], which persists whole [`ChannelMonitor`]s. * - [`Persist::update_persisted_channel`], which persists only a [`ChannelMonitorUpdate`] * * Whole [`ChannelMonitor`]s are stored in the [`CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE`], * using the familiar encoding of an [`OutPoint`] (for example, `[SOME-64-CHAR-HEX-STRING]_1`). * * Each [`ChannelMonitorUpdate`] is stored in a dynamic secondary namespace, as follows: * * - primary namespace: [`CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE`] * - secondary namespace: [the monitor's encoded outpoint name] * * Under that secondary namespace, each update is stored with a number string, like `21`, which * represents its `update_id` value. * * For example, consider this channel, named for its transaction ID and index, or [`OutPoint`]: * * - Transaction ID: `deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef` * - Index: `1` * * Full channel monitors would be stored at a single key: * * `[CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE]/deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef_1` * * Updates would be stored as follows (with `/` delimiting primary_namespace/secondary_namespace/key): * * ```text * [CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE]/deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef_1/1 * [CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE]/deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef_1/2 * [CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE]/deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef_1/3 * ``` * ... and so on. * * # Reading channel state from storage * * Channel state can be reconstructed by calling * [`MonitorUpdatingPersister::read_all_channel_monitors_with_updates`]. Alternatively, users can * list channel monitors themselves and load channels individually using * [`MonitorUpdatingPersister::read_channel_monitor_with_updates`]. * * ## EXTREMELY IMPORTANT * * It is extremely important that your [`KVStore::read`] implementation uses the * [`io::ErrorKind::NotFound`] variant correctly: that is, when a file is not found, and _only_ in * that circumstance (not when there is really a permissions error, for example). This is because * neither channel monitor reading function lists updates. Instead, either reads the monitor, and * using its stored `update_id`, synthesizes update storage keys, and tries them in sequence until * one is not found. All _other_ errors will be bubbled up in the function's [`Result`]. * * # Pruning stale channel updates * * Stale updates are pruned when the consolidation threshold is reached according to `maximum_pending_updates`. * Monitor updates in the range between the latest `update_id` and `update_id - maximum_pending_updates` * are deleted. * The `lazy` flag is used on the [`KVStore::remove`] method, so there are no guarantees that the deletions * will complete. However, stale updates are not a problem for data integrity, since updates are * only read that are higher than the stored [`ChannelMonitor`]'s `update_id`. * * If you have many stale updates stored (such as after a crash with pending lazy deletes), and * would like to get rid of them, consider using the * [`MonitorUpdatingPersister::cleanup_stale_updates`] function. */ export declare class MonitorUpdatingPersister extends CommonBase { /** * Constructs a new [`MonitorUpdatingPersister`]. * * The `maximum_pending_updates` parameter controls how many updates may be stored before a * [`MonitorUpdatingPersister`] consolidates updates by writing a full monitor. Note that * consolidation will frequently occur with fewer updates than what you set here; this number * is merely the maximum that may be stored. When setting this value, consider that for higher * values of `maximum_pending_updates`: * * - [`MonitorUpdatingPersister`] will tend to write more [`ChannelMonitorUpdate`]s than * [`ChannelMonitor`]s, approaching one [`ChannelMonitor`] write for every * `maximum_pending_updates` [`ChannelMonitorUpdate`]s. * - [`MonitorUpdatingPersister`] will issue deletes differently. Lazy deletes will come in * \"waves\" for each [`ChannelMonitor`] write. A larger `maximum_pending_updates` means bigger, * less frequent \"waves.\" * - [`MonitorUpdatingPersister`] will potentially have more listing to do if you need to run * [`MonitorUpdatingPersister::cleanup_stale_updates`]. */ static constructor_new(kv_store: KVStore, logger: Logger, maximum_pending_updates: bigint, entropy_source: EntropySource, signer_provider: SignerProvider, broadcaster: BroadcasterInterface, fee_estimator: FeeEstimator): MonitorUpdatingPersister; /** * Reads all stored channel monitors, along with any stored updates for them. * * It is extremely important that your [`KVStore::read`] implementation uses the * [`io::ErrorKind::NotFound`] variant correctly. For more information, please see the * documentation for [`MonitorUpdatingPersister`]. */ read_all_channel_monitors_with_updates(): Result_CVec_C2Tuple_ThirtyTwoBytesChannelMonitorZZIOErrorZ; /** * Read a single channel monitor, along with any stored updates for it. * * It is extremely important that your [`KVStore::read`] implementation uses the * [`io::ErrorKind::NotFound`] variant correctly. For more information, please see the * documentation for [`MonitorUpdatingPersister`]. * * For `monitor_key`, channel storage keys be the channel's transaction ID and index, or * [`OutPoint`], with an underscore `_` between them. For example, given: * * - Transaction ID: `deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef` * - Index: `1` * * The correct `monitor_key` would be: * `deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef_1` * * Loading a large number of monitors will be faster if done in parallel. You can use this * function to accomplish this. Take care to limit the number of parallel readers. */ read_channel_monitor_with_updates(monitor_key: string): Result_C2Tuple_ThirtyTwoBytesChannelMonitorZIOErrorZ; /** * Cleans up stale updates for all monitors. * * This function works by first listing all monitors, and then for each of them, listing all * updates. The updates that have an `update_id` less than or equal to than the stored monitor * are deleted. The deletion can either be lazy or non-lazy based on the `lazy` flag; this will * be passed to [`KVStore::remove`]. */ cleanup_stale_updates(lazy: boolean): Result_NoneIOErrorZ; /** * Constructs a new Persist which calls the relevant methods on this_arg. * This copies the `inner` pointer in this_arg and thus the returned Persist must be freed before this_arg is */ as_Persist(): Persist; }