Skip to content

Commit fec8553

Browse files
committed
Parameterize ChannelManager::new with a block hash
When ChannelMonitors are persisted, they need to store the most recent block hash seen. However, for newly created channels the default block hash is used. If persisted before a block is connected, the funding output may be missed when syncing after a restart. Instead, initialize ChannelManager with a "birthday" hash so it can be used later when creating channels.
1 parent 5daf543 commit fec8553

File tree

5 files changed

+59
-17
lines changed

5 files changed

+59
-17
lines changed

background-processor/src/lib.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ mod tests {
106106
use lightning::chain::keysinterface::{Sign, InMemorySigner, KeysInterface, KeysManager};
107107
use lightning::chain::transaction::OutPoint;
108108
use lightning::get_event_msg;
109-
use lightning::ln::channelmanager::{ChannelManager, SimpleArcChannelManager};
109+
use lightning::ln::channelmanager::{ChainParameters, ChannelManager, SimpleArcChannelManager};
110110
use lightning::ln::features::InitFeatures;
111111
use lightning::ln::msgs::ChannelMessageHandler;
112112
use lightning::util::config::UserConfig;
@@ -155,10 +155,16 @@ mod tests {
155155
let persister = Arc::new(FilesystemPersister::new(format!("{}_persister_{}", persist_dir, i)));
156156
let seed = [i as u8; 32];
157157
let network = Network::Testnet;
158-
let now = Duration::from_secs(genesis_block(network).header.time as u64);
158+
let genesis_block = genesis_block(network);
159+
let now = Duration::from_secs(genesis_block.header.time as u64);
159160
let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos()));
160161
let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new(Some(chain_source.clone()), tx_broadcaster.clone(), logger.clone(), fee_estimator.clone(), persister.clone()));
161-
let manager = Arc::new(ChannelManager::new(Network::Testnet, fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster, logger.clone(), keys_manager.clone(), UserConfig::default(), i));
162+
let params = ChainParameters {
163+
network,
164+
latest_hash: genesis_block.block_hash(),
165+
latest_height: 0,
166+
};
167+
let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster, logger.clone(), keys_manager.clone(), UserConfig::default(), params));
162168
let node = Node { node: manager, persister, logger };
163169
nodes.push(node);
164170
}

fuzz/src/chanmon_consistency.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
//! channel being force-closed.
2020
2121
use bitcoin::blockdata::block::BlockHeader;
22+
use bitcoin::blockdata::constants::genesis_block;
2223
use bitcoin::blockdata::transaction::{Transaction, TxOut};
2324
use bitcoin::blockdata::script::{Builder, Script};
2425
use bitcoin::blockdata::opcodes;
@@ -35,7 +36,7 @@ use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr,
3536
use lightning::chain::transaction::OutPoint;
3637
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
3738
use lightning::chain::keysinterface::{KeysInterface, InMemorySigner};
38-
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret, PaymentSendFailure, ChannelManagerReadArgs};
39+
use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret, PaymentSendFailure, ChannelManagerReadArgs};
3940
use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
4041
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, DecodeError, ErrorAction, UpdateAddHTLC, Init};
4142
use lightning::util::enforcing_trait_impls::{EnforcingSigner, INITIAL_REVOKED_COMMITMENT_NUMBER};
@@ -318,7 +319,13 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
318319
config.channel_options.fee_proportional_millionths = 0;
319320
config.channel_options.announced_channel = true;
320321
config.peer_channel_config_limits.min_dust_limit_satoshis = 0;
321-
(ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0),
322+
let network = Network::Bitcoin;
323+
let params = ChainParameters {
324+
network,
325+
latest_hash: genesis_block(network).block_hash(),
326+
latest_height: 0,
327+
};
328+
(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, params),
322329
monitor, keys_manager)
323330
} }
324331
}

fuzz/src/full_stack.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget,
3131
use lightning::chain::chainmonitor;
3232
use lightning::chain::transaction::OutPoint;
3333
use lightning::chain::keysinterface::{InMemorySigner, KeysInterface};
34-
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret};
34+
use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret};
3535
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
3636
use lightning::ln::msgs::DecodeError;
3737
use lightning::routing::router::get_route;
@@ -348,9 +348,16 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
348348
config.channel_options.fee_proportional_millionths = slice_to_be32(get_slice!(4));
349349
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
350350
config.peer_channel_config_limits.min_dust_limit_satoshis = 0;
351-
let channelmanager = Arc::new(ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0));
351+
let network = Network::Bitcoin;
352+
let genesis_hash = genesis_block(network).block_hash();
353+
let params = ChainParameters {
354+
network,
355+
latest_hash: genesis_hash,
356+
latest_height: 0,
357+
};
358+
let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, params));
352359
let our_id = PublicKey::from_secret_key(&Secp256k1::signing_only(), &keys_manager.get_node_secret());
353-
let net_graph_msg_handler = Arc::new(NetGraphMsgHandler::new(genesis_block(Network::Bitcoin).header.block_hash(), None, Arc::clone(&logger)));
360+
let net_graph_msg_handler = Arc::new(NetGraphMsgHandler::new(genesis_hash, None, Arc::clone(&logger)));
354361

