|
14 | 14 | use crate::chain;
|
15 | 15 | use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch};
|
16 | 16 | use crate::chain::chaininterface::LowerBoundedFeeEstimator;
|
17 |
| -use crate::chain::channelmonitor; |
| 17 | +use crate::chain::chainmonitor::Persist; |
| 18 | +use crate::chain::{channelmonitor, BestBlock}; |
18 | 19 | use crate::chain::channelmonitor::{CLOSED_CHANNEL_UPDATE_ID, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
|
19 | 20 | use crate::chain::transaction::OutPoint;
|
20 |
| -use crate::sign::{ecdsa::EcdsaChannelSigner, EntropySource, OutputSpender, SignerProvider}; |
| 21 | +use crate::sign::{ecdsa::EcdsaChannelSigner, EntropySource, OutputSpender, SignerProvider, SpendableOutputDescriptor}; |
21 | 22 | use crate::events::{Event, FundingInfo, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason};
|
22 | 23 | use crate::ln::types::{ChannelId, PaymentPreimage, PaymentSecret, PaymentHash};
|
23 | 24 | use crate::ln::channel::{CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT, get_holder_selected_channel_reserve_satoshis, OutboundV1Channel, InboundV1Channel, COINBASE_MATURITY, ChannelPhase};
|
24 |
| -use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA}; |
| 25 | +use crate::ln::channelmanager::{self, ChainParameters, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA}; |
25 | 26 | use crate::ln::channel::{DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, ChannelError};
|
26 | 27 | use crate::ln::{chan_utils, onion_utils};
|
27 | 28 | use crate::ln::chan_utils::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
|
| 29 | +use crate::ln::fundrecoverer::{FundRecoverer, RecoveryEvent}; |
28 | 30 | use crate::routing::gossip::{NetworkGraph, NetworkUpdate};
|
29 | 31 | use crate::routing::router::{Path, PaymentParameters, Route, RouteHop, get_route, RouteParameters};
|
30 | 32 | use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures};
|
@@ -174,6 +176,166 @@ fn test_funding_exceeds_no_wumbo_limit() {
|
174 | 176 | }
|
175 | 177 | }
|
176 | 178 |
|
| 179 | +#[test] |
| 180 | +fn test_peer_storage() { |
| 181 | + let chanmon_cfgs = create_chanmon_cfgs(2); |
| 182 | + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); |
| 183 | + let (persister, chain_monitor); |
| 184 | + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); |
| 185 | + let nodes_0_deserialized; |
| 186 | + let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); |
| 187 | + let nodes_0_serialized = nodes[0].node.encode(); |
| 188 | + |
| 189 | + let (_a, _b, _cid, _funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1); |
| 190 | + |
| 191 | + let msg_events_a = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_msg_events(); |
| 192 | + for msg in msg_events_a { |
| 193 | + if let MessageSendEvent::SendPeerStorageMessage { node_id: _, ref msg } = msg { |
| 194 | + nodes[1].node.handle_peer_storage(nodes[0].node.get_our_node_id(), msg); |
| 195 | + } else { |
| 196 | + panic!("Unexpected event"); |
| 197 | + } |
| 198 | + } |
| 199 | + |
| 200 | + let msg_events_b = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_msg_events(); |
| 201 | + for msg in msg_events_b { |
| 202 | + if let MessageSendEvent::SendPeerStorageMessage { node_id: _, ref msg } = msg { |
| 203 | + nodes[0].node.handle_peer_storage(nodes[1].node.get_our_node_id(), msg); |
| 204 | + } else { |
| 205 | + panic!("Unexpected event"); |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + send_payment(&nodes[0], &vec!(&nodes[1])[..], 1000); |
| 210 | + send_payment(&nodes[0], &vec!(&nodes[1])[..], 10000); |
| 211 | + send_payment(&nodes[0], &vec!(&nodes[1])[..], 9999); |
| 212 | + |
| 213 | + nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id()); |
| 214 | + nodes[1].node.peer_disconnected(nodes[0].node.get_our_node_id()); |
| 215 | + |
| 216 | + // Reconnect peers |
| 217 | + nodes[0].node.peer_connected(nodes[1].node.get_our_node_id(), &msgs::Init { |
| 218 | + features: nodes[1].node.init_features(), networks: None, remote_network_address: None |
| 219 | + }, true).unwrap(); |
| 220 | + let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); |
| 221 | + assert_eq!(reestablish_1.len(), 1); |
| 222 | + nodes[1].node.peer_connected(nodes[0].node.get_our_node_id(), &msgs::Init { |
| 223 | + features: nodes[0].node.init_features(), networks: None, remote_network_address: None |
| 224 | + }, false).unwrap(); |
| 225 | + let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); |
| 226 | + assert_eq!(reestablish_2.len(), 1); |
| 227 | + |
| 228 | + nodes[0].node.handle_channel_reestablish(nodes[1].node.get_our_node_id(), &reestablish_2[0]); |
| 229 | + handle_chan_reestablish_msgs!(nodes[0], nodes[1]); |
| 230 | + nodes[1].node.handle_channel_reestablish(nodes[0].node.get_our_node_id(), &reestablish_1[0]); |
| 231 | + handle_chan_reestablish_msgs!(nodes[1], nodes[0]); |
| 232 | + |
| 233 | + nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id()); |
| 234 | + nodes[1].node.peer_disconnected(nodes[0].node.get_our_node_id()); |
| 235 | + |
| 236 | + // Lets drop the monitor and clear the chain_monitor as well. |
| 237 | + nodes[0].chain_source.clear_watched_txn_and_outputs(); |
| 238 | + reload_node!(nodes[0], test_default_channel_config(), &nodes_0_serialized, &[], persister, chain_monitor, nodes_0_deserialized); |
| 239 | + let persister: &dyn Persist<TestChannelSigner> = &chanmon_cfgs[0].persister; |
| 240 | + |
| 241 | + let fundrecoverer |
| 242 | + = FundRecoverer::new(node_cfgs[0].keys_manager, node_cfgs[0].logger,test_default_channel_config(), ChainParameters {network: Network::Testnet, |
| 243 | + best_block: BestBlock::from_network(Network::Testnet)}, node_cfgs[0].keys_manager, node_cfgs[0].keys_manager, Some(&chanmon_cfgs[0].chain_source), |
| 244 | + persister, node_cfgs[0].fee_estimator, node_cfgs[0].tx_broadcaster, Vec::new()); |
| 245 | + |
| 246 | + fundrecoverer.peer_connected(nodes[1].node.get_our_node_id(), &msgs::Init { |
| 247 | + features: nodes[0].node.init_features(), networks: None, remote_network_address: None |
| 248 | + }, true).unwrap(); |
| 249 | + |
| 250 | + nodes[1].node.peer_connected(nodes[0].node.get_our_node_id(), &msgs::Init { |
| 251 | + features: nodes[0].node.init_features(), networks: None, remote_network_address: None |
| 252 | + }, true).unwrap(); |
| 253 | + let msg_events = nodes[1].node.get_and_clear_pending_msg_events(); |
| 254 | + // 0th - SendYourPeerStorageMessage |
| 255 | + // 1st - SendChannelReestablish |
| 256 | + assert_eq!(msg_events.len(), 2); |
| 257 | + for msg in msg_events { |
| 258 | + if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg { |
| 259 | + fundrecoverer.handle_channel_reestablish(nodes[1].node.get_our_node_id(), msg); |
| 260 | + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); |
| 261 | + } else if let MessageSendEvent::SendYourPeerStorageMessage { ref node_id, ref msg } = msg { |
| 262 | + fundrecoverer.handle_your_peer_storage(nodes[1].node.get_our_node_id(), msg); |
| 263 | + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); |
| 264 | + } else { |
| 265 | + panic!("Unexpected event") |
| 266 | + } |
| 267 | + } |
| 268 | + |
| 269 | + let recovery_event = fundrecoverer.get_and_clear_recovery_pending_events(); |
| 270 | + assert_eq!(recovery_event.len(), 1); |
| 271 | + match recovery_event[0] { |
| 272 | + RecoveryEvent::RescanBlock{..} => {}, |
| 273 | + }; |
| 274 | + |
| 275 | + let bogus_chan_reestablish = fundrecoverer.get_and_clear_pending_msg_events(); |
| 276 | + // We receive two `channel_reestablish`(bogus) messages: the first from `handle_your_peer_storage` and the second from `handle_channel_reestablish`. |
| 277 | + assert_eq!(bogus_chan_reestablish.len(), 2); |
| 278 | + match bogus_chan_reestablish[0] { |
| 279 | + MessageSendEvent::SendChannelReestablish {ref node_id, ref msg} => { |
| 280 | + assert_eq!(nodes[1].node.get_our_node_id(), *node_id); |
| 281 | + nodes[1].node.handle_channel_reestablish(nodes[0].node.get_our_node_id(), msg); |
| 282 | + }, |
| 283 | + _ => panic!("Unexpected event"), |
| 284 | + } |
| 285 | + |
| 286 | + let commitment_tx = { |
| 287 | + let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); |
| 288 | + assert_eq!(node_txn.len(), 1); |
| 289 | + node_txn.remove(0) |
| 290 | + }; |
| 291 | + |
| 292 | + let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![commitment_tx.clone()]); |
| 293 | + connect_block(&nodes[1], &block); |
| 294 | + // Since we are using fundrecoverer as Chain::watch. |
| 295 | + let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); |
| 296 | + let height = nodes[0].best_block_info().1 + 1; |
| 297 | + fundrecoverer.best_block_updated(&block.header, height); |
| 298 | + fundrecoverer.transactions_confirmed(&block.header, &txdata, height); |
| 299 | + |
| 300 | + check_closed_broadcast!(nodes[1], true); |
| 301 | + |
| 302 | + let events = nodes[1].node.get_and_clear_pending_events(); |
| 303 | + assert_eq!(events.len(), 1); |
| 304 | + match events[0] { |
| 305 | + Event::ChannelClosed {..} => {}, // If we actually processed we'd receive the payment |
| 306 | + _ => panic!("Unexpected event"), |
| 307 | + } |
| 308 | + let mut dummy_block = create_dummy_block(nodes[1].best_block_hash(), height, Vec::new()); |
| 309 | + for i in 1..CHAN_CONFIRM_DEPTH { |
| 310 | + let prev_blockhash = dummy_block.header.block_hash(); |
| 311 | + let dummy_txdata: Vec<_> = dummy_block.txdata.iter().enumerate().collect(); |
| 312 | + fundrecoverer.best_block_updated(&dummy_block.header, height + i + 1); |
| 313 | + fundrecoverer.transactions_confirmed(&dummy_block.header, &dummy_txdata, height + i + 1); |
| 314 | + dummy_block = create_dummy_block(prev_blockhash, height + i + 1, Vec::new()); |
| 315 | + } |
| 316 | + |
| 317 | + // Clearing chain source so that the `drop` doesn't panic. |
| 318 | + nodes[0].chain_source.clear_watched_txn_and_outputs(); |
| 319 | + |
| 320 | + check_added_monitors!(nodes[1], 1); |
| 321 | + |
| 322 | + for event in fundrecoverer.get_and_clear_pending_events() { |
| 323 | + match event { |
| 324 | + Event::SpendableOutputs { mut outputs, channel_id: _ } => { |
| 325 | + for outp in outputs.drain(..) { |
| 326 | + match outp { |
| 327 | + SpendableOutputDescriptor::StaticPaymentOutput(static_payment) => { |
| 328 | + assert_eq!(static_payment.output.value.to_sat(), commitment_tx.output[0].value.to_sat()); |
| 329 | + }, |
| 330 | + _ => panic!("Unexpected event"), |
| 331 | + } |
| 332 | + } |
| 333 | + }, |
| 334 | + _ => panic!("Unexpected event"), |
| 335 | + }; |
| 336 | + } |
| 337 | +} |
| 338 | + |
177 | 339 | fn do_test_counterparty_no_reserve(send_from_initiator: bool) {
|
178 | 340 | // A peer providing a channel_reserve_satoshis of 0 (or less than our dust limit) is insecure,
|
179 | 341 | // but only for them. Because some LSPs do it with some level of trust of the clients (for a
|
|
0 commit comments