Add Persist trait.
authorValentine Wallace <vwallace@protonmail.com>
Wed, 16 Sep 2020 21:43:33 +0000 (17:43 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Fri, 16 Oct 2020 15:30:33 +0000 (11:30 -0400)
Implementors of Persist are responsible for persisting new ChannelMonitors
and ChannelMonitor updates to disk/backups.

lightning/src/chain/channelmonitor.rs

index 315b2afec495cf6895ee2999b6472608ffdd7559..93a4edb6e3c4cf4499afda966688db17c07dad69 100644 (file)
@@ -2123,6 +2123,61 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
        }
 }
 
+/// `Persist` defines behavior for persisting channel monitors: this could mean
+/// writing once to disk, and/or uploading to one or more backup services.
+///
+/// Note that for every new monitor, you **must** persist the new `ChannelMonitor`
+/// to disk/backups. And, on every update, you **must** persist either the
+/// `ChannelMonitorUpdate` or the updated monitor itself. Otherwise, there is risk
+/// of situations such as revoking a transaction, then crashing before this
+/// revocation can be persisted, then unintentionally broadcasting a revoked
+/// transaction and losing money. This is a risk because previous channel states
+/// are toxic, so it's important that whatever channel state is persisted is
+/// kept up-to-date.
+pub trait Persist<Keys: ChannelKeys>: Send + Sync {
+       /// Persist a new channel's data. The data can be stored any way you want, but
+       /// the identifier provided by Rust-Lightning is the channel's outpoint (and
+       /// it is up to you to maintain a correct mapping between the outpoint and the
+       /// stored channel data). Note that you **must** persist every new monitor to
+       /// disk. See the `Persist` trait documentation for more details.
+       ///
+       /// See [`ChannelMonitor::write_for_disk`] for writing out a `ChannelMonitor`,
+       /// and [`ChannelMonitorUpdateErr`] for requirements when returning errors.
+       ///
+       /// [`ChannelMonitor::write_for_disk`]: struct.ChannelMonitor.html#method.write_for_disk
+       /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html
+       fn persist_new_channel(&self, id: OutPoint, data: &ChannelMonitor<Keys>) -> Result<(), ChannelMonitorUpdateErr>;
+
+       /// Update one channel's data. The provided `ChannelMonitor` has already
+       /// applied the given update.
+       ///
+       /// Note that on every update, you **must** persist either the
+       /// `ChannelMonitorUpdate` or the updated monitor itself to disk/backups. See
+       /// the `Persist` trait documentation for more details.
+       ///
+       /// If an implementer chooses to persist the updates only, they need to make
+       /// sure that all the updates are applied to the `ChannelMonitors` *before*
+       /// the set of channel monitors is given to the `ChannelManager`
+       /// deserialization routine. See [`ChannelMonitor::update_monitor`] for
+       /// applying a monitor update to a monitor. If full `ChannelMonitors` are
+       /// persisted, then there is no need to persist individual updates.
+       ///
+       /// Note that there could be a performance tradeoff between persisting complete
+       /// channel monitors on every update vs. persisting only updates and applying
+       /// them in batches. The size of each monitor grows `O(number of state updates)`
+       /// whereas updates are small and `O(1)`.
+       ///
+       /// See [`ChannelMonitor::write_for_disk`] for writing out a `ChannelMonitor`,
+       /// [`ChannelMonitorUpdate::write`] for writing out an update, and
+       /// [`ChannelMonitorUpdateErr`] for requirements when returning errors.
+       ///
+       /// [`ChannelMonitor::update_monitor`]: struct.ChannelMonitor.html#impl-1
+       /// [`ChannelMonitor::write_for_disk`]: struct.ChannelMonitor.html#method.write_for_disk
+       /// [`ChannelMonitorUpdate::write`]: struct.ChannelMonitorUpdate.html#method.write
+       /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html
+       fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor<Keys>) -> Result<(), ChannelMonitorUpdateErr>;
+}
+
 const MAX_ALLOC_SIZE: usize = 64*1024;
 
 impl<ChanSigner: ChannelKeys + Readable> Readable for (BlockHash, ChannelMonitor<ChanSigner>) {