355362
let peers = RefCell::new([false; 256]);
356363
let mut loss_detector = MoneyLossDetector::new(&peers, channelmanager.clone(), monitor.clone(), PeerManager::new(MessageHandler {

lightning/src/ln/channelmanager.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,24 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
451451
logger: L,
452452
}
453453

454+
/// Chain-related parameters used to construct a new `ChannelManager`.
455+
///
456+
/// Typically, the block-specific parameters are derived from the best block hash for the network,
457+
/// as a newly constructed `ChannelManager` will not have created any channels yet. These parameters
458+
/// are not needed when deserializing a previously constructed `ChannelManager`.
459+
pub struct ChainParameters {
460+
/// The network for determining the `chain_hash` in Lightning messages.
461+
pub network: Network,
462+
463+
/// The hash of the latest block successfully connected.
464+
pub latest_hash: BlockHash,
465+
466+
/// The height of the latest block successfully connected.
467+
///
468+
/// Used to track on-chain channel funding outputs and send payments with reliable timelocks.
469+
pub latest_height: usize,
470+
}
471+
454472
/// Whenever we release the `ChannelManager`'s `total_consistency_lock`, from read mode, it is
455473
/// desirable to notify any listeners on `wait_timeout`/`wait` that new updates are available for
456474
/// persistence. Therefore, this struct is responsible for locking the total consistency lock and,
@@ -760,24 +778,21 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
760778
///
761779
/// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`!
762780
///
763-
/// Users must provide the current blockchain height from which to track onchain channel
764-
/// funding outpoints and send payments with reliable timelocks.
765-
///
766781
/// Users need to notify the new ChannelManager when a new block is connected or
767782
/// disconnected using its `block_connected` and `block_disconnected` methods.
768-
pub fn new(network: Network, fee_est: F, chain_monitor: M, tx_broadcaster: T, logger: L, keys_manager: K, config: UserConfig, current_blockchain_height: usize) -> Self {
783+
pub fn new(fee_est: F, chain_monitor: M, tx_broadcaster: T, logger: L, keys_manager: K, config: UserConfig, params: ChainParameters) -> Self {
769784
let mut secp_ctx = Secp256k1::new();
770785
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
771786

772787
ChannelManager {
773788
default_configuration: config.clone(),
774-
genesis_hash: genesis_block(network).header.block_hash(),
789+
genesis_hash: genesis_block(params.network).header.block_hash(),
775790
fee_estimator: fee_est,
776791
chain_monitor,
777792
tx_broadcaster,
778793

779-
latest_block_height: AtomicUsize::new(current_blockchain_height),
780-
last_block_hash: Mutex::new(Default::default()),
794+
latest_block_height: AtomicUsize::new(params.latest_height),
795+
last_block_hash: Mutex::new(params.latest_hash),
781796
secp_ctx,
782797

783798
channel_state: Mutex::new(ChannelHolder{

lightning/src/ln/functional_test_utils.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use chain::Watch;
1414
use chain::channelmonitor::ChannelMonitor;
1515
use chain::transaction::OutPoint;
16-
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure};
16+
use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure};
1717
use routing::router::{Route, get_route};
1818
use routing::network_graph::{NetGraphMsgHandler, NetworkGraph};
1919
use ln::features::InitFeatures;
@@ -28,6 +28,7 @@ use util::config::UserConfig;
2828
use util::ser::{ReadableArgs, Writeable, Readable};
2929

3030
use bitcoin::blockdata::block::{Block, BlockHeader};
31+
use bitcoin::blockdata::constants::genesis_block;
3132
use bitcoin::blockdata::transaction::{Transaction, TxOut};
3233
use bitcoin::network::constants::Network;
3334

@@ -1161,7 +1162,13 @@ pub fn create_node_chanmgrs<'a, 'b>(node_count: usize, cfgs: &'a Vec<NodeCfg<'b>
11611162
default_config.channel_options.announced_channel = true;
11621163
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
11631164
default_config.own_channel_config.our_htlc_minimum_msat = 1000; // sanitization being done by the sender, to exerce receiver logic we need to lift of limit
1164-
let node = ChannelManager::new(Network::Testnet, cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { default_config }, 0);
1165+
let network = Network::Testnet;
1166+
let params = ChainParameters {
1167+
network,
1168+
latest_hash: genesis_block(network).header.block_hash(),
1169+
latest_height: 0,
1170+
};
1171+
let node = ChannelManager::new(cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { default_config }, params);
11651172
chanmgrs.push(node);
11661173
}
11671174

0 commit comments

Comments
 (0)