Merge pull request #555 from ariard/2020-03-begin-dryup-chanmon-keys
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Sat, 21 Mar 2020 22:21:38 +0000 (22:21 +0000)
committerGitHub <noreply@github.com>
Sat, 21 Mar 2020 22:21:38 +0000 (22:21 +0000)
Begin dry-up ChannelMonitor key access

ARCH.md [new file with mode: 0644]
README.md
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_tests.rs

diff --git a/ARCH.md b/ARCH.md
new file mode 100644 (file)
index 0000000..dba91e7
--- /dev/null
+++ b/ARCH.md
@@ -0,0 +1,62 @@
+Rust-Lightning is broken into a number of high-level structures with APIs to hook them
+together, as well as APIs for you, the user, to provide external data.
+
+The two most important structures which nearly every application of Rust-Lightning will
+need to use are `ChannelManager` and `ChannelMonitor`. `ChannelManager` holds multiple
+channels, routes payments between them, and exposes a simple API to make and receive
+payments. Individual `ChannelMonitor`s monitor the on-chain state of a channel, punish
+counterparties if they misbehave, and force-close channels if they contain unresolved
+HTLCs which are near expiration. The `ManyChannelMonitor` API provides a way for you to
+receive `ChannelMonitorUpdate`s from `ChannelManager` and persist them to disk before the
+channel steps forward.
+
+There are two additional important structures that you may use either on the same device
+as the `ChannelManager` or on a separate one. `Router` handles receiving channel and node
+node announcements and calculates routes for sending payments. `PeerManager` handles the
+authenticated and encrypted communication protocol, monitoring for liveness of peers,
+routing messages to `ChannelManager` and `Router` instances directly, and receiving
+messages from them via the `EventsProvider` interface.
+
+These structs communicate with each other using a public API, so that you can easily add
+a proxy in between for special handling. Further, APIs for key generation, transaction
+broadcasting, block fetching, and fee estimation must be implemented and the data
+provided by you, the user.
+
+The library does not rely on the presence of a runtime environment outside of access to
+heap, atomic integers, and basic Mutex primitives. This means the library will never
+spawn threads or take any action whatsoever except when you call into it. Thus,
+`ChannelManager` and `PeerManager` have public functions which you should call on a timer,
+network reads and writes are external and provided by you, and the library relies only on
+block time for current time knowledge.
+
+At a high level, some of the common interfaces fit together as follows:
+
+
+```
+
+                     -----------------
+                     | KeysInterface |  --------------
+                     -----------------  | UserConfig |
+         --------------------       |   --------------
+  /------| MessageSendEvent |       |   |     ----------------
+ |       --------------------       |   |     | FeeEstimator |
+ |   (as MessageSendEventsProvider) |   |     ----------------
+ |                         ^        |   |    /          |      ------------------------
+ |                          \       |   |   /      ---------> | BroadcasterInterface |
+ |                           \      |   |  /      /     |     ------------------------
+ |                            \     v   v v      /      v        ^
+ |    (as                      ------------------       ----------------------
+ |    ChannelMessageHandler)-> | ChannelManager | ----> | ManyChannelMonitor |
+ v               /             ------------------       ----------------------
+--------------- /                ^         (as EventsProvider)   ^
+| PeerManager |-                 |              \     /         /
+---------------                  |        -------\---/----------
+ |              -----------------------  /        \ /
+ |              | ChainWatchInterface | -          v
+ |              -----------------------        ---------
+ |                            |                | Event |
+(as RoutingMessageHandler)    v                ---------
+  \                   ----------
+   -----------------> | Router |
+                      ----------
+```
index f6fba666c337d39d0c0e768e93e1d0fbd7a8453b..7dec713f637e23c5eb316c1ba56b7d6e93a9e724 100644 (file)
--- a/README.md
+++ b/README.md
@@ -46,6 +46,6 @@ Contributors are warmly welcome, see [CONTRIBUTING.md](CONTRIBUTING.md).
 Project Architecture
 ---------------------
 
-COMING SOON.
+For a Rust-Lightning high-level API introduction, see [ARCH.md](ARCH.md).
 
 License is Apache-2.0.
index cde40ee323241cde60b14a400ab537e21477daa4..1afce1f7bb99e3b9ebe207567caeb205108b59f8 100644 (file)
@@ -3470,10 +3470,17 @@ impl<'a, ChanSigner: ChannelKeys + Readable, M: Deref, T: Deref, K: Deref, F: De
                        let funding_txo = channel.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
                        funding_txo_set.insert(funding_txo.clone());
                        if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
-                               if channel.get_cur_local_commitment_transaction_number() != monitor.get_cur_local_commitment_number() ||
-                                               channel.get_revoked_remote_commitment_transaction_number() != monitor.get_min_seen_secret() ||
-                                               channel.get_cur_remote_commitment_transaction_number() != monitor.get_cur_remote_commitment_number() ||
-                                               channel.get_latest_monitor_update_id() != monitor.get_latest_update_id() {
+                               if channel.get_cur_local_commitment_transaction_number() < monitor.get_cur_local_commitment_number() ||
+                                               channel.get_revoked_remote_commitment_transaction_number() < monitor.get_min_seen_secret() ||
+                                               channel.get_cur_remote_commitment_transaction_number() < monitor.get_cur_remote_commitment_number() ||
+                                               channel.get_latest_monitor_update_id() > monitor.get_latest_update_id() {
+                                       // If the channel is ahead of the monitor, return InvalidValue:
+                                       return Err(DecodeError::InvalidValue);
+                               } else if channel.get_cur_local_commitment_transaction_number() > monitor.get_cur_local_commitment_number() ||
+                                               channel.get_revoked_remote_commitment_transaction_number() > monitor.get_min_seen_secret() ||
+                                               channel.get_cur_remote_commitment_transaction_number() > monitor.get_cur_remote_commitment_number() ||
+                                               channel.get_latest_monitor_update_id() < monitor.get_latest_update_id() {
+                                       // But if the channel is behind of the monitor, close the channel:
                                        let (_, _, mut new_failed_htlcs) = channel.force_shutdown(true);
                                        failed_htlcs.append(&mut new_failed_htlcs);
                                        monitor.broadcast_latest_local_commitment_txn(&args.tx_broadcaster);
index 9669c7852ccdf91b755585b028d985c580a6e9b2..8ea9dcf753c07159bb376d0ace428e88754e59b4 100644 (file)
@@ -3839,6 +3839,13 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
        create_announced_chan_between_nodes(&nodes, 2, 0, InitFeatures::supported(), InitFeatures::supported());
        let (_, _, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 3, InitFeatures::supported(), InitFeatures::supported());
 
+       let mut node_0_stale_monitors_serialized = Vec::new();
+       for monitor in nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap().iter() {
+               let mut writer = test_utils::TestVecWriter(Vec::new());
+               monitor.1.write_for_disk(&mut writer).unwrap();
+               node_0_stale_monitors_serialized.push(writer.0);
+       }
+
        let (our_payment_preimage, _) = route_payment(&nodes[2], &[&nodes[0], &nodes[1]], 1000000);
 
        // Serialize the ChannelManager here, but the monitor we keep up-to-date
@@ -3861,6 +3868,15 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
        fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
        new_chan_monitor = test_utils::TestChannelMonitor::new(nodes[0].chain_monitor.clone(), nodes[0].tx_broadcaster.clone(), Arc::new(test_utils::TestLogger::new()), &fee_estimator);
        nodes[0].chan_monitor = &new_chan_monitor;
+
+       let mut node_0_stale_monitors = Vec::new();
+       for serialized in node_0_stale_monitors_serialized.iter() {
+               let mut read = &serialized[..];
+               let (_, monitor) = <(Sha256dHash, ChannelMonitor<EnforcingChannelKeys>)>::read(&mut read, Arc::new(test_utils::TestLogger::new())).unwrap();
+               assert!(read.is_empty());
+               node_0_stale_monitors.push(monitor);
+       }
+
        let mut node_0_monitors = Vec::new();
        for serialized in node_0_monitors_serialized.iter() {
                let mut read = &serialized[..];
@@ -3869,9 +3885,25 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
                node_0_monitors.push(monitor);
        }
 
-       let mut nodes_0_read = &nodes_0_serialized[..];
        keys_manager = test_utils::TestKeysInterface::new(&nodes[0].node_seed, Network::Testnet, Arc::new(test_utils::TestLogger::new()));
-       let (_, nodes_0_deserialized_tmp) = <(Sha256dHash, ChannelManager<EnforcingChannelKeys, &test_utils::TestChannelMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator>)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
+
+       let mut nodes_0_read = &nodes_0_serialized[..];
+       if let Err(msgs::DecodeError::InvalidValue) =
+               <(Sha256dHash, ChannelManager<EnforcingChannelKeys, &test_utils::TestChannelMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator>)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
+               default_config: UserConfig::default(),
+               keys_manager: &keys_manager,
+               fee_estimator: &fee_estimator,
+               monitor: nodes[0].chan_monitor,
+               tx_broadcaster: nodes[0].tx_broadcaster.clone(),
+               logger: Arc::new(test_utils::TestLogger::new()),
+               channel_monitors: &mut node_0_stale_monitors.iter_mut().map(|monitor| { (monitor.get_funding_txo().unwrap(), monitor) }).collect(),
+       }) { } else {
+               panic!("If the monitor(s) are stale, this indicates a bug and we should get an Err return");
+       };
+
+       let mut nodes_0_read = &nodes_0_serialized[..];
+       let (_, nodes_0_deserialized_tmp) =
+               <(Sha256dHash, ChannelManager<EnforcingChannelKeys, &test_utils::TestChannelMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator>)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
                default_config: UserConfig::default(),
                keys_manager: &keys_manager,
                fee_estimator: &fee_estimator,