beta,
# 1.41.1 is MSRV for Rust-Lightning, lightning-invoice, and lightning-persister
1.41.1,
- # 1.45.2 is MSRV for lightning-net-tokio, lightning-block-sync, and coverage generation
+ # 1.45.2 is MSRV for lightning-net-tokio, lightning-block-sync, lightning-background-processor, and coverage generation
1.45.2,
# 1.47.0 will be the MSRV for no-std builds using hashbrown once core2 is updated
1.47.0]
- toolchain: stable
build-net-tokio: true
build-no-std: true
+ build-futures: true
- toolchain: stable
platform: macos-latest
build-net-tokio: true
build-no-std: true
+ build-futures: true
- toolchain: beta
platform: macos-latest
build-net-tokio: true
build-no-std: true
+ build-futures: true
- toolchain: stable
platform: windows-latest
build-net-tokio: true
build-no-std: true
+ build-futures: true
- toolchain: beta
platform: windows-latest
build-net-tokio: true
build-no-std: true
+ build-futures: true
- toolchain: beta
build-net-tokio: true
build-no-std: true
+ build-futures: true
- toolchain: 1.41.1
build-no-std: false
test-log-variants: true
+ build-futures: false
- toolchain: 1.45.2
build-net-old-tokio: true
build-net-tokio: true
build-no-std: false
+ build-futures: true
coverage: true
- toolchain: 1.47.0
+ build-futures: true
build-no-std: true
runs-on: ${{ matrix.platform }}
steps:
- name: Test on Rust ${{ matrix.toolchain }} with net-tokio and full code-linking for coverage generation
if: matrix.coverage
run: RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always
- - name: Test on no-std bullds Rust ${{ matrix.toolchain }}
+ - name: Test no-std builds on Rust ${{ matrix.toolchain }}
if: "matrix.build-no-std && !matrix.coverage"
shell: bash # Default on Winblows is powershell
run: |
- cd lightning
- cargo test --verbose --color always --no-default-features --features no-std
- # check if there is a conflict between no-std and the default std feature
- cargo test --verbose --color always --features no-std
- # check that things still pass without grind_signatures
- # note that outbound_commitment_test only runs in this mode, because of hardcoded signature values
- cargo test --verbose --color always --no-default-features --features std
- # check if there is a conflict between no-std and the c_bindings cfg
- RUSTFLAGS="--cfg=c_bindings" cargo test --verbose --color always --no-default-features --features=no-std
- cd ..
- cd lightning-invoice
- cargo test --verbose --color always --no-default-features --features no-std
- # check if there is a conflict between no-std and the default std feature
- cargo test --verbose --color always --features no-std
+ for DIR in lightning lightning-invoice lightning-rapid-gossip-sync; do
+ cd $DIR
+ cargo test --verbose --color always --no-default-features --features no-std
+ # check if there is a conflict between no-std and the default std feature
+ cargo test --verbose --color always --features no-std
+ # check that things still pass without grind_signatures
+ # note that outbound_commitment_test only runs in this mode, because of hardcoded signature values
+ cargo test --verbose --color always --no-default-features --features std
+ # check if there is a conflict between no-std and the c_bindings cfg
+ RUSTFLAGS="--cfg=c_bindings" cargo test --verbose --color always --no-default-features --features=no-std
+ cd ..
+ done
# check no-std compatibility across dependencies
- cd ..
cd no-std-check
cargo check --verbose --color always
- cd ..
+ - name: Build no-std-check on Rust ${{ matrix.toolchain }} for ARM Embedded
+ if: "matrix.build-no-std && matrix.platform == 'ubuntu-latest'"
+ run: |
+ cd no-std-check
+ rustup target add thumbv7m-none-eabi
+ sudo apt-get -y install gcc-arm-none-eabi
+ cargo build --target=thumbv7m-none-eabi
- name: Test on no-std builds Rust ${{ matrix.toolchain }} and full code-linking for coverage generation
if: "matrix.build-no-std && matrix.coverage"
run: |
cd lightning
RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --no-default-features --features no-std
- cd ..
+ - name: Test futures builds on Rust ${{ matrix.toolchain }}
+ if: "matrix.build-futures && !matrix.coverage"
+ shell: bash # Default on Winblows is powershell
+ run: |
+ cd lightning-background-processor
+ cargo test --verbose --color always --no-default-features --features futures
+ - name: Test futures builds on Rust ${{ matrix.toolchain }} and full code-linking for coverage generation
+ if: "matrix.build-futures && matrix.coverage"
+ shell: bash # Default on Winblows is powershell
+ run: |
+ cd lightning-background-processor
+ RUSTFLAGS="-C link-dead-code" cargo test --verbose --color always --no-default-features --features futures
- name: Test on Rust ${{ matrix.toolchain }}
if: "! matrix.build-net-tokio"
run: |
- cargo test --verbose --color always -p lightning
- cargo test --verbose --color always -p lightning-invoice
- cargo test --verbose --color always -p lightning-rapid-gossip-sync
- cargo build --verbose --color always -p lightning-persister
- cargo build --verbose --color always -p lightning-background-processor
+ cargo test --verbose --color always -p lightning
+ cargo test --verbose --color always -p lightning-invoice
+ cargo test --verbose --color always -p lightning-rapid-gossip-sync
+ cargo test --verbose --color always -p lightning-persister
+ cargo test --verbose --color always -p lightning-background-processor
- name: Test C Bindings Modifications on Rust ${{ matrix.toolchain }}
if: "! matrix.build-net-tokio"
run: |
run: |
cargo check --release
cargo check --no-default-features --features=no-std --release
+ cargo check --no-default-features --features=futures --release
cargo doc --release
fuzz:
"no-std-check",
]
-# Our tests do actual crypo and lots of work, the tradeoff for -O1 is well worth it.
+# Our tests do actual crypto and lots of work, the tradeoff for -O1 is well worth it.
# Ideally we would only do this in profile.test, but profile.test only applies to
# the test binary, not dependencies, which means most of the critical code still
# gets compiled as -O0. See
[![Documentation](https://img.shields.io/static/v1?logo=read-the-docs&label=docs.rs&message=lightning&color=informational)](https://docs.rs/lightning/)
[![Safety Dance](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
-`rust-lightning` is a Bitcoin Lightning library written in Rust. The main crate,
-`lightning`, does not handle networking, persistence, or any other I/O. Thus,
-it is runtime-agnostic, but users must implement basic networking logic, chain
-interactions, and disk storage. More information is available in the `About`
-section.
+[LDK](https://lightningdevkit.org)/`rust-lightning` is a highly performant and flexible
+implementation of the Lightning Network protocol.
+
+The primary crate, `lightning`, is runtime-agnostic. Data persistence, chain interactions,
+and networking can be provided by LDK's [sample modules](#crates), or you may provide your
+own custom implementations.
+More information is available in the [`About`](#about) section.
Status
------
-The project implements all of the [BOLT
-specifications](https://github.com/lightning/bolts). The
-implementation has pretty good test coverage that is expected to continue to
-improve. It is also anticipated that as developers begin using the API, the
-lessons from that will result in changes to the API, so any developer using this
-API at this stage should be prepared to embrace that. The current state is
-sufficient for a developer or project to experiment with it.
+The project implements all of the [BOLT specifications](https://github.com/lightning/bolts),
+and has been in production use since 2021. As with any Lightning implementation, care and attention
+to detail is important for safe deployment.
Communications for `rust-lightning` and Lightning Development Kit happen through
our LDK [Discord](https://discord.gg/5AcknnMfBw) channels.
About
-----------
-LDK/`rust-lightning` is a generic library which allows you to build a Lightning
+LDK/`rust-lightning` is a generic library that allows you to build a Lightning
node without needing to worry about getting all of the Lightning state machine,
routing, and on-chain punishment code (and other chain interactions) exactly
-correct. Note that `rust-lightning` isn't, in itself, a node. There are various
-working/in progress demos which could be used as a node today, but if you "just"
-want a generic Lightning node, you're almost certainly better off with [Core
-Lightning](https://github.com/ElementsProject/lightning) or
-[LND](https://github.com/lightningnetwork/lnd). If, on the other hand, you want
-to integrate Lightning with custom features such as your own chain sync, your
-own key management, your own data storage/backup logic, etc., LDK is likely your
-only option. Some `rust-lightning` utilities such as those in
+correct. Note that LDK isn't, in itself, a node. For an out-of-the-box Lightning
+node based on LDK, see [Sensei](https://l2.technology/sensei). However, if you
+want to integrate Lightning with custom features such as your own chain sync,
+key management, data storage/backup logic, etc., LDK is likely your best option.
+Some `rust-lightning` utilities such as those in
[`chan_utils`](./lightning/src/ln/chan_utils.rs) are also suitable for use in
non-LN Bitcoin applications such as Discreet Log Contracts (DLCs) and bulletin boards.
use bitcoin::hash_types::{BlockHash, WPubkeyHash};
use lightning::chain;
-use lightning::chain::{BestBlock, ChannelMonitorUpdateErr, chainmonitor, channelmonitor, Confirm, Watch};
+use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, chainmonitor, channelmonitor, Confirm, Watch};
use lightning::chain::channelmonitor::{ChannelMonitor, MonitorEvent};
use lightning::chain::transaction::OutPoint;
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
use lightning::chain::keysinterface::{KeyMaterial, KeysInterface, InMemorySigner, Recipient};
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
-use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs};
+use lightning::ln::channelmanager::{self, ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs};
use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
-use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, DecodeError, UpdateAddHTLC, Init};
use lightning::ln::script::ShutdownScript;
use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
}
}
impl chain::Watch<EnforcingSigner> for TestChainMonitor {
- fn watch_channel(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor<EnforcingSigner>) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn watch_channel(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor<EnforcingSigner>) -> chain::ChannelMonitorUpdateStatus {
let mut ser = VecWriter(Vec::new());
monitor.write(&mut ser).unwrap();
if let Some(_) = self.latest_monitors.lock().unwrap().insert(funding_txo, (monitor.get_latest_update_id(), ser.0)) {
self.chain_monitor.watch_channel(funding_txo, monitor)
}
- fn update_channel(&self, funding_txo: OutPoint, update: channelmonitor::ChannelMonitorUpdate) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn update_channel(&self, funding_txo: OutPoint, update: channelmonitor::ChannelMonitorUpdate) -> chain::ChannelMonitorUpdateStatus {
let mut map_lock = self.latest_monitors.lock().unwrap();
let mut map_entry = match map_lock.entry(funding_txo) {
hash_map::Entry::Occupied(entry) => entry,
_ => panic!("{}", err),
}
},
- APIError::MonitorUpdateFailed => {
+ APIError::MonitorUpdateInProgress => {
// We can (obviously) temp-fail a monitor update
},
APIError::IncompatibleShutdownScript { .. } => panic!("Cannot send an incompatible shutdown script"),
if let Err(err) = source.send_payment(&Route {
paths: vec![vec![RouteHop {
pubkey: dest.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: dest_chan_id,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: amt,
cltv_expiry_delta: 200,
}]],
if let Err(err) = source.send_payment(&Route {
paths: vec![vec![RouteHop {
pubkey: middle.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: middle_chan_id,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 50000,
cltv_expiry_delta: 100,
},RouteHop {
pubkey: dest.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: dest_chan_id,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: amt,
cltv_expiry_delta: 200,
}]],
let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone()));
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU32::new(0), enforcement_states: Mutex::new(HashMap::new()) });
let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(),
- Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(&keys_manager)));
+ Arc::new(TestPersister {
+ update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed)
+ }), Arc::clone(&keys_manager)));
let mut config = UserConfig::default();
config.channel_config.forwarding_fee_proportional_millionths = 0;
let keys_manager = Arc::clone(& $keys_manager);
let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone()));
let chain_monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(),
- Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(& $keys_manager)));
+ Arc::new(TestPersister {
+ update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed)
+ }), Arc::clone(& $keys_manager)));
let mut config = UserConfig::default();
config.channel_config.forwarding_fee_proportional_millionths = 0;
let res = (<(BlockHash, ChanMan)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, chain_monitor.clone());
for (funding_txo, mon) in monitors.drain() {
- assert!(chain_monitor.chain_monitor.watch_channel(funding_txo, mon).is_ok());
+ assert_eq!(chain_monitor.chain_monitor.watch_channel(funding_txo, mon),
+ ChannelMonitorUpdateStatus::Completed);
}
res
} }
let mut channel_txn = Vec::new();
macro_rules! make_channel {
($source: expr, $dest: expr, $chan_id: expr) => { {
- $source.peer_connected(&$dest.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
- $dest.peer_connected(&$source.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
+ $source.peer_connected(&$dest.get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ $dest.peer_connected(&$source.get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
$source.create_channel($dest.get_our_node_id(), 100_000, 42, 0, None).unwrap();
let open_channel = {
} else { panic!("Wrong event type"); }
};
- $dest.handle_open_channel(&$source.get_our_node_id(), InitFeatures::known(), &open_channel);
+ $dest.handle_open_channel(&$source.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let accept_channel = {
let events = $dest.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
} else { panic!("Wrong event type"); }
};
- $source.handle_accept_channel(&$dest.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ $source.handle_accept_channel(&$dest.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let funding_output;
{
let events = $source.get_and_clear_pending_events();
// bit-twiddling mutations to have similar effects. This is probably overkill, but no
// harm in doing so.
- 0x00 => *monitor_a.persister.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure),
- 0x01 => *monitor_b.persister.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure),
- 0x02 => *monitor_c.persister.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure),
- 0x04 => *monitor_a.persister.update_ret.lock().unwrap() = Ok(()),
- 0x05 => *monitor_b.persister.update_ret.lock().unwrap() = Ok(()),
- 0x06 => *monitor_c.persister.update_ret.lock().unwrap() = Ok(()),
+ 0x00 => *monitor_a.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::InProgress,
+ 0x01 => *monitor_b.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::InProgress,
+ 0x02 => *monitor_c.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::InProgress,
+ 0x04 => *monitor_a.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::Completed,
+ 0x05 => *monitor_b.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::Completed,
+ 0x06 => *monitor_c.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::Completed,
0x08 => {
if let Some((id, _)) = monitor_a.latest_monitors.lock().unwrap().get(&chan_1_funding) {
},
0x0e => {
if chan_a_disconnected {
- nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
chan_a_disconnected = false;
}
},
0x0f => {
if chan_b_disconnected {
- nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
chan_b_disconnected = false;
}
},
// after we resolve all pending events.
// First make sure there are no pending monitor updates, resetting the error state
// and calling force_channel_monitor_updated for each monitor.
- *monitor_a.persister.update_ret.lock().unwrap() = Ok(());
- *monitor_b.persister.update_ret.lock().unwrap() = Ok(());
- *monitor_c.persister.update_ret.lock().unwrap() = Ok(());
+ *monitor_a.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::Completed;
+ *monitor_b.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::Completed;
+ *monitor_c.persister.update_ret.lock().unwrap() = ChannelMonitorUpdateStatus::Completed;
if let Some((id, _)) = monitor_a.latest_monitors.lock().unwrap().get(&chan_1_funding) {
monitor_a.chain_monitor.force_channel_monitor_updated(chan_1_funding, *id);
// Next, make sure peers are all connected to each other
if chan_a_disconnected {
- nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
chan_a_disconnected = false;
}
if chan_b_disconnected {
- nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
chan_b_disconnected = false;
}
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
use lightning::chain;
-use lightning::chain::{BestBlock, Confirm, Listen};
+use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen};
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
use lightning::chain::chainmonitor;
use lightning::chain::transaction::OutPoint;
let broadcast = Arc::new(TestBroadcaster{ txn_broadcasted: Mutex::new(Vec::new()) });
let monitor = Arc::new(chainmonitor::ChainMonitor::new(None, broadcast.clone(), Arc::clone(&logger), fee_est.clone(),
- Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) })));
+ Arc::new(TestPersister { update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed) })));
let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), inbound_payment_key: KeyMaterial(inbound_payment_key.try_into().unwrap()), counter: AtomicU64::new(0) });
let mut config = UserConfig::default();
use lightning::chain;
use lightning::chain::transaction::OutPoint;
-use lightning::ln::channelmanager::{ChannelDetails, ChannelCounterparty};
-use lightning::ln::features::InitFeatures;
+use lightning::ln::channelmanager::{self, ChannelDetails, ChannelCounterparty};
use lightning::ln::msgs;
use lightning::routing::gossip::{NetworkGraph, RoutingFees};
use lightning::routing::router::{find_route, PaymentParameters, RouteHint, RouteHintHop, RouteParameters};
channel_id: [0; 32],
counterparty: ChannelCounterparty {
node_id: *rnid,
- features: InitFeatures::known(),
+ features: channelmanager::provided_init_features(),
unspendable_punishment_reserve: 0,
forwarding_info: None,
outbound_htlc_minimum_msat: None,
use std::sync::Mutex;
pub struct TestPersister {
- pub update_ret: Mutex<Result<(), chain::ChannelMonitorUpdateErr>>,
+ pub update_ret: Mutex<chain::ChannelMonitorUpdateStatus>,
}
impl chainmonitor::Persist<EnforcingSigner> for TestPersister {
- fn persist_new_channel(&self, _funding_txo: OutPoint, _data: &channelmonitor::ChannelMonitor<EnforcingSigner>, _update_id: MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn persist_new_channel(&self, _funding_txo: OutPoint, _data: &channelmonitor::ChannelMonitor<EnforcingSigner>, _update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
self.update_ret.lock().unwrap().clone()
}
- fn update_persisted_channel(&self, _funding_txo: OutPoint, _update: &Option<channelmonitor::ChannelMonitorUpdate>, _data: &channelmonitor::ChannelMonitor<EnforcingSigner>, _update_id: MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn update_persisted_channel(&self, _funding_txo: OutPoint, _update: &Option<channelmonitor::ChannelMonitorUpdate>, _data: &channelmonitor::ChannelMonitor<EnforcingSigner>, _update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
self.update_ret.lock().unwrap().clone()
}
}
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
+[features]
+futures = [ "futures-util" ]
+
[dependencies]
bitcoin = "0.29.0"
lightning = { version = "0.0.111", path = "../lightning", features = ["std"] }
lightning-rapid-gossip-sync = { version = "0.0.111", path = "../lightning-rapid-gossip-sync" }
-futures = { version = "0.3", optional = true }
+futures-util = { version = "0.3", default-features = false, features = ["async-await-macro"], optional = true }
[dev-dependencies]
lightning = { version = "0.0.111", path = "../lightning", features = ["_test_utils"] }
use std::ops::Deref;
#[cfg(feature = "futures")]
-use futures::{select, future::FutureExt};
+use futures_util::{select_biased, future::FutureExt};
/// `BackgroundProcessor` takes care of tasks that (1) need to happen periodically to keep
/// Rust-Lightning running properly, and (2) either can or should be run in the background. Its
/// [`ChannelManager`] persistence should be done in the background.
/// * Calling [`ChannelManager::timer_tick_occurred`] and [`PeerManager::timer_tick_occurred`]
/// at the appropriate intervals.
-/// * Calling [`NetworkGraph::remove_stale_channels`] (if a [`GossipSync`] with a [`NetworkGraph`]
-/// is provided to [`BackgroundProcessor::start`]).
+/// * Calling [`NetworkGraph::remove_stale_channels_and_tracking`] (if a [`GossipSync`] with a
+/// [`NetworkGraph`] is provided to [`BackgroundProcessor::start`]).
///
/// It will also call [`PeerManager::process_events`] periodically though this shouldn't be relied
/// upon as doing so may result in high latency.
// The network graph must not be pruned while rapid sync completion is pending
log_trace!($logger, "Assessing prunability of network graph");
if let Some(network_graph) = $gossip_sync.prunable_network_graph() {
- network_graph.remove_stale_channels();
+ network_graph.remove_stale_channels_and_tracking();
if let Err(e) = $persister.persist_graph(network_graph) {
log_error!($logger, "Error: Failed to persist network graph, check your disk and permissions {}", e)
Descriptor: 'static + SocketDescriptor + Send + Sync,
CMH: 'static + Deref + Send + Sync,
RMH: 'static + Deref + Send + Sync,
+ OMH: 'static + Deref + Send + Sync,
EH: 'static + EventHandler + Send,
PS: 'static + Deref + Send,
M: 'static + Deref<Target = ChainMonitor<Signer, CF, T, F, L, P>> + Send + Sync,
PGS: 'static + Deref<Target = P2PGossipSync<G, CA, L>> + Send + Sync,
RGS: 'static + Deref<Target = RapidGossipSync<G, L>> + Send,
UMH: 'static + Deref + Send + Sync,
- PM: 'static + Deref<Target = PeerManager<Descriptor, CMH, RMH, L, UMH>> + Send + Sync,
+ PM: 'static + Deref<Target = PeerManager<Descriptor, CMH, RMH, OMH, L, UMH>> + Send + Sync,
S: 'static + Deref<Target = SC> + Send + Sync,
SC: WriteableScore<'a>,
SleepFuture: core::future::Future<Output = bool>,
L::Target: 'static + Logger,
P::Target: 'static + Persist<Signer>,
CMH::Target: 'static + ChannelMessageHandler,
+ OMH::Target: 'static + OnionMessageHandler,
RMH::Target: 'static + RoutingMessageHandler,
UMH::Target: 'static + CustomMessageHandler,
PS::Target: 'static + Persister<'a, Signer, CW, T, K, F, L, SC>,
let mut should_continue = true;
define_run_body!(persister, event_handler, chain_monitor, channel_manager,
gossip_sync, peer_manager, logger, scorer, should_continue, {
- select! {
+ select_biased! {
_ = channel_manager.get_persistable_update_future().fuse() => true,
cont = sleeper(Duration::from_millis(100)).fuse() => {
should_continue = cont;
use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeysInterface, KeysManager};
use lightning::chain::transaction::OutPoint;
use lightning::get_event_msg;
- use lightning::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChainParameters, ChannelManager, SimpleArcChannelManager};
- use lightning::ln::features::{ChannelFeatures, InitFeatures};
+ use lightning::ln::channelmanager::{self, BREAKDOWN_TIMEOUT, ChainParameters, ChannelManager, SimpleArcChannelManager};
+ use lightning::ln::features::ChannelFeatures;
use lightning::ln::msgs::{ChannelMessageHandler, Init};
use lightning::ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler};
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
const EVENT_DEADLINE: u64 = 5 * FRESHNESS_TIMER;
- #[derive(Clone, Eq, Hash, PartialEq)]
+ #[derive(Clone, Hash, PartialEq, Eq)]
struct TestDescriptor{}
impl SocketDescriptor for TestDescriptor {
fn send_data(&mut self, _data: &[u8], _resume_read: bool) -> usize {
for i in 0..num_nodes {
for j in (i+1)..num_nodes {
- nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
}
}
macro_rules! begin_open_channel {
($node_a: expr, $node_b: expr, $channel_value: expr) => {{
$node_a.node.create_channel($node_b.node.get_our_node_id(), $channel_value, 100, 42, None).unwrap();
- $node_b.node.handle_open_channel(&$node_a.node.get_our_node_id(), InitFeatures::known(), &get_event_msg!($node_a, MessageSendEvent::SendOpenChannel, $node_b.node.get_our_node_id()));
- $node_a.node.handle_accept_channel(&$node_b.node.get_our_node_id(), InitFeatures::known(), &get_event_msg!($node_b, MessageSendEvent::SendAcceptChannel, $node_a.node.get_our_node_id()));
+ $node_b.node.handle_open_channel(&$node_a.node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!($node_a, MessageSendEvent::SendOpenChannel, $node_b.node.get_our_node_id()));
+ $node_a.node.handle_accept_channel(&$node_b.node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!($node_b, MessageSendEvent::SendAcceptChannel, $node_a.node.get_our_node_id()));
}}
}
// Initiate the background processors to watch each node.
let data_dir = nodes[0].persister.get_data_dir();
let persister = Arc::new(Persister::new(data_dir));
- let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger), random_seed_bytes);
- let invoice_payer = Arc::new(InvoicePayer::new(Arc::clone(&nodes[0].node), router, Arc::clone(&nodes[0].scorer), Arc::clone(&nodes[0].logger), |_: &_| {}, Retry::Attempts(2)));
+ let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger), random_seed_bytes, Arc::clone(&nodes[0].scorer));
+ let invoice_payer = Arc::new(InvoicePayer::new(Arc::clone(&nodes[0].node), router, Arc::clone(&nodes[0].logger), |_: &_| {}, Retry::Attempts(2)));
let event_handler = Arc::clone(&invoice_payer);
let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
assert!(bg_processor.stop().is_ok());
[dependencies]
bitcoin = "0.29.0"
lightning = { version = "0.0.111", path = "../lightning" }
-futures = { version = "0.3" }
+futures-util = { version = "0.3" }
tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }
struct ChainListenerSet<'a, L: chain::Listen + ?Sized>(Vec<(u32, &'a L)>);
impl<'a, L: chain::Listen + ?Sized> chain::Listen for ChainListenerSet<'a, L> {
+ // Needed to differentiate test expectations.
+ #[cfg(test)]
+ fn block_connected(&self, block: &bitcoin::Block, height: u32) {
+ for (starting_height, chain_listener) in self.0.iter() {
+ if height > *starting_height {
+ chain_listener.block_connected(block, height);
+ }
+ }
+ }
+
fn filtered_block_connected(&self, header: &BlockHeader, txdata: &chain::transaction::TransactionData, height: u32) {
for (starting_height, chain_listener) in self.0.iter() {
if height > *starting_height {
/// Returns the block for a given hash. A headers-only block source should return a `Transient`
/// error.
- fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block>;
+ fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, BlockData>;
/// Returns the hash of the best block and, optionally, its height.
///
}
/// The kind of `BlockSourceError`, either persistent or transient.
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BlockSourceErrorKind {
/// Indicates an error that won't resolve when retrying a request (e.g., invalid data).
Persistent,
/// A block header and some associated data. This information should be available from most block
/// sources (and, notably, is available in Bitcoin Core's RPC and REST interfaces).
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BlockHeaderData {
/// The block header itself.
pub header: BlockHeader,
pub chainwork: Uint256,
}
+/// A block including either all its transactions or only the block header.
+///
+/// [`BlockSource`] may be implemented to either always return full blocks or, in the case of
+/// compact block filters (BIP 157/158), return header-only blocks when no pertinent transactions
+/// match. See [`chain::Filter`] for details on how to notify a source of such transactions.
+pub enum BlockData {
+ /// A block containing all its transactions.
+ FullBlock(Block),
+ /// A block header for when the block does not contain any pertinent transactions.
+ HeaderOnly(BlockHeader),
+}
+
/// A lightweight client for keeping a listener in sync with the chain, allowing for Simplified
/// Payment Verification (SPV).
///
chain_poller: &mut P,
) -> Result<(), (BlockSourceError, Option<ValidatedBlockHeader>)> {
for header in connected_blocks.drain(..).rev() {
- let block = chain_poller
+ let height = header.height;
+ let block_data = chain_poller
.fetch_block(&header).await
.or_else(|e| Err((e, Some(new_tip))))?;
- debug_assert_eq!(block.block_hash, header.block_hash);
+ debug_assert_eq!(block_data.block_hash, header.block_hash);
+
+ match block_data.deref() {
+ BlockData::FullBlock(block) => {
+ self.chain_listener.block_connected(&block, height);
+ },
+ BlockData::HeaderOnly(header) => {
+ self.chain_listener.filtered_block_connected(&header, &[], height);
+ },
+ }
self.header_cache.block_connected(header.block_hash, header);
- self.chain_listener.block_connected(&block, header.height);
new_tip = header;
}
Ok(_) => panic!("Expected error"),
}
}
+
+ #[tokio::test]
+ async fn sync_from_chain_with_filtered_blocks() {
+ let mut chain = Blockchain::default().with_height(3).filtered_blocks();
+
+ let new_tip = chain.tip();
+ let old_tip = chain.at_height(1);
+ let chain_listener = &MockChainListener::new()
+ .expect_filtered_block_connected(*chain.at_height(2))
+ .expect_filtered_block_connected(*new_tip);
+ let mut notifier = ChainNotifier {
+ header_cache: &mut chain.header_cache(0..=1),
+ chain_listener,
+ };
+ let mut poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
+ match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
+ Err((e, _)) => panic!("Unexpected error: {:?}", e),
+ Ok(_) => {},
+ }
+ }
+
}
//! Adapters that make one or more [`BlockSource`]s simpler to poll for new chain tip transitions.
-use crate::{AsyncBlockSourceResult, BlockHeaderData, BlockSource, BlockSourceError, BlockSourceResult};
+use crate::{AsyncBlockSourceResult, BlockData, BlockHeaderData, BlockSource, BlockSourceError, BlockSourceResult};
-use bitcoin::blockdata::block::Block;
use bitcoin::hash_types::BlockHash;
use bitcoin::network::constants::Network;
use lightning::chain::BestBlock;
}
/// A chain tip relative to another chain tip in terms of block hash and chainwork.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChainTip {
/// A chain tip with the same hash as another chain's tip.
Common,
}
}
-impl Validate for Block {
+impl Validate for BlockData {
type T = ValidatedBlock;
fn validate(self, block_hash: BlockHash) -> BlockSourceResult<Self::T> {
- let pow_valid_block_hash = self.header
- .validate_pow(&self.header.target())
+ let header = match &self {
+ BlockData::FullBlock(block) => &block.header,
+ BlockData::HeaderOnly(header) => header,
+ };
+
+ let pow_valid_block_hash = header
+ .validate_pow(&header.target())
.or_else(|e| Err(BlockSourceError::persistent(e)))?;
if pow_valid_block_hash != block_hash {
return Err(BlockSourceError::persistent("invalid block hash"));
}
- if !self.check_merkle_root() {
- return Err(BlockSourceError::persistent("invalid merkle root"));
- }
+ if let BlockData::FullBlock(block) = &self {
+ if !block.check_merkle_root() {
+ return Err(BlockSourceError::persistent("invalid merkle root"));
+ }
- if !self.check_witness_commitment() {
- return Err(BlockSourceError::persistent("invalid witness commitment"));
+ if !block.check_witness_commitment() {
+ return Err(BlockSourceError::persistent("invalid witness commitment"));
+ }
}
Ok(ValidatedBlock { block_hash, inner: self })
}
/// A block header with validated proof of work and corresponding block hash.
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ValidatedBlockHeader {
pub(crate) block_hash: BlockHash,
inner: BlockHeaderData,
/// A block with validated data against its transaction list and corresponding block hash.
pub struct ValidatedBlock {
pub(crate) block_hash: BlockHash,
- inner: Block,
+ inner: BlockData,
}
impl std::ops::Deref for ValidatedBlock {
- type Target = Block;
+ type Target = BlockData;
fn deref(&self) -> &Self::Target {
&self.inner
pub trait Validate {}
impl Validate for crate::BlockHeaderData {}
- impl Validate for bitcoin::blockdata::block::Block {}
+ impl Validate for crate::BlockData {}
}
/// The canonical `Poll` implementation used for a single `BlockSource`.
//! Simple REST client implementation which implements [`BlockSource`] against a Bitcoin Core REST
//! endpoint.
-use crate::{BlockHeaderData, BlockSource, AsyncBlockSourceResult};
+use crate::{BlockData, BlockHeaderData, BlockSource, AsyncBlockSourceResult};
use crate::http::{BinaryResponse, HttpEndpoint, HttpClient, JsonResponse};
-use bitcoin::blockdata::block::Block;
use bitcoin::hash_types::BlockHash;
use bitcoin::hashes::hex::ToHex;
-use futures::lock::Mutex;
+use futures_util::lock::Mutex;
use std::convert::TryFrom;
use std::convert::TryInto;
})
}
- fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> {
+ fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, BlockData> {
Box::pin(async move {
let resource_path = format!("block/{}.bin", header_hash.to_hex());
- Ok(self.request_resource::<BinaryResponse, _>(&resource_path).await?)
+ Ok(BlockData::FullBlock(self.request_resource::<BinaryResponse, _>(&resource_path).await?))
})
}
//! Simple RPC client implementation which implements [`BlockSource`] against a Bitcoin Core RPC
//! endpoint.
-use crate::{BlockHeaderData, BlockSource, AsyncBlockSourceResult};
+use crate::{BlockData, BlockHeaderData, BlockSource, AsyncBlockSourceResult};
use crate::http::{HttpClient, HttpEndpoint, HttpError, JsonResponse};
-use bitcoin::blockdata::block::Block;
use bitcoin::hash_types::BlockHash;
use bitcoin::hashes::hex::ToHex;
-use futures::lock::Mutex;
+use futures_util::lock::Mutex;
use serde_json;
})
}
- fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> {
+ fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, BlockData> {
Box::pin(async move {
let header_hash = serde_json::json!(header_hash.to_hex());
let verbosity = serde_json::json!(0);
- Ok(self.call_method("getblock", &[header_hash, verbosity]).await?)
+ Ok(BlockData::FullBlock(self.call_method("getblock", &[header_hash, verbosity]).await?))
})
}
-use crate::{AsyncBlockSourceResult, BlockHeaderData, BlockSource, BlockSourceError, UnboundedCache};
+use crate::{AsyncBlockSourceResult, BlockData, BlockHeaderData, BlockSource, BlockSourceError, UnboundedCache};
use crate::poll::{Validate, ValidatedBlockHeader};
use bitcoin::blockdata::block::{Block, BlockHeader};
without_blocks: Option<std::ops::RangeFrom<usize>>,
without_headers: bool,
malformed_headers: bool,
+ filtered_blocks: bool,
}
impl Blockchain {
Self { malformed_headers: true, ..self }
}
+ pub fn filtered_blocks(self) -> Self {
+ Self { filtered_blocks: true, ..self }
+ }
+
pub fn fork_at_height(&self, height: usize) -> Self {
assert!(height + 1 < self.blocks.len());
let mut blocks = self.blocks.clone();
})
}
- fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> {
+ fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, BlockData> {
Box::pin(async move {
for (height, block) in self.blocks.iter().enumerate() {
if block.header.block_hash() == *header_hash {
}
}
- return Ok(block.clone());
+ if self.filtered_blocks {
+ return Ok(BlockData::HeaderOnly(block.header.clone()));
+ } else {
+ return Ok(BlockData::FullBlock(block.clone()));
+ }
}
}
Err(BlockSourceError::transient("block not found"))
pub struct MockChainListener {
expected_blocks_connected: RefCell<VecDeque<BlockHeaderData>>,
+ expected_filtered_blocks_connected: RefCell<VecDeque<BlockHeaderData>>,
expected_blocks_disconnected: RefCell<VecDeque<BlockHeaderData>>,
}
pub fn new() -> Self {
Self {
expected_blocks_connected: RefCell::new(VecDeque::new()),
+ expected_filtered_blocks_connected: RefCell::new(VecDeque::new()),
expected_blocks_disconnected: RefCell::new(VecDeque::new()),
}
}
self
}
+ pub fn expect_filtered_block_connected(self, block: BlockHeaderData) -> Self {
+ self.expected_filtered_blocks_connected.borrow_mut().push_back(block);
+ self
+ }
+
pub fn expect_block_disconnected(self, block: BlockHeaderData) -> Self {
self.expected_blocks_disconnected.borrow_mut().push_back(block);
self
}
impl chain::Listen for MockChainListener {
- fn filtered_block_connected(&self, header: &BlockHeader, _txdata: &chain::transaction::TransactionData, height: u32) {
+ fn block_connected(&self, block: &Block, height: u32) {
match self.expected_blocks_connected.borrow_mut().pop_front() {
None => {
- panic!("Unexpected block connected: {:?}", header.block_hash());
+ panic!("Unexpected block connected: {:?}", block.block_hash());
+ },
+ Some(expected_block) => {
+ assert_eq!(block.block_hash(), expected_block.header.block_hash());
+ assert_eq!(height, expected_block.height);
+ },
+ }
+ }
+
+ fn filtered_block_connected(&self, header: &BlockHeader, _txdata: &chain::transaction::TransactionData, height: u32) {
+ match self.expected_filtered_blocks_connected.borrow_mut().pop_front() {
+ None => {
+ panic!("Unexpected filtered block connected: {:?}", header.block_hash());
},
Some(expected_block) => {
assert_eq!(header.block_hash(), expected_block.header.block_hash());
panic!("Expected blocks connected: {:?}", expected_blocks_connected);
}
+ let expected_filtered_blocks_connected = self.expected_filtered_blocks_connected.borrow();
+ if !expected_filtered_blocks_connected.is_empty() {
+ panic!("Expected filtered_blocks connected: {:?}", expected_filtered_blocks_connected);
+ }
+
let expected_blocks_disconnected = self.expected_blocks_disconnected.borrow();
if !expected_blocks_disconnected.is_empty() {
panic!("Expected blocks disconnected: {:?}", expected_blocks_disconnected);
[features]
default = ["std"]
-no-std = ["hashbrown", "lightning/no-std", "core2/alloc"]
+no-std = ["hashbrown", "lightning/no-std"]
std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std", "bech32/std"]
[dependencies]
secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"] }
num-traits = { version = "0.2.8", default-features = false }
bitcoin_hashes = { version = "0.11", default-features = false }
-hashbrown = { version = "0.11", optional = true }
-core2 = { version = "0.3.0", default-features = false, optional = true }
+hashbrown = { version = "0.8", optional = true }
serde = { version = "1.0.118", optional = true }
[dev-dependencies]
/// Errors that indicate what is wrong with the invoice. They have some granularity for debug
/// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user.
#[allow(missing_docs)]
-#[derive(PartialEq, Debug, Clone)]
+#[derive(PartialEq, Eq, Debug, Clone)]
pub enum ParseError {
Bech32Error(bech32::Error),
ParseAmountError(ParseIntError),
/// Indicates that something went wrong while parsing or validating the invoice. Parsing errors
/// should be mostly seen as opaque and are only there for debugging reasons. Semantic errors
/// like wrong signatures, missing fields etc. could mean that someone tampered with the invoice.
-#[derive(PartialEq, Debug, Clone)]
+#[derive(PartialEq, Eq, Debug, Clone)]
pub enum ParseOrSemanticError {
/// The invoice couldn't be decoded
ParseError(ParseError),
self
}
- /// Sets the expiry time
+ /// Sets the expiry time, dropping the subsecond part (which is not representable in BOLT 11
+ /// invoices).
pub fn expiry_time(mut self, expiry_time: Duration) -> Self {
self.tagged_fields.push(TaggedField::ExpiryTime(ExpiryTime::from_duration(expiry_time)));
self
self.set_flags()
}
- /// Sets the timestamp to a duration since the Unix epoch.
+ /// Sets the timestamp to a duration since the Unix epoch, dropping the subsecond part (which
+ /// is not representable in BOLT 11 invoices).
pub fn duration_since_epoch(mut self, time: Duration) -> InvoiceBuilder<D, H, tb::True, C, S> {
match PositiveTimestamp::from_duration_since_epoch(time) {
Ok(t) => self.timestamp = Some(t),
///
/// Otherwise, returns a [`CreationError::TimestampOutOfBounds`].
pub fn from_unix_timestamp(unix_seconds: u64) -> Result<Self, CreationError> {
- Self::from_duration_since_epoch(Duration::from_secs(unix_seconds))
+ if unix_seconds <= MAX_TIMESTAMP {
+ Ok(Self(Duration::from_secs(unix_seconds)))
+ } else {
+ Err(CreationError::TimestampOutOfBounds)
+ }
}
/// Creates a `PositiveTimestamp` from a [`SystemTime`] with a corresponding Unix timestamp in
/// the range `0..=MAX_TIMESTAMP`.
///
+ /// Note that the subsecond part is dropped as it is not representable in BOLT 11 invoices.
+ ///
/// Otherwise, returns a [`CreationError::TimestampOutOfBounds`].
#[cfg(feature = "std")]
pub fn from_system_time(time: SystemTime) -> Result<Self, CreationError> {
/// Creates a `PositiveTimestamp` from a [`Duration`] since the Unix epoch in the range
/// `0..=MAX_TIMESTAMP`.
///
+ /// Note that the subsecond part is dropped as it is not representable in BOLT 11 invoices.
+ ///
/// Otherwise, returns a [`CreationError::TimestampOutOfBounds`].
pub fn from_duration_since_epoch(duration: Duration) -> Result<Self, CreationError> {
- if duration.as_secs() <= MAX_TIMESTAMP {
- Ok(PositiveTimestamp(duration))
- } else {
- Err(CreationError::TimestampOutOfBounds)
- }
+ Self::from_unix_timestamp(duration.as_secs())
}
/// Returns the Unix timestamp representing the stored time
ExpiryTime(Duration::from_secs(seconds))
}
- /// Construct an `ExpiryTime` from a `Duration`.
+ /// Construct an `ExpiryTime` from a `Duration`, dropping the sub-second part.
pub fn from_duration(duration: Duration) -> ExpiryTime {
- ExpiryTime(duration)
+ Self::from_seconds(duration.as_secs())
}
/// Returns the expiry time in seconds
}.unwrap();
assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
+ let mut payment_secret_features = InvoiceFeatures::empty();
+ payment_secret_features.set_payment_secret_required();
+
// Including payment secret and feature bits
let invoice = {
let mut invoice = invoice_template.clone();
invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
- invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
+ invoice.data.tagged_fields.push(Features(payment_secret_features.clone()).into());
invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
}.unwrap();
assert!(Invoice::from_signed(invoice).is_ok());
// Missing payment secret
let invoice = {
let mut invoice = invoice_template.clone();
- invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
+ invoice.data.tagged_fields.push(Features(payment_secret_features).into());
invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
}.unwrap();
assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
);
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));
- assert_eq!(invoice.features(), Some(&InvoiceFeatures::known()));
+
+ let mut expected_features = InvoiceFeatures::empty();
+ expected_features.set_variable_length_onion_required();
+ expected_features.set_payment_secret_required();
+ expected_features.set_basic_mpp_optional();
+ assert_eq!(invoice.features(), Some(&expected_features));
let raw_invoice = builder.build_raw().unwrap();
assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
//! and payee using information provided by the payer and from the payee's [`Invoice`], when
//! applicable.
//!
-//! [`InvoicePayer`] is parameterized by a [`LockableScore`], which it uses for scoring failed and
-//! successful payment paths upon receiving [`Event::PaymentPathFailed`] and
-//! [`Event::PaymentPathSuccessful`] events, respectively.
+//! [`InvoicePayer`] uses its [`Router`] parameterization for optionally notifying scorers upon
+//! receiving the [`Event::PaymentPathFailed`] and [`Event::PaymentPathSuccessful`] events.
+//! It also does the same for payment probe failure and success events using [`Event::ProbeFailed`]
+//! and [`Event::ProbeSuccessful`].
//!
//! [`InvoicePayer`] is capable of retrying failed payments. It accomplishes this by implementing
//! [`EventHandler`] which decorates a user-provided handler. It will intercept any
//! # extern crate lightning_invoice;
//! # extern crate secp256k1;
//! #
-//! # #[cfg(feature = "no-std")]
-//! # extern crate core2;
-//! #
+//! # use lightning::io;
//! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
//! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
//! # use lightning::ln::msgs::LightningError;
//! # use lightning::util::logger::{Logger, Record};
//! # use lightning::util::ser::{Writeable, Writer};
//! # use lightning_invoice::Invoice;
-//! # use lightning_invoice::payment::{InvoicePayer, Payer, Retry, Router};
+//! # use lightning_invoice::payment::{InFlightHtlcs, InvoicePayer, Payer, Retry, Router};
//! # use secp256k1::PublicKey;
//! # use std::cell::RefCell;
//! # use std::ops::Deref;
//! #
-//! # #[cfg(not(feature = "std"))]
-//! # use core2::io;
-//! # #[cfg(feature = "std")]
-//! # use std::io;
-//! #
//! # struct FakeEventProvider {}
//! # impl EventsProvider for FakeEventProvider {
//! # fn process_pending_events<H: Deref>(&self, handler: H) where H::Target: EventHandler {}
//! #
//! # struct FakeRouter {}
//! # impl Router for FakeRouter {
-//! # fn find_route<S: Score>(
+//! # fn find_route(
//! # &self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
-//! # first_hops: Option<&[&ChannelDetails]>, scorer: &S
+//! # first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InFlightHtlcs
//! # ) -> Result<Route, LightningError> { unimplemented!() }
+//! #
+//! # fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64) { unimplemented!() }
+//! # fn notify_payment_path_successful(&self, path: &[&RouteHop]) { unimplemented!() }
+//! # fn notify_payment_probe_successful(&self, path: &[&RouteHop]) { unimplemented!() }
+//! # fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) { unimplemented!() }
//! # }
//! #
//! # struct FakeScorer {}
//! # let router = FakeRouter {};
//! # let scorer = RefCell::new(FakeScorer {});
//! # let logger = FakeLogger {};
-//! let invoice_payer = InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+//! let invoice_payer = InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
//!
//! let invoice = "...";
//! if let Ok(invoice) = invoice.parse::<Invoice>() {
use bitcoin_hashes::sha256::Hash as Sha256;
use crate::prelude::*;
+use lightning::io;
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
use lightning::ln::msgs::LightningError;
use lightning::routing::gossip::NodeId;
-use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
use lightning::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters};
use lightning::util::errors::APIError;
use lightning::util::events::{Event, EventHandler};
use lightning::util::logger::Logger;
+use lightning::util::ser::Writeable;
use time_utils::Time;
use crate::sync::Mutex;
/// See [module-level documentation] for details.
///
/// [module-level documentation]: crate::payment
-pub type InvoicePayer<P, R, S, L, E> = InvoicePayerUsingTime::<P, R, S, L, E, ConfiguredTime>;
+pub type InvoicePayer<P, R, L, E> = InvoicePayerUsingTime::<P, R, L, E, ConfiguredTime>;
#[cfg(not(feature = "no-std"))]
type ConfiguredTime = std::time::Instant;
type ConfiguredTime = time_utils::Eternity;
/// (C-not exported) generally all users should use the [`InvoicePayer`] type alias.
-pub struct InvoicePayerUsingTime<P: Deref, R: Router, S: Deref, L: Deref, E: EventHandler, T: Time>
+pub struct InvoicePayerUsingTime<P: Deref, R: Router, L: Deref, E: EventHandler, T: Time>
where
P::Target: Payer,
- S::Target: for <'a> LockableScore<'a>,
L::Target: Logger,
{
payer: P,
router: R,
- scorer: S,
logger: L,
event_handler: E,
/// Caches the overall attempts at making a payment, which is updated prior to retrying.
}
}
-/// Used to store information about all the HTLCs that are inflight across all payment attempts
-struct AccountForInFlightHtlcs<'a, S: Score> {
- scorer: &'a mut S,
- /// Maps a channel's short channel id and its direction to the liquidity used up.
- inflight_htlcs: HashMap<(u64, bool), u64>,
-}
-
-#[cfg(c_bindings)]
-impl<'a, S:Score> lightning::util::ser::Writeable for AccountForInFlightHtlcs<'a, S> {
- fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), std::io::Error> { self.scorer.write(writer) }
-}
-
-impl<'a, S: Score> Score for AccountForInFlightHtlcs<'a, S> {
- fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
- if let Some(used_liqudity) = self.inflight_htlcs.get(&(short_channel_id, source < target)) {
- let usage = ChannelUsage {
- inflight_htlc_msat: usage.inflight_htlc_msat + used_liqudity,
- ..usage
- };
-
- self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
- } else {
- self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
- }
- }
-
- fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
- self.scorer.payment_path_failed(path, short_channel_id)
- }
-
- fn payment_path_successful(&mut self, path: &[&RouteHop]) {
- self.scorer.payment_path_successful(path)
- }
-
- fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
- self.scorer.probe_failed(path, short_channel_id)
- }
-
- fn probe_successful(&mut self, path: &[&RouteHop]) {
- self.scorer.probe_successful(path)
- }
-}
-
/// Storing minimal payment attempts information required for determining if a outbound payment can
/// be retried.
#[derive(Clone, Copy)]
/// A trait defining behavior for routing an [`Invoice`] payment.
pub trait Router {
/// Finds a [`Route`] between `payer` and `payee` for a payment with the given values.
- fn find_route<S: Score>(
+ fn find_route(
&self, payer: &PublicKey, route_params: &RouteParameters, payment_hash: &PaymentHash,
- first_hops: Option<&[&ChannelDetails]>, scorer: &S
+ first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
) -> Result<Route, LightningError>;
+ /// Lets the router know that payment through a specific path has failed.
+ fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64);
+ /// Lets the router know that payment through a specific path was successful.
+ fn notify_payment_path_successful(&self, path: &[&RouteHop]);
+ /// Lets the router know that a payment probe was successful.
+ fn notify_payment_probe_successful(&self, path: &[&RouteHop]);
+ /// Lets the router know that a payment probe failed.
+ fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64);
}
/// Strategies available to retry payment path failures for an [`Invoice`].
Sending(PaymentSendFailure),
}
-impl<P: Deref, R: Router, S: Deref, L: Deref, E: EventHandler, T: Time> InvoicePayerUsingTime<P, R, S, L, E, T>
+impl<P: Deref, R: Router, L: Deref, E: EventHandler, T: Time> InvoicePayerUsingTime<P, R, L, E, T>
where
P::Target: Payer,
- S::Target: for <'a> LockableScore<'a>,
L::Target: Logger,
{
/// Creates an invoice payer that retries failed payment paths.
/// Will forward any [`Event::PaymentPathFailed`] events to the decorated `event_handler` once
/// `retry` has been exceeded for a given [`Invoice`].
pub fn new(
- payer: P, router: R, scorer: S, logger: L, event_handler: E, retry: Retry
+ payer: P, router: R, logger: L, event_handler: E, retry: Retry
) -> Self {
Self {
payer,
router,
- scorer,
logger,
event_handler,
payment_cache: Mutex::new(HashMap::new()),
let inflight_htlcs = self.create_inflight_map();
let route = self.router.find_route(
&payer, ¶ms, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
- &AccountForInFlightHtlcs { scorer: &mut self.scorer.lock(), inflight_htlcs }
+ inflight_htlcs
).map_err(|e| PaymentError::Routing(e))?;
match send_payment(&route) {
},
PaymentSendFailure::PartialFailure { failed_paths_retry, payment_id, results } => {
// If a `PartialFailure` event returns a result that is an `Ok()`, it means that
- // part of our payment is retried. When we receive `MonitorUpdateFailed`, it
+ // part of our payment is retried. When we receive `MonitorUpdateInProgress`, it
// means that we are still waiting for our channel monitor update to be completed.
for (result, path) in results.iter().zip(route.paths.into_iter()) {
match result {
- Ok(_) | Err(APIError::MonitorUpdateFailed) => {
+ Ok(_) | Err(APIError::MonitorUpdateInProgress) => {
self.process_path_inflight_htlcs(payment_hash, path);
},
_ => {},
let route = self.router.find_route(
&payer, ¶ms, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
- &AccountForInFlightHtlcs { scorer: &mut self.scorer.lock(), inflight_htlcs }
+ inflight_htlcs
);
if route.is_err() {
},
Err(PaymentSendFailure::PartialFailure { failed_paths_retry, results, .. }) => {
// If a `PartialFailure` error contains a result that is an `Ok()`, it means that
- // part of our payment is retried. When we receive `MonitorUpdateFailed`, it
+ // part of our payment is retried. When we receive `MonitorUpdateInProgress`, it
// means that we are still waiting for our channel monitor update to complete.
for (result, path) in results.iter().zip(route.unwrap().paths.into_iter()) {
match result {
- Ok(_) | Err(APIError::MonitorUpdateFailed) => {
+ Ok(_) | Err(APIError::MonitorUpdateInProgress) => {
self.process_path_inflight_htlcs(payment_hash, path);
},
_ => {},
///
/// This function should be called whenever we need information about currently used up liquidity
/// across payments.
- fn create_inflight_map(&self) -> HashMap<(u64, bool), u64> {
+ fn create_inflight_map(&self) -> InFlightHtlcs {
let mut total_inflight_map: HashMap<(u64, bool), u64> = HashMap::new();
// Make an attempt at finding existing payment information from `payment_cache`. If it
// does not exist, it probably is a fresh payment and we can just return an empty
}
}
- total_inflight_map
+ InFlightHtlcs(total_inflight_map)
}
}
} else { false }
}
-impl<P: Deref, R: Router, S: Deref, L: Deref, E: EventHandler, T: Time> EventHandler for InvoicePayerUsingTime<P, R, S, L, E, T>
+impl<P: Deref, R: Router, L: Deref, E: EventHandler, T: Time> EventHandler for InvoicePayerUsingTime<P, R, L, E, T>
where
P::Target: Payer,
- S::Target: for <'a> LockableScore<'a>,
L::Target: Logger,
{
fn handle_event(&self, event: &Event) {
} => {
if let Some(short_channel_id) = short_channel_id {
let path = path.iter().collect::<Vec<_>>();
- self.scorer.lock().payment_path_failed(&path, *short_channel_id);
+ self.router.notify_payment_path_failed(&path, *short_channel_id)
}
if payment_id.is_none() {
},
Event::PaymentPathSuccessful { path, .. } => {
let path = path.iter().collect::<Vec<_>>();
- self.scorer.lock().payment_path_successful(&path);
+ self.router.notify_payment_path_successful(&path);
},
Event::PaymentSent { payment_hash, .. } => {
let mut payment_cache = self.payment_cache.lock().unwrap();
Event::ProbeSuccessful { payment_hash, path, .. } => {
log_trace!(self.logger, "Probe payment {} of {}msat was successful", log_bytes!(payment_hash.0), path.last().unwrap().fee_msat);
let path = path.iter().collect::<Vec<_>>();
- self.scorer.lock().probe_successful(&path);
+ self.router.notify_payment_probe_successful(&path);
},
Event::ProbeFailed { payment_hash, path, short_channel_id, .. } => {
if let Some(short_channel_id) = short_channel_id {
log_trace!(self.logger, "Probe payment {} of {}msat failed at channel {}", log_bytes!(payment_hash.0), path.last().unwrap().fee_msat, *short_channel_id);
let path = path.iter().collect::<Vec<_>>();
- self.scorer.lock().probe_failed(&path, *short_channel_id);
+ self.router.notify_payment_probe_failed(&path, *short_channel_id);
}
},
_ => {},
}
}
+/// A map with liquidity value (in msat) keyed by a short channel id and the direction the HTLC
+/// is traveling in. The direction boolean is determined by checking if the HTLC source's public
+/// key is less than its destination. See [`InFlightHtlcs::used_liquidity_msat`] for more
+/// details.
+pub struct InFlightHtlcs(HashMap<(u64, bool), u64>);
+
+impl InFlightHtlcs {
+ /// Returns liquidity in msat given the public key of the HTLC source, target, and short channel
+ /// id.
+ pub fn used_liquidity_msat(&self, source: &NodeId, target: &NodeId, channel_scid: u64) -> Option<u64> {
+ self.0.get(&(channel_scid, source < target)).map(|v| *v)
+ }
+}
+
+impl Writeable for InFlightHtlcs {
+ fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> { self.0.write(writer) }
+}
+
+impl lightning::util::ser::Readable for InFlightHtlcs {
+ fn read<R: io::Read>(reader: &mut R) -> Result<Self, lightning::ln::msgs::DecodeError> {
+ let infight_map: HashMap<(u64, bool), u64> = lightning::util::ser::Readable::read(reader)?;
+ Ok(Self(infight_map))
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
use crate::{InvoiceBuilder, Currency};
- use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
+ use utils::{ScorerAccountingForInFlightHtlcs, create_invoice_from_channelmanager_and_duration_since_epoch};
use bitcoin_hashes::sha256::Hash as Sha256;
use lightning::ln::PaymentPreimage;
- use lightning::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures};
+ use lightning::ln::channelmanager;
+ use lightning::ln::features::{ChannelFeatures, NodeFeatures};
use lightning::ln::functional_test_utils::*;
use lightning::ln::msgs::{ChannelMessageHandler, ErrorAction, LightningError};
use lightning::routing::gossip::{EffectiveCapacity, NodeId};
use lightning::routing::router::{PaymentParameters, Route, RouteHop};
- use lightning::routing::scoring::ChannelUsage;
+ use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
use lightning::util::test_utils::TestLogger;
use lightning::util::errors::APIError;
use lightning::util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
use secp256k1::{SecretKey, PublicKey, Secp256k1};
use std::cell::RefCell;
use std::collections::VecDeque;
+ use std::ops::DerefMut;
use std::time::{SystemTime, Duration};
use time_utils::tests::SinceEpoch;
use DEFAULT_EXPIRY_TIME;
- use lightning::util::errors::APIError::{ChannelUnavailable, MonitorUpdateFailed};
+ use lightning::util::errors::APIError::{ChannelUnavailable, MonitorUpdateInProgress};
fn invoice(payment_preimage: PaymentPreimage) -> Invoice {
let payment_hash = Sha256::hash(&payment_preimage.0);
let final_value_msat = invoice.amount_milli_satoshis().unwrap();
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
let payer = TestPayer::new()
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2))
.expect_send(Amount::OnRetry(final_value_msat / 2));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
assert!(invoice_payer.pay_invoice(&invoice).is_ok());
}
let payer = TestPayer::new()
.expect_send(Amount::OnRetry(final_value_msat / 2))
.expect_send(Amount::OnRetry(final_value_msat / 2));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(PaymentId([1; 32]));
let event = Event::PaymentPathFailed {
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2))
.expect_send(Amount::OnRetry(final_value_msat / 2));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
- type InvoicePayerUsingSinceEpoch <P, R, S, L, E> = InvoicePayerUsingTime::<P, R, S, L, E, SinceEpoch>;
+ type InvoicePayerUsingSinceEpoch <P, R, L, E> = InvoicePayerUsingTime::<P, R, L, E, SinceEpoch>;
let invoice_payer =
- InvoicePayerUsingSinceEpoch::new(&payer, router, &scorer, &logger, event_handler, Retry::Timeout(Duration::from_secs(120)));
+ InvoicePayerUsingSinceEpoch::new(&payer, router, &logger, event_handler, Retry::Timeout(Duration::from_secs(120)));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
let final_value_msat = invoice.amount_milli_satoshis().unwrap();
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };
let payer = TestPayer::new();
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_preimage = PaymentPreimage([1; 32]);
let invoice = expired_invoice(payment_preimage);
let final_value_msat = invoice.amount_milli_satoshis().unwrap();
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
.fails_on_attempt(2)
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
let final_value_msat = invoice.amount_milli_satoshis().unwrap();
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
assert_eq!(*payer.attempts.borrow(), 1);
let payer = TestPayer::new()
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
fn fails_paying_invoice_with_routing_errors() {
let payer = TestPayer::new();
let router = FailingRouter {};
- let scorer = RefCell::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, |_: &_| {}, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, |_: &_| {}, Retry::Attempts(0));
let payment_preimage = PaymentPreimage([1; 32]);
let invoice = invoice(payment_preimage);
let payer = TestPayer::new()
.fails_on_attempt(1)
.expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, |_: &_| {}, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, |_: &_| {}, Retry::Attempts(0));
match invoice_payer.pay_invoice(&invoice) {
Err(PaymentError::Sending(_)) => {},
let final_value_msat = 100;
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
let payment_id =
Some(invoice_payer.pay_zero_value_invoice(&invoice, final_value_msat).unwrap());
let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };
let payer = TestPayer::new();
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
let payment_preimage = PaymentPreimage([1; 32]);
let invoice = invoice(payment_preimage);
let payer = TestPayer::new()
.expect_send(Amount::Spontaneous(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_pubkey(
pubkey, payment_preimage, final_value_msat, final_cltv_expiry_delta
let payer = TestPayer::new()
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new().expect(TestResult::PaymentFailure {
+ let scorer = TestScorer::new().expect(TestResult::PaymentFailure {
path: path.clone(), short_channel_id: path[0].short_channel_id,
- }));
+ });
+ let router = TestRouter::new(scorer);
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
let event = Event::PaymentPathFailed {
// Expect that scorer is given short_channel_id upon handling the event.
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new()
+ let scorer = TestScorer::new()
.expect(TestResult::PaymentSuccess { path: route.paths[0].clone() })
- .expect(TestResult::PaymentSuccess { path: route.paths[1].clone() })
- );
+ .expect(TestResult::PaymentSuccess { path: route.paths[1].clone() });
+ let router = TestRouter::new(scorer);
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
let payment_id = invoice_payer.pay_invoice(&invoice).unwrap();
let event = Event::PaymentPathSuccessful {
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
let final_value_msat = invoice.amount_milli_satoshis().unwrap();
let route = TestRouter::route_for_value(final_value_msat);
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
let payment_id = invoice_payer.pay_invoice(&invoice).unwrap();
let inflight_map = invoice_payer.create_inflight_map();
// First path check
- assert_eq!(inflight_map.get(&(0, false)).unwrap().clone(), 94);
- assert_eq!(inflight_map.get(&(1, true)).unwrap().clone(), 84);
- assert_eq!(inflight_map.get(&(2, false)).unwrap().clone(), 64);
+ assert_eq!(inflight_map.0.get(&(0, false)).unwrap().clone(), 94);
+ assert_eq!(inflight_map.0.get(&(1, true)).unwrap().clone(), 84);
+ assert_eq!(inflight_map.0.get(&(2, false)).unwrap().clone(), 64);
// Second path check
- assert_eq!(inflight_map.get(&(3, false)).unwrap().clone(), 74);
- assert_eq!(inflight_map.get(&(4, false)).unwrap().clone(), 64);
+ assert_eq!(inflight_map.0.get(&(3, false)).unwrap().clone(), 74);
+ assert_eq!(inflight_map.0.get(&(4, false)).unwrap().clone(), 64);
invoice_payer.handle_event(&Event::PaymentPathSuccessful {
payment_id, payment_hash, path: route.paths[0].clone()
let inflight_map = invoice_payer.create_inflight_map();
- assert_eq!(inflight_map.get(&(0, false)), None);
- assert_eq!(inflight_map.get(&(1, true)), None);
- assert_eq!(inflight_map.get(&(2, false)), None);
+ assert_eq!(inflight_map.0.get(&(0, false)), None);
+ assert_eq!(inflight_map.0.get(&(1, true)), None);
+ assert_eq!(inflight_map.0.get(&(2, false)), None);
// Second path should still be inflight
- assert_eq!(inflight_map.get(&(3, false)).unwrap().clone(), 74);
- assert_eq!(inflight_map.get(&(4, false)).unwrap().clone(), 64)
+ assert_eq!(inflight_map.0.get(&(3, false)).unwrap().clone(), 74);
+ assert_eq!(inflight_map.0.get(&(4, false)).unwrap().clone(), 64)
}
#[test]
.expect_send(Amount::ForInvoice(final_value_msat));
let final_value_msat = payment_invoice.amount_milli_satoshis().unwrap();
let route = TestRouter::route_for_value(final_value_msat);
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new()
+ let scorer = TestScorer::new()
// 1st invoice, 1st path
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
.expect_usage(ChannelUsage { amount_msat: 84, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
.expect_usage(ChannelUsage { amount_msat: 94, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
// 2nd invoice, 2nd path
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 64, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 74, inflight_htlc_msat: 74, effective_capacity: EffectiveCapacity::Unknown } )
- );
+ .expect_usage(ChannelUsage { amount_msat: 74, inflight_htlc_msat: 74, effective_capacity: EffectiveCapacity::Unknown } );
+ let router = TestRouter::new(scorer);
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
// Succeed 1st path, leave 2nd path inflight
let payment_id = invoice_payer.pay_invoice(&payment_invoice).unwrap();
.expect_send(Amount::OnRetry(final_value_msat / 2))
.expect_send(Amount::OnRetry(final_value_msat / 4));
let final_value_msat = payment_invoice.amount_milli_satoshis().unwrap();
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new()
+ let scorer = TestScorer::new()
// 1st invoice, 1st path
.expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
.expect_usage(ChannelUsage { amount_msat: 84, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
.expect_usage(ChannelUsage { amount_msat: 46, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
// Retry 2, 2nd path
.expect_usage(ChannelUsage { amount_msat: 16, inflight_htlc_msat: 64 + 32, effective_capacity: EffectiveCapacity::Unknown } )
- .expect_usage(ChannelUsage { amount_msat: 26, inflight_htlc_msat: 74 + 32 + 10, effective_capacity: EffectiveCapacity::Unknown } )
- );
+ .expect_usage(ChannelUsage { amount_msat: 26, inflight_htlc_msat: 74 + 32 + 10, effective_capacity: EffectiveCapacity::Unknown } );
+ let router = TestRouter::new(scorer);
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
// Fail 1st path, leave 2nd path inflight
let payment_id = Some(invoice_payer.pay_invoice(&payment_invoice).unwrap());
.fails_with_partial_failure(
retry.clone(), OnAttempt(1),
Some(vec![
- Err(ChannelUnavailable { err: "abc".to_string() }), Err(MonitorUpdateFailed)
+ Err(ChannelUnavailable { err: "abc".to_string() }), Err(MonitorUpdateInProgress)
]))
.expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
let inflight_map = invoice_payer.create_inflight_map();
- // Only the second path, which failed with `MonitorUpdateFailed` should be added to our
+ // Only the second path, which failed with `MonitorUpdateInProgress` should be added to our
// inflight map because retries are disabled.
- assert_eq!(inflight_map.len(), 2);
+ assert_eq!(inflight_map.0.len(), 2);
}
#[test]
.fails_with_partial_failure(
retry.clone(), OnAttempt(1),
Some(vec![
- Ok(()), Err(MonitorUpdateFailed)
+ Ok(()), Err(MonitorUpdateInProgress)
]))
.expect_send(Amount::ForInvoice(final_value_msat));
- let router = TestRouter {};
- let scorer = RefCell::new(TestScorer::new());
+ let router = TestRouter::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
- InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+ InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
let inflight_map = invoice_payer.create_inflight_map();
// All paths successful, hence we check of the existence of all 5 hops.
- assert_eq!(inflight_map.len(), 5);
+ assert_eq!(inflight_map.0.len(), 5);
}
- struct TestRouter;
+ struct TestRouter {
+ scorer: RefCell<TestScorer>,
+ }
impl TestRouter {
+ fn new(scorer: TestScorer) -> Self {
+ TestRouter { scorer: RefCell::new(scorer) }
+ }
+
fn route_for_value(final_value_msat: u64) -> Route {
Route {
paths: vec![
}
impl Router for TestRouter {
- fn find_route<S: Score>(
+ fn find_route(
&self, payer: &PublicKey, route_params: &RouteParameters, _payment_hash: &PaymentHash,
- _first_hops: Option<&[&ChannelDetails]>, scorer: &S
+ _first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
) -> Result<Route, LightningError> {
// Simulate calling the Scorer just as you would in find_route
let route = Self::route_for_value(route_params.final_value_msat);
+ let mut locked_scorer = self.scorer.lock();
+ let scorer = ScorerAccountingForInFlightHtlcs::new(locked_scorer.deref_mut(), inflight_htlcs);
for path in route.paths {
let mut aggregate_msat = 0u64;
for (idx, hop) in path.iter().rev().enumerate() {
payment_params: Some(route_params.payment_params.clone()), ..Self::route_for_value(route_params.final_value_msat)
})
}
+
+ fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
+ self.scorer.lock().payment_path_failed(path, short_channel_id);
+ }
+
+ fn notify_payment_path_successful(&self, path: &[&RouteHop]) {
+ self.scorer.lock().payment_path_successful(path);
+ }
+
+ fn notify_payment_probe_successful(&self, path: &[&RouteHop]) {
+ self.scorer.lock().probe_successful(path);
+ }
+
+ fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
+ self.scorer.lock().probe_failed(path, short_channel_id);
+ }
}
struct FailingRouter;
impl Router for FailingRouter {
- fn find_route<S: Score>(
+ fn find_route(
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
- _first_hops: Option<&[&ChannelDetails]>, _scorer: &S
+ _first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InFlightHtlcs
) -> Result<Route, LightningError> {
Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError })
}
+
+ fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
+
+ fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {}
+
+ fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {}
+
+ fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
}
struct TestScorer {
#[cfg(c_bindings)]
impl lightning::util::ser::Writeable for TestScorer {
- fn write<W: lightning::util::ser::Writer>(&self, _: &mut W) -> Result<(), std::io::Error> { unreachable!(); }
+ fn write<W: lightning::util::ser::Writer>(&self, _: &mut W) -> Result<(), lightning::io::Error> { unreachable!(); }
}
impl Score for TestScorer {
Some(TestResult::PaymentSuccess { path }) => {
panic!("Unexpected successful payment path: {:?}", path)
},
- None => panic!("Unexpected payment_path_failed call: {:?}", actual_path),
+ None => panic!("Unexpected notify_payment_path_failed call: {:?}", actual_path),
}
}
}
Some(TestResult::PaymentSuccess { path }) => {
assert_eq!(actual_path, &path.iter().collect::<Vec<_>>()[..]);
},
- None => panic!("Unexpected payment_path_successful call: {:?}", actual_path),
+ None => panic!("Unexpected notify_payment_path_successful call: {:?}", actual_path),
}
}
}
Some(TestResult::PaymentSuccess { path }) => {
panic!("Unexpected successful payment path: {:?}", path)
},
- None => panic!("Unexpected payment_path_failed call: {:?}", actual_path),
+ None => panic!("Unexpected notify_payment_path_failed call: {:?}", actual_path),
}
}
}
Some(TestResult::PaymentSuccess { path }) => {
panic!("Unexpected successful payment path: {:?}", path)
},
- None => panic!("Unexpected payment_path_successful call: {:?}", actual_path),
+ None => panic!("Unexpected notify_payment_path_successful call: {:?}", actual_path),
}
}
}
}
fn fails_on_attempt(self, attempt: usize) -> Self {
- let failure = PaymentSendFailure::ParameterError(APIError::MonitorUpdateFailed);
+ let failure = PaymentSendFailure::ParameterError(APIError::MonitorUpdateInProgress);
self.fails_with(failure, OnAttempt(attempt))
}
struct ManualRouter(RefCell<VecDeque<Result<Route, LightningError>>>);
impl Router for ManualRouter {
- fn find_route<S: Score>(
+ fn find_route(
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
- _first_hops: Option<&[&ChannelDetails]>, _scorer: &S
+ _first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InFlightHtlcs
) -> Result<Route, LightningError> {
self.0.borrow_mut().pop_front().unwrap()
}
+
+ fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
+
+ fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {}
+
+ fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {}
+
+ fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
}
impl ManualRouter {
fn expect_find_route(&self, result: Result<Route, LightningError>) {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let chans = nodes[0].node.list_usable_channels();
let mut route = Route {
paths: vec![
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chans[0].short_channel_id.unwrap(),
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 10_000,
cltv_expiry_delta: 100,
}],
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chans[1].short_channel_id.unwrap(),
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_001, // Our default max-HTLC-value is 10% of the channel value, which this is one more than
cltv_expiry_delta: 100,
}],
router.expect_find_route(Ok(route.clone()));
let event_handler = |_: &_| { panic!(); };
- let scorer = RefCell::new(TestScorer::new());
- let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, Retry::Attempts(1));
+ let invoice_payer = InvoicePayer::new(nodes[0].node, router, nodes[0].logger, event_handler, Retry::Attempts(1));
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
&nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let chans = nodes[0].node.list_usable_channels();
let mut route = Route {
paths: vec![
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chans[0].short_channel_id.unwrap(),
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_001, // Our default max-HTLC-value is 10% of the channel value, which this is one more than
cltv_expiry_delta: 100,
}],
router.expect_find_route(Ok(route.clone()));
let event_handler = |_: &_| { panic!(); };
- let scorer = RefCell::new(TestScorer::new());
- let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, Retry::Attempts(1));
+ let invoice_payer = InvoicePayer::new(nodes[0].node, router, nodes[0].logger, event_handler, Retry::Attempts(1));
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
&nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1_scid = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_2_scid = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 0, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ let chan_1_scid = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_2_scid = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
let mut route = Route {
paths: vec![
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_1_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 0,
cltv_expiry_delta: 100,
}, RouteHop {
pubkey: nodes[2].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_2_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_000,
cltv_expiry_delta: 100,
}],
vec![RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_1_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 0,
cltv_expiry_delta: 100,
}, RouteHop {
pubkey: nodes[2].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_2_scid,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 100_000_000,
cltv_expiry_delta: 100,
}]
let event_checker = expected_events.borrow_mut().pop_front().unwrap();
event_checker(event);
};
- let scorer = RefCell::new(TestScorer::new());
- let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, Retry::Attempts(1));
+ let invoice_payer = InvoicePayer::new(nodes[0].node, router, nodes[0].logger, event_handler, Retry::Attempts(1));
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
&nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
//! Convenient utilities to create an invoice.
use {CreationError, Currency, Invoice, InvoiceBuilder, SignOrCreationError};
-use payment::{Payer, Router};
+use payment::{InFlightHtlcs, Payer, Router};
use crate::{prelude::*, Description, InvoiceDescription, Sha256};
use bech32::ToBase32;
use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA};
use lightning::ln::inbound_payment::{create, create_from_hash, ExpandedKey};
use lightning::ln::msgs::LightningError;
-use lightning::routing::gossip::{NetworkGraph, RoutingFees};
-use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
-use lightning::routing::scoring::Score;
+use lightning::routing::gossip::{NetworkGraph, NodeId, RoutingFees};
+use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route, RouteHop};
+use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
use lightning::util::logger::Logger;
use secp256k1::PublicKey;
use core::ops::Deref;
}
/// A [`Router`] implemented using [`find_route`].
-pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref> where L::Target: Logger {
+pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> where
+ L::Target: Logger,
+ S::Target: for <'a> LockableScore<'a>,
+{
network_graph: G,
logger: L,
random_seed_bytes: Mutex<[u8; 32]>,
+ scorer: S
}
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> DefaultRouter<G, L> where L::Target: Logger {
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> DefaultRouter<G, L, S> where
+ L::Target: Logger,
+ S::Target: for <'a> LockableScore<'a>,
+{
/// Creates a new router using the given [`NetworkGraph`], a [`Logger`], and a randomness source
/// `random_seed_bytes`.
- pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32]) -> Self {
+ pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S) -> Self {
let random_seed_bytes = Mutex::new(random_seed_bytes);
- Self { network_graph, logger, random_seed_bytes }
+ Self { network_graph, logger, random_seed_bytes, scorer }
}
}
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> Router for DefaultRouter<G, L>
-where L::Target: Logger {
- fn find_route<S: Score>(
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultRouter<G, L, S> where
+ L::Target: Logger,
+ S::Target: for <'a> LockableScore<'a>,
+{
+ fn find_route(
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
- first_hops: Option<&[&ChannelDetails]>, scorer: &S
+ first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
) -> Result<Route, LightningError> {
let random_seed_bytes = {
let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
*locked_random_seed_bytes = sha256::Hash::hash(&*locked_random_seed_bytes).into_inner();
*locked_random_seed_bytes
};
- find_route(payer, params, &self.network_graph, first_hops, &*self.logger, scorer, &random_seed_bytes)
+
+ find_route(
+ payer, params, &self.network_graph, first_hops, &*self.logger,
+ &ScorerAccountingForInFlightHtlcs::new(&mut self.scorer.lock(), inflight_htlcs),
+ &random_seed_bytes
+ )
+ }
+
+ fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
+ self.scorer.lock().payment_path_failed(path, short_channel_id);
+ }
+
+ fn notify_payment_path_successful(&self, path: &[&RouteHop]) {
+ self.scorer.lock().payment_path_successful(path);
+ }
+
+ fn notify_payment_probe_successful(&self, path: &[&RouteHop]) {
+ self.scorer.lock().probe_successful(path);
+ }
+
+ fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
+ self.scorer.lock().probe_failed(path, short_channel_id);
}
}
}
}
+
+/// Used to store information about all the HTLCs that are inflight across all payment attempts.
+pub(crate) struct ScorerAccountingForInFlightHtlcs<'a, S: Score> {
+ scorer: &'a mut S,
+ /// Maps a channel's short channel id and its direction to the liquidity used up.
+ inflight_htlcs: InFlightHtlcs,
+}
+
+impl<'a, S: Score> ScorerAccountingForInFlightHtlcs<'a, S> {
+ pub(crate) fn new(scorer: &'a mut S, inflight_htlcs: InFlightHtlcs) -> Self {
+ ScorerAccountingForInFlightHtlcs {
+ scorer,
+ inflight_htlcs
+ }
+ }
+}
+
+#[cfg(c_bindings)]
+impl<'a, S:Score> lightning::util::ser::Writeable for ScorerAccountingForInFlightHtlcs<'a, S> {
+ fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), lightning::io::Error> { self.scorer.write(writer) }
+}
+
+impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
+ fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
+ if let Some(used_liqudity) = self.inflight_htlcs.used_liquidity_msat(
+ source, target, short_channel_id
+ ) {
+ let usage = ChannelUsage {
+ inflight_htlc_msat: usage.inflight_htlc_msat + used_liqudity,
+ ..usage
+ };
+
+ self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+ } else {
+ self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+ }
+ }
+
+ fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) { unreachable!() }
+
+ fn payment_path_successful(&mut self, _path: &[&RouteHop]) { unreachable!() }
+
+ fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) { unreachable!() }
+
+ fn probe_successful(&mut self, _path: &[&RouteHop]) { unreachable!() }
+}
+
+
#[cfg(test)]
mod test {
use core::time::Duration;
use bitcoin_hashes::sha256::Hash as Sha256;
use lightning::chain::keysinterface::PhantomKeysManager;
use lightning::ln::{PaymentPreimage, PaymentHash};
- use lightning::ln::channelmanager::{PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY};
+ use lightning::ln::channelmanager::{self, PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY};
use lightning::ln::functional_test_utils::*;
- use lightning::ln::features::InitFeatures;
use lightning::ln::msgs::ChannelMessageHandler;
use lightning::routing::router::{PaymentParameters, RouteParameters, find_route};
use lightning::util::enforcing_trait_impls::EnforcingSigner;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let non_default_invoice_expiry_secs = 4200;
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
&nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000), "test".to_string(),
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- let chan_2_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut scid_aliases = HashSet::new();
scid_aliases.insert(chan_1_0.0.short_channel_id_alias.unwrap());
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _chan_1_0_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_1_0_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 10_000_000, 0, InitFeatures::known(), InitFeatures::known());
- let _chan_1_0_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ let _chan_1_0_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_1_0_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let _chan_1_0_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut scid_aliases = HashSet::new();
scid_aliases.insert(chan_1_0_high_inbound_capacity.0.short_channel_id_alias.unwrap());
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Create an unannonced channel between `nodes[2]` and `nodes[0]`, for which the
// `msgs::ChannelUpdate` is never handled for the node(s). As the `msgs::ChannelUpdate`
private_chan_cfg.channel_handshake_config.announced_channel = false;
let temporary_channel_id = nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
let open_channel = get_event_msg!(nodes[2], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_open_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[0].node.handle_open_channel(&nodes[2].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let accept_channel = get_event_msg!(nodes[0], MessageSendEvent::SendAcceptChannel, nodes[2].node.get_our_node_id());
- nodes[2].node.handle_accept_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[2].node.handle_accept_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let tx = sign_funding_transaction(&nodes[2], &nodes[0], 1_000_000, temporary_channel_id);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let _chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let _chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
- let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_1_0 = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_1_0.0);
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_1_0.1);
- let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_2_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 2, 0, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ let chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 2, 0, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// As the invoice amt is 1 msat above chan_1_0's inbound capacity, it shouldn't be included
let mut scid_aliases_99_000_001_msat = HashSet::new();
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan_0_1.1);
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_1.0);
- let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_amt = 20_000;
let (payment_hash, _payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600).unwrap();
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_0_1 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_0_1 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut scid_aliases = HashSet::new();
scid_aliases.insert(chan_0_1.0.short_channel_id_alias.unwrap());
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 1000000, 10001, InitFeatures::known(), InitFeatures::known());
- let chan_1_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 3, 3_000_000, 10005, InitFeatures::known(), InitFeatures::known());
+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 1000000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_1_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 3, 3_000_000, 10005, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut scid_aliases = HashSet::new();
scid_aliases.insert(chan_0_2.0.short_channel_id_alias.unwrap());
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 1000000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 1000000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Create an unannonced channel between `nodes[1]` and `nodes[3]`, for which the
// `msgs::ChannelUpdate` is never handled for the node(s). As the `msgs::ChannelUpdate`
private_chan_cfg.channel_handshake_config.announced_channel = false;
let temporary_channel_id = nodes[1].node.create_channel(nodes[3].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
let open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[3].node.get_our_node_id());
- nodes[3].node.handle_open_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[3].node.handle_open_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let accept_channel = get_event_msg!(nodes[3], MessageSendEvent::SendAcceptChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_accept_channel(&nodes[3].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[1].node.handle_accept_channel(&nodes[3].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let tx = sign_funding_transaction(&nodes[1], &nodes[3], 1_000_000, temporary_channel_id);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_0_1 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_0_1 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
- let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_2_0 = create_announced_chan_between_nodes_with_value(&nodes, 2, 0, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_2_0.1);
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_2_0.0);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_0_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan_0_2.1);
nodes[2].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &chan_0_2.0);
- let _chan_1_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let _chan_1_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
- let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Hints should include `chan_0_3` from as `nodes[3]` only have private channels, and no
// channels for `nodes[2]` as it contains a mix of public and private channels.
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let _chan_0_1_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_0_1_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, InitFeatures::known(), InitFeatures::known());
- let _chan_0_1_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let _chan_0_1_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_0_1_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let _chan_0_1_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut scid_aliases = HashSet::new();
scid_aliases.insert(chan_0_1_high_inbound_capacity.0.short_channel_id_alias.unwrap());
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_1_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 3, 200_000, 0, InitFeatures::known(), InitFeatures::known());
+ let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_1_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 3, 200_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Since the invoice 1 msat above chan_0_3's inbound capacity, it should be filtered out.
let mut scid_aliases_99_000_001_msat = HashSet::new();
fn handle_channel_update(&self, _msg: &ChannelUpdate) -> Result<bool, LightningError> { Ok(false) }
fn get_next_channel_announcement(&self, _starting_point: u64) -> Option<(ChannelAnnouncement, Option<ChannelUpdate>, Option<ChannelUpdate>)> { None }
fn get_next_node_announcement(&self, _starting_point: Option<&PublicKey>) -> Option<NodeAnnouncement> { None }
- fn peer_connected(&self, _their_node_id: &PublicKey, _init_msg: &Init) { }
+ fn peer_connected(&self, _their_node_id: &PublicKey, _init_msg: &Init) -> Result<(), ()> { Ok(()) }
fn handle_reply_channel_range(&self, _their_node_id: &PublicKey, _msg: ReplyChannelRange) -> Result<(), LightningError> { Ok(()) }
fn handle_reply_short_channel_ids_end(&self, _their_node_id: &PublicKey, _msg: ReplyShortChannelIdsEnd) -> Result<(), LightningError> { Ok(()) }
fn handle_query_channel_range(&self, _their_node_id: &PublicKey, _msg: QueryChannelRange) -> Result<(), LightningError> { Ok(()) }
fn handle_query_short_channel_ids(&self, _their_node_id: &PublicKey, _msg: QueryShortChannelIds) -> Result<(), LightningError> { Ok(()) }
- fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::known() }
- fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::known() }
+ fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
+ fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::empty() }
}
impl ChannelMessageHandler for MsgHandler {
fn handle_open_channel(&self, _their_node_id: &PublicKey, _their_features: InitFeatures, _msg: &OpenChannel) {}
self.pubkey_disconnected.clone().try_send(()).unwrap();
}
}
- fn peer_connected(&self, their_node_id: &PublicKey, _msg: &Init) {
+ fn peer_connected(&self, their_node_id: &PublicKey, _init_msg: &Init) -> Result<(), ()> {
if *their_node_id == self.expected_pubkey {
self.pubkey_connected.clone().try_send(()).unwrap();
}
+ Ok(())
}
fn handle_channel_reestablish(&self, _their_node_id: &PublicKey, _msg: &ChannelReestablish) {}
fn handle_error(&self, _their_node_id: &PublicKey, _msg: &ErrorMessage) {}
- fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::known() }
- fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::known() }
+ fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
+ fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::empty() }
}
impl MessageSendEventsProvider for MsgHandler {
fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::hashes::hex::FromHex;
use bitcoin::{Txid, TxMerkleNode};
- use lightning::chain::ChannelMonitorUpdateErr;
+ use lightning::chain::ChannelMonitorUpdateStatus;
use lightning::chain::chainmonitor::Persist;
use lightning::chain::transaction::OutPoint;
use lightning::{check_closed_broadcast, check_closed_event, check_added_monitors};
- use lightning::ln::features::InitFeatures;
+ use lightning::ln::channelmanager;
use lightning::ln::functional_test_utils::*;
use lightning::util::events::{ClosureReason, MessageSendEventsProvider};
use lightning::util::test_utils;
}
// Create some initial channel and check that a channel was persisted.
- let _ = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let _ = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
check_persisted_data!(0);
// Send a few payments and make sure the monitors are updated to the latest.
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[1].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[0].node.get_our_node_id()).unwrap();
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
index: 0
};
match persister.persist_new_channel(test_txo, &added_monitors[0].1, update_id.2) {
- Err(ChannelMonitorUpdateErr::PermanentFailure) => {},
+ ChannelMonitorUpdateStatus::PermanentFailure => {},
_ => panic!("unexpected result from persisting new channel")
}
let mut node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[1].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[0].node.get_our_node_id()).unwrap();
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
index: 0
};
match persister.persist_new_channel(test_txo, &added_monitors[0].1, update_id.2) {
- Err(ChannelMonitorUpdateErr::PermanentFailure) => {},
+ ChannelMonitorUpdateStatus::PermanentFailure => {},
_ => panic!("unexpected result from persisting new channel")
}
"""
[features]
+default = ["std"]
+no-std = ["lightning/no-std"]
+std = ["lightning/std"]
_bench_unstable = []
[dependencies]
-lightning = { version = "0.0.111", path = "../lightning" }
+lightning = { version = "0.0.111", path = "../lightning", default-features = false }
bitcoin = { version = "0.29.0", default-features = false }
[dev-dependencies]
use core::fmt::Debug;
-use std::fmt::Formatter;
+use core::fmt::Formatter;
use lightning::ln::msgs::{DecodeError, LightningError};
/// All-encompassing standard error type that processing can return
LightningError(LightningError),
}
-impl From<std::io::Error> for GraphSyncError {
- fn from(error: std::io::Error) -> Self {
+impl From<lightning::io::Error> for GraphSyncError {
+ fn from(error: lightning::io::Error) -> Self {
Self::DecodeError(DecodeError::Io(error.kind()))
}
}
}
impl Debug for GraphSyncError {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
GraphSyncError::DecodeError(e) => f.write_fmt(format_args!("DecodeError: {:?}", e)),
GraphSyncError::LightningError(e) => f.write_fmt(format_args!("LightningError: {:?}", e))
#![deny(unused_mut)]
#![deny(unused_variables)]
#![deny(unused_imports)]
-//! This crate exposes functionality to rapidly sync gossip data, aimed primarily at mobile
+//! This crate exposes client functionality to rapidly sync gossip data, aimed primarily at mobile
//! devices.
//!
-//! The server sends a compressed response containing differential gossip data. The gossip data is
-//! formatted compactly, omitting signatures and opportunistically incremental where previous
-//! channel updates are known (a mechanism that is enabled when the timestamp of the last known
-//! channel update is communicated). A reference server implementation can be found
-//! [here](https://github.com/lightningdevkit/rapid-gossip-sync-server).
+//! The rapid gossip sync server will provide a compressed response containing differential gossip
+//! data. The gossip data is formatted compactly, omitting signatures and opportunistically
+//! incremental where previous channel updates are known. This mechanism is enabled when the
+//! timestamp of the last known channel update is communicated. A reference server implementation
+//! can be found [on Github](https://github.com/lightningdevkit/rapid-gossip-sync-server).
//!
-//! An example server request could look as simple as the following. Note that the first ever rapid
-//! sync should use `0` for `last_sync_timestamp`:
+//! The primary benefit of this syncing mechanism is that it allows a low-powered client to offload
+//! the validation of gossip signatures to a semi-trusted server. This enables the client to
+//! privately calculate routes for payments, and to do so much faster than requiring a full
+//! peer-to-peer gossip sync to complete.
+//!
+//! The server calculates its response on the basis of a client-provided `latest_seen` timestamp,
+//! i.e., the server will return all rapid gossip sync data it has seen after the given timestamp.
+//!
+//! # Getting Started
+//! Firstly, the data needs to be retrieved from the server. For example, you could use the server
+//! at <https://rapidsync.lightningdevkit.org> with the following request format:
//!
//! ```shell
//! curl -o rapid_sync.lngossip https://rapidsync.lightningdevkit.org/snapshot/<last_sync_timestamp>
//! ```
+//! Note that the first ever rapid sync should use `0` for `last_sync_timestamp`.
//!
-//! Then, call the network processing function. In this example, we process the update by reading
-//! its contents from disk, which we do by calling the `sync_network_graph_with_file_path` method:
+//! After the gossip data snapshot has been downloaded, one of the client's graph processing
+//! functions needs to be called. In this example, we process the update by reading its contents
+//! from disk, which we do by calling [`RapidGossipSync::update_network_graph`]:
//!
//! ```
//! use bitcoin::blockdata::constants::genesis_block;
//! let block_hash = genesis_block(Network::Bitcoin).header.block_hash();
//! let network_graph = NetworkGraph::new(block_hash, &logger);
//! let rapid_sync = RapidGossipSync::new(&network_graph);
-//! let new_last_sync_timestamp_result = rapid_sync.sync_network_graph_with_file_path("./rapid_sync.lngossip");
+//! let snapshot_contents: &[u8] = &[0; 0];
+//! let new_last_sync_timestamp_result = rapid_sync.update_network_graph(snapshot_contents);
//! ```
-//!
-//! The primary benefit this syncing mechanism provides is that given a trusted server, a
-//! low-powered client can offload the validation of gossip signatures. This enables a client to
-//! privately calculate routes for payments, and do so much faster and earlier than requiring a full
-//! peer-to-peer gossip sync to complete.
-//!
-//! The reason the rapid sync server requires trust is that it could provide bogus data, though at
-//! worst, all that would result in is a fake network topology, which wouldn't enable the server to
-//! steal or siphon off funds. It could, however, reduce the client's privacy by forcing all
-//! payments to be routed via channels the server controls.
-//!
-//! The way a server is meant to calculate this rapid gossip sync data is by using a `latest_seen`
-//! timestamp provided by the client. It's not included in either channel announcement or update,
-//! (not least due to announcements not including any timestamps at all, but only a block height)
-//! but rather, it's a timestamp of when the server saw a particular message.
+
+#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
// Allow and import test features for benching
#![cfg_attr(all(test, feature = "_bench_unstable"), feature(test))]
#[cfg(all(test, feature = "_bench_unstable"))]
extern crate test;
+#[cfg(not(feature = "std"))]
+extern crate alloc;
+
+#[cfg(feature = "std")]
use std::fs::File;
-use std::ops::Deref;
-use std::sync::atomic::{AtomicBool, Ordering};
+use core::ops::Deref;
+use core::sync::atomic::{AtomicBool, Ordering};
+use lightning::io;
use lightning::routing::gossip::NetworkGraph;
use lightning::util::logger::Logger;
-use crate::error::GraphSyncError;
+pub use crate::error::GraphSyncError;
/// Error types that these functions can return
-pub mod error;
+mod error;
/// Core functionality of this crate
-pub mod processing;
+mod processing;
-/// Rapid Gossip Sync struct
+/// The main Rapid Gossip Sync object.
+///
/// See [crate-level documentation] for usage.
///
/// [crate-level documentation]: crate
}
impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
- /// Instantiate a new [`RapidGossipSync`] instance
+ /// Instantiate a new [`RapidGossipSync`] instance.
pub fn new(network_graph: NG) -> Self {
Self {
network_graph,
}
}
- /// Sync gossip data from a file
+ /// Sync gossip data from a file.
/// Returns the last sync timestamp to be used the next time rapid sync data is queried.
///
/// `network_graph`: The network graph to apply the updates to
///
/// `sync_path`: Path to the file where the gossip update data is located
///
+ #[cfg(feature = "std")]
pub fn sync_network_graph_with_file_path(
&self,
sync_path: &str,
self.update_network_graph_from_byte_stream(&mut file)
}
+ /// Update network graph from binary data.
+ /// Returns the last sync timestamp to be used the next time rapid sync data is queried.
+ ///
+ /// `network_graph`: network graph to be updated
+ ///
+ /// `update_data`: `&[u8]` binary stream that comprises the update data
+ pub fn update_network_graph(&self, update_data: &[u8]) -> Result<u32, GraphSyncError> {
+ let mut read_cursor = io::Cursor::new(update_data);
+ self.update_network_graph_from_byte_stream(&mut read_cursor)
+ }
+
/// Gets a reference to the underlying [`NetworkGraph`] which was provided in
/// [`RapidGossipSync::new`].
///
&self.network_graph
}
- /// Returns whether a rapid gossip sync has completed at least once
+ /// Returns whether a rapid gossip sync has completed at least once.
pub fn is_initial_sync_complete(&self) -> bool {
self.is_initial_sync_complete.load(Ordering::Acquire)
}
}
+#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use std::fs;
-use std::cmp::max;
-use std::io;
-use std::io::Read;
-use std::ops::Deref;
-use std::sync::atomic::Ordering;
+use core::cmp::max;
+use core::ops::Deref;
+use core::sync::atomic::Ordering;
use bitcoin::BlockHash;
use bitcoin::secp256k1::PublicKey;
use lightning::routing::gossip::NetworkGraph;
use lightning::util::logger::Logger;
use lightning::util::ser::{BigSize, Readable};
+use lightning::io;
use crate::error::GraphSyncError;
use crate::RapidGossipSync;
+#[cfg(not(feature = "std"))]
+use alloc::{vec::Vec, borrow::ToOwned};
+
/// The purpose of this prefix is to identify the serialization format, should other rapid gossip
/// sync formats arise in the future.
///
const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY: u32 = 50_000;
impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
- /// Update network graph from binary data.
- /// Returns the last sync timestamp to be used the next time rapid sync data is queried.
- ///
- /// `network_graph`: network graph to be updated
- ///
- /// `update_data`: `&[u8]` binary stream that comprises the update data
- pub fn update_network_graph(&self, update_data: &[u8]) -> Result<u32, GraphSyncError> {
- let mut read_cursor = io::Cursor::new(update_data);
- self.update_network_graph_from_byte_stream(&mut read_cursor)
- }
-
-
- pub(crate) fn update_network_graph_from_byte_stream<R: Read>(
+ pub(crate) fn update_network_graph_from_byte_stream<R: io::Read>(
&self,
mut read_cursor: &mut R,
) -> Result<u32, GraphSyncError> {
let backdated_timestamp = latest_seen_timestamp.saturating_sub(24 * 3600 * 7);
let node_id_count: u32 = Readable::read(read_cursor)?;
- let mut node_ids: Vec<PublicKey> = Vec::with_capacity(std::cmp::min(
+ let mut node_ids: Vec<PublicKey> = Vec::with_capacity(core::cmp::min(
node_id_count,
MAX_INITIAL_NODE_ID_VECTOR_CAPACITY,
) as usize);
htlc_maximum_msat: default_htlc_maximum_msat,
fee_base_msat: default_fee_base_msat,
fee_proportional_millionths: default_fee_proportional_millionths,
- excess_data: vec![],
+ excess_data: Vec::new(),
}
} else {
// incremental update, field flags will indicate mutated values
htlc_maximum_msat: directional_info.htlc_maximum_msat,
fee_base_msat: directional_info.fees.base_msat,
fee_proportional_millionths: directional_info.fees.proportional_millionths,
- excess_data: vec![],
+ excess_data: Vec::new(),
}
};
[dependencies]
bitcoin = { version = "0.29.0", default-features = false, features = ["secp-recovery"] }
-hashbrown = { version = "0.11", optional = true }
+hashbrown = { version = "0.8", optional = true }
hex = { version = "0.4", optional = true }
regex = { version = "1.5.6", optional = true }
backtrace = { version = "0.3", optional = true }
use bitcoin::hash_types::Txid;
use chain;
-use chain::{ChannelMonitorUpdateErr, Filter, WatchedOutput};
+use chain::{ChannelMonitorUpdateStatus, Filter, WatchedOutput};
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, Balance, MonitorEvent, TransactionOutputs, LATENCY_GRACE_PERIOD_BLOCKS};
use chain::transaction::{OutPoint, TransactionData};
///
/// Each method can return three possible values:
/// * If persistence (including any relevant `fsync()` calls) happens immediately, the
-/// implementation should return `Ok(())`, indicating normal channel operation should continue.
+/// implementation should return [`ChannelMonitorUpdateStatus::Completed`], indicating normal
+/// channel operation should continue.
/// * If persistence happens asynchronously, implementations should first ensure the
/// [`ChannelMonitor`] or [`ChannelMonitorUpdate`] are written durably to disk, and then return
-/// `Err(ChannelMonitorUpdateErr::TemporaryFailure)` while the update continues in the
-/// background. Once the update completes, [`ChainMonitor::channel_monitor_updated`] should be
-/// called with the corresponding [`MonitorUpdateId`].
+/// [`ChannelMonitorUpdateStatus::InProgress`] while the update continues in the background.
+/// Once the update completes, [`ChainMonitor::channel_monitor_updated`] should be called with
+/// the corresponding [`MonitorUpdateId`].
///
/// Note that unlike the direct [`chain::Watch`] interface,
/// [`ChainMonitor::channel_monitor_updated`] must be called once for *each* update which occurs.
///
/// * If persistence fails for some reason, implementations should return
-/// `Err(ChannelMonitorUpdateErr::PermanentFailure)`, in which case the channel will likely be
+/// [`ChannelMonitorUpdateStatus::PermanentFailure`], in which case the channel will likely be
/// closed without broadcasting the latest state. See
-/// [`ChannelMonitorUpdateErr::PermanentFailure`] for more details.
+/// [`ChannelMonitorUpdateStatus::PermanentFailure`] for more details.
pub trait Persist<ChannelSigner: Sign> {
/// Persist a new channel's data in response to a [`chain::Watch::watch_channel`] call. This is
/// called by [`ChannelManager`] for new channels, or may be called directly, e.g. on startup.
/// and the stored channel data). Note that you **must** persist every new monitor to disk.
///
/// The `update_id` is used to identify this call to [`ChainMonitor::channel_monitor_updated`],
- /// if you return [`ChannelMonitorUpdateErr::TemporaryFailure`].
+ /// if you return [`ChannelMonitorUpdateStatus::InProgress`].
///
/// See [`Writeable::write`] on [`ChannelMonitor`] for writing out a `ChannelMonitor`
- /// and [`ChannelMonitorUpdateErr`] for requirements when returning errors.
+ /// and [`ChannelMonitorUpdateStatus`] for requirements when returning errors.
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`Writeable::write`]: crate::util::ser::Writeable::write
- fn persist_new_channel(&self, channel_id: OutPoint, data: &ChannelMonitor<ChannelSigner>, update_id: MonitorUpdateId) -> Result<(), ChannelMonitorUpdateErr>;
+ fn persist_new_channel(&self, channel_id: OutPoint, data: &ChannelMonitor<ChannelSigner>, update_id: MonitorUpdateId) -> ChannelMonitorUpdateStatus;
/// Update one channel's data. The provided [`ChannelMonitor`] has already applied the given
/// update.
/// whereas updates are small and `O(1)`.
///
/// The `update_id` is used to identify this call to [`ChainMonitor::channel_monitor_updated`],
- /// if you return [`ChannelMonitorUpdateErr::TemporaryFailure`].
+ /// if you return [`ChannelMonitorUpdateStatus::InProgress`].
///
/// See [`Writeable::write`] on [`ChannelMonitor`] for writing out a `ChannelMonitor`,
/// [`Writeable::write`] on [`ChannelMonitorUpdate`] for writing out an update, and
- /// [`ChannelMonitorUpdateErr`] for requirements when returning errors.
+ /// [`ChannelMonitorUpdateStatus`] for requirements when returning errors.
///
/// [`Writeable::write`]: crate::util::ser::Writeable::write
- fn update_persisted_channel(&self, channel_id: OutPoint, update: &Option<ChannelMonitorUpdate>, data: &ChannelMonitor<ChannelSigner>, update_id: MonitorUpdateId) -> Result<(), ChannelMonitorUpdateErr>;
+ fn update_persisted_channel(&self, channel_id: OutPoint, update: &Option<ChannelMonitorUpdate>, data: &ChannelMonitor<ChannelSigner>, update_id: MonitorUpdateId) -> ChannelMonitorUpdateStatus;
}
struct MonitorHolder<ChannelSigner: Sign> {
/// The full set of pending monitor updates for this Channel.
///
/// Note that this lock must be held during updates to prevent a race where we call
- /// update_persisted_channel, the user returns a TemporaryFailure, and then calls
- /// channel_monitor_updated immediately, racing our insertion of the pending update into the
- /// contained Vec.
+ /// update_persisted_channel, the user returns a
+ /// [`ChannelMonitorUpdateStatus::InProgress`], and then calls channel_monitor_updated
+ /// immediately, racing our insertion of the pending update into the contained Vec.
///
/// Beyond the synchronization of updates themselves, we cannot handle user events until after
/// any chain updates have been stored on disk. Thus, we scan this list when returning updates
if !monitor_state.has_pending_chainsync_updates(&pending_monitor_updates) {
// If there are not ChainSync persists awaiting completion, go ahead and
// set last_chain_persist_height here - we wouldn't want the first
- // TemporaryFailure to always immediately be considered "overly delayed".
+ // InProgress to always immediately be considered "overly delayed".
monitor_state.last_chain_persist_height.store(height as usize, Ordering::Release);
}
}
log_trace!(self.logger, "Syncing Channel Monitor for channel {}", log_funding_info!(monitor));
match self.persister.update_persisted_channel(*funding_outpoint, &None, monitor, update_id) {
- Ok(()) =>
+ ChannelMonitorUpdateStatus::Completed =>
log_trace!(self.logger, "Finished syncing Channel Monitor for channel {}", log_funding_info!(monitor)),
- Err(ChannelMonitorUpdateErr::PermanentFailure) => {
+ ChannelMonitorUpdateStatus::PermanentFailure => {
monitor_state.channel_perm_failed.store(true, Ordering::Release);
self.pending_monitor_events.lock().unwrap().push((*funding_outpoint, vec![MonitorEvent::UpdateFailed(*funding_outpoint)], monitor.get_counterparty_node_id()));
},
- Err(ChannelMonitorUpdateErr::TemporaryFailure) => {
+ ChannelMonitorUpdateStatus::InProgress => {
log_debug!(self.logger, "Channel Monitor sync for channel {} in progress, holding events until completion!", log_funding_info!(monitor));
pending_monitor_updates.push(update_id);
},
}
/// Indicates the persistence of a [`ChannelMonitor`] has completed after
- /// [`ChannelMonitorUpdateErr::TemporaryFailure`] was returned from an update operation.
+ /// [`ChannelMonitorUpdateStatus::InProgress`] was returned from an update operation.
///
/// Thus, the anticipated use is, at a high level:
/// 1) This [`ChainMonitor`] calls [`Persist::update_persisted_channel`] which stores the
/// update to disk and begins updating any remote (e.g. watchtower/backup) copies,
- /// returning [`ChannelMonitorUpdateErr::TemporaryFailure`],
+ /// returning [`ChannelMonitorUpdateStatus::InProgress`],
/// 2) once all remote copies are updated, you call this function with the
/// `completed_update_id` that completed, and once all pending updates have completed the
/// channel will be re-enabled.
if monitor_is_pending_updates || monitor_data.channel_perm_failed.load(Ordering::Acquire) {
// If there are still monitor updates pending (or an old monitor update
// finished after a later one perm-failed), we cannot yet construct an
- // UpdateCompleted event.
+ // Completed event.
return Ok(());
}
- self.pending_monitor_events.lock().unwrap().push((funding_txo, vec![MonitorEvent::UpdateCompleted {
+ self.pending_monitor_events.lock().unwrap().push((funding_txo, vec![MonitorEvent::Completed {
funding_txo,
monitor_update_id: monitor_data.monitor.get_latest_update_id(),
}], monitor_data.monitor.get_counterparty_node_id()));
pub fn force_channel_monitor_updated(&self, funding_txo: OutPoint, monitor_update_id: u64) {
let monitors = self.monitors.read().unwrap();
let counterparty_node_id = monitors.get(&funding_txo).and_then(|m| m.monitor.get_counterparty_node_id());
- self.pending_monitor_events.lock().unwrap().push((funding_txo, vec![MonitorEvent::UpdateCompleted {
+ self.pending_monitor_events.lock().unwrap().push((funding_txo, vec![MonitorEvent::Completed {
funding_txo,
monitor_update_id,
}], counterparty_node_id));
///
/// Note that we persist the given `ChannelMonitor` while holding the `ChainMonitor`
/// monitors lock.
- fn watch_channel(&self, funding_outpoint: OutPoint, monitor: ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr> {
+ fn watch_channel(&self, funding_outpoint: OutPoint, monitor: ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus {
let mut monitors = self.monitors.write().unwrap();
let entry = match monitors.entry(funding_outpoint) {
hash_map::Entry::Occupied(_) => {
log_error!(self.logger, "Failed to add new channel data: channel monitor for given outpoint is already present");
- return Err(ChannelMonitorUpdateErr::PermanentFailure)},
+ return ChannelMonitorUpdateStatus::PermanentFailure
+ },
hash_map::Entry::Vacant(e) => e,
};
log_trace!(self.logger, "Got new ChannelMonitor for channel {}", log_funding_info!(monitor));
let update_id = MonitorUpdateId::from_new_monitor(&monitor);
let mut pending_monitor_updates = Vec::new();
let persist_res = self.persister.persist_new_channel(funding_outpoint, &monitor, update_id);
- if persist_res.is_err() {
- log_error!(self.logger, "Failed to persist new ChannelMonitor for channel {}: {:?}", log_funding_info!(monitor), persist_res);
- } else {
- log_trace!(self.logger, "Finished persisting new ChannelMonitor for channel {}", log_funding_info!(monitor));
- }
- if persist_res == Err(ChannelMonitorUpdateErr::PermanentFailure) {
- return persist_res;
- } else if persist_res.is_err() {
- pending_monitor_updates.push(update_id);
+ match persist_res {
+ ChannelMonitorUpdateStatus::InProgress => {
+ log_info!(self.logger, "Persistence of new ChannelMonitor for channel {} in progress", log_funding_info!(monitor));
+ pending_monitor_updates.push(update_id);
+ },
+ ChannelMonitorUpdateStatus::PermanentFailure => {
+ log_error!(self.logger, "Persistence of new ChannelMonitor for channel {} failed", log_funding_info!(monitor));
+ return persist_res;
+ },
+ ChannelMonitorUpdateStatus::Completed => {
+ log_info!(self.logger, "Persistence of new ChannelMonitor for channel {} completed", log_funding_info!(monitor));
+ }
}
if let Some(ref chain_source) = self.chain_source {
monitor.load_outputs_to_watch(chain_source);
/// Note that we persist the given `ChannelMonitor` update while holding the
/// `ChainMonitor` monitors lock.
- fn update_channel(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr> {
+ fn update_channel(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> ChannelMonitorUpdateStatus {
// Update the monitor that watches the channel referred to by the given outpoint.
let monitors = self.monitors.read().unwrap();
match monitors.get(&funding_txo) {
#[cfg(any(test, fuzzing))]
panic!("ChannelManager generated a channel update for a channel that was not yet registered!");
#[cfg(not(any(test, fuzzing)))]
- Err(ChannelMonitorUpdateErr::PermanentFailure)
+ ChannelMonitorUpdateStatus::PermanentFailure
},
Some(monitor_state) => {
let monitor = &monitor_state.monitor;
let update_id = MonitorUpdateId::from_monitor_update(&update);
let mut pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
let persist_res = self.persister.update_persisted_channel(funding_txo, &Some(update), monitor, update_id);
- if let Err(e) = persist_res {
- if e == ChannelMonitorUpdateErr::TemporaryFailure {
+ match persist_res {
+ ChannelMonitorUpdateStatus::InProgress => {
pending_monitor_updates.push(update_id);
- } else {
+ log_debug!(self.logger, "Persistence of ChannelMonitorUpdate for channel {} in progress", log_funding_info!(monitor));
+ },
+ ChannelMonitorUpdateStatus::PermanentFailure => {
monitor_state.channel_perm_failed.store(true, Ordering::Release);
- }
- log_error!(self.logger, "Failed to persist ChannelMonitor update for channel {}: {:?}", log_funding_info!(monitor), e);
- } else {
- log_trace!(self.logger, "Finished persisting ChannelMonitor update for channel {}", log_funding_info!(monitor));
+ log_error!(self.logger, "Persistence of ChannelMonitorUpdate for channel {} failed", log_funding_info!(monitor));
+ },
+ ChannelMonitorUpdateStatus::Completed => {
+ log_debug!(self.logger, "Persistence of ChannelMonitorUpdate for channel {} completed", log_funding_info!(monitor));
+ },
}
if update_res.is_err() {
- Err(ChannelMonitorUpdateErr::PermanentFailure)
+ ChannelMonitorUpdateStatus::PermanentFailure
} else if monitor_state.channel_perm_failed.load(Ordering::Acquire) {
- Err(ChannelMonitorUpdateErr::PermanentFailure)
+ ChannelMonitorUpdateStatus::PermanentFailure
} else {
persist_res
}
L::Target: Logger,
P::Target: Persist<ChannelSigner>,
{
+ #[cfg(not(anchors))]
/// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity.
///
/// An [`EventHandler`] may safely call back to the provider, though this shouldn't be needed in
handler.handle_event(&event);
}
}
+ #[cfg(anchors)]
+ /// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity.
+ ///
+ /// For channels featuring anchor outputs, this method will also process [`BumpTransaction`]
+ /// events produced from each [`ChannelMonitor`] while there is a balance to claim onchain
+ /// within each channel. As the confirmation of a commitment transaction may be critical to the
+ /// safety of funds, this method must be invoked frequently, ideally once for every chain tip
+ /// update (block connected or disconnected).
+ ///
+ /// An [`EventHandler`] may safely call back to the provider, though this shouldn't be needed in
+ /// order to handle these events.
+ ///
+ /// [`SpendableOutputs`]: events::Event::SpendableOutputs
+ /// [`BumpTransaction`]: events::Event::BumpTransaction
+ fn process_pending_events<H: Deref>(&self, handler: H) where H::Target: EventHandler {
+ let mut pending_events = Vec::new();
+ for monitor_state in self.monitors.read().unwrap().values() {
+ pending_events.append(&mut monitor_state.monitor.get_and_clear_pending_events());
+ }
+ for event in pending_events.drain(..) {
+ handler.handle_event(&event);
+ }
+ }
}
#[cfg(test)]
use ::{check_added_monitors, check_closed_broadcast, check_closed_event};
use ::{expect_payment_sent, expect_payment_claimed, expect_payment_sent_without_paths, expect_payment_path_successful, get_event_msg};
use ::{get_htlc_update_msgs, get_local_commitment_txn, get_revoke_commit_msgs, get_route_and_payment_hash, unwrap_send_err};
- use chain::{ChannelMonitorUpdateErr, Confirm, Watch};
+ use chain::{ChannelMonitorUpdateStatus, Confirm, Watch};
use chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS;
- use ln::channelmanager::PaymentSendFailure;
- use ln::features::InitFeatures;
+ use ln::channelmanager::{self, PaymentSendFailure};
use ln::functional_test_utils::*;
use ln::msgs::ChannelMessageHandler;
use util::errors::APIError;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Route two payments to be claimed at the same time.
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
let (payment_preimage_2, payment_hash_2, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
chanmon_cfgs[1].persister.offchain_monitor_updates.lock().unwrap().clear();
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.claim_funds(payment_preimage_1);
check_added_monitors!(nodes[1], 1);
check_added_monitors!(nodes[1], 1);
expect_payment_claimed!(nodes[1], payment_hash_2, 1_000_000);
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let persistences = chanmon_cfgs[1].persister.offchain_monitor_updates.lock().unwrap().clone();
assert_eq!(persistences.len(), 1);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let channel = create_announced_chan_between_nodes(
- &nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ &nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get a route for later and rebalance the channel somewhat
send_payment(&nodes[0], &[&nodes[1]], 10_000_000);
// Temp-fail the block connection which will hold the channel-closed event
chanmon_cfgs[0].persister.chain_sync_monitor_persistences.lock().unwrap().clear();
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
// Connect B's commitment transaction, but only to the ChainMonitor/ChannelMonitor. The
// channel is now closed, but the ChannelManager doesn't know that yet.
// If the ChannelManager tries to update the channel, however, the ChainMonitor will pass
// the update through to the ChannelMonitor which will refuse it (as the channel is closed).
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
unwrap_send_err!(nodes[0].node.send_payment(&route, second_payment_hash, &Some(second_payment_secret)),
true, APIError::ChannelUnavailable { ref err },
assert!(err.contains("ChannelMonitor storage failure")));
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
chanmon_cfgs[0].persister.chain_sync_monitor_persistences.lock().unwrap().clear();
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::PermanentFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::PermanentFailure);
connect_blocks(&nodes[0], 1);
// Before processing events, the ChannelManager will still think the Channel is open and
//! ChannelMonitors to get out of the HSM and onto monitoring devices.
use bitcoin::blockdata::block::BlockHeader;
-use bitcoin::blockdata::transaction::{TxOut,Transaction};
-use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
+use bitcoin::blockdata::transaction::{OutPoint as BitcoinOutPoint, TxOut, Transaction};
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::opcodes;
use ln::{PaymentHash, PaymentPreimage};
use ln::msgs::DecodeError;
use ln::chan_utils;
-use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCType, ChannelTransactionParameters, HolderCommitmentTransaction};
+use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction};
use ln::channelmanager::HTLCSource;
use chain;
use chain::{BestBlock, WatchedOutput};
use chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
use chain::transaction::{OutPoint, TransactionData};
use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface};
+#[cfg(anchors)]
+use chain::onchaintx::ClaimEvent;
use chain::onchaintx::OnchainTxHandler;
use chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput};
use chain::Filter;
use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48, OptionDeserWrapper};
use util::byte_utils;
use util::events::Event;
+#[cfg(anchors)]
+use util::events::{AnchorDescriptor, BumpTransactionEvent};
use prelude::*;
use core::{cmp, mem};
/// much smaller than a full [`ChannelMonitor`]. However, for large single commitment transaction
/// updates (e.g. ones during which there are hundreds of HTLCs pending on the commitment
/// transaction), a single update may reach upwards of 1 MiB in serialized size.
-#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq))]
+#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq, Eq))]
#[derive(Clone)]
#[must_use]
pub struct ChannelMonitorUpdate {
/// increasing and increase by one for each new update, with one exception specified below.
///
/// This sequence number is also used to track up to which points updates which returned
- /// ChannelMonitorUpdateErr::TemporaryFailure have been applied to all copies of a given
+ /// [`ChannelMonitorUpdateStatus::InProgress`] have been applied to all copies of a given
/// ChannelMonitor when ChannelManager::channel_monitor_updated is called.
///
/// The only instance where update_id values are not strictly increasing is the case where we
/// allow post-force-close updates with a special update ID of [`CLOSED_CHANNEL_UPDATE_ID`]. See
/// its docs for more details.
+ ///
+ /// [`ChannelMonitorUpdateStatus::InProgress`]: super::ChannelMonitorUpdateStatus::InProgress
pub update_id: u64,
}
}
/// An event to be processed by the ChannelManager.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub enum MonitorEvent {
/// A monitor event containing an HTLCUpdate.
HTLCEvent(HTLCUpdate),
CommitmentTxConfirmed(OutPoint),
/// Indicates a [`ChannelMonitor`] update has completed. See
- /// [`ChannelMonitorUpdateErr::TemporaryFailure`] for more information on how this is used.
+ /// [`ChannelMonitorUpdateStatus::InProgress`] for more information on how this is used.
///
- /// [`ChannelMonitorUpdateErr::TemporaryFailure`]: super::ChannelMonitorUpdateErr::TemporaryFailure
- UpdateCompleted {
+ /// [`ChannelMonitorUpdateStatus::InProgress`]: super::ChannelMonitorUpdateStatus::InProgress
+ Completed {
/// The funding outpoint of the [`ChannelMonitor`] that was updated
funding_txo: OutPoint,
/// The Update ID from [`ChannelMonitorUpdate::update_id`] which was applied or
},
/// Indicates a [`ChannelMonitor`] update has failed. See
- /// [`ChannelMonitorUpdateErr::PermanentFailure`] for more information on how this is used.
+ /// [`ChannelMonitorUpdateStatus::PermanentFailure`] for more information on how this is used.
///
- /// [`ChannelMonitorUpdateErr::PermanentFailure`]: super::ChannelMonitorUpdateErr::PermanentFailure
+ /// [`ChannelMonitorUpdateStatus::PermanentFailure`]: super::ChannelMonitorUpdateStatus::PermanentFailure
UpdateFailed(OutPoint),
}
impl_writeable_tlv_based_enum_upgradable!(MonitorEvent,
- // Note that UpdateCompleted and UpdateFailed are currently never serialized to disk as they are
+ // Note that Completed and UpdateFailed are currently never serialized to disk as they are
// generated only in ChainMonitor
- (0, UpdateCompleted) => {
+ (0, Completed) => {
(0, funding_txo, required),
(2, monitor_update_id, required),
},
/// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on
/// chain. Used to update the corresponding HTLC in the backward channel. Failing to pass the
/// preimage claim backward will lead to loss of funds.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub struct HTLCUpdate {
pub(crate) payment_hash: PaymentHash,
pub(crate) payment_preimage: Option<PaymentPreimage>,
pub(crate) const HTLC_FAIL_BACK_BUFFER: u32 = CLTV_CLAIM_BUFFER + LATENCY_GRACE_PERIOD_BLOCKS;
// TODO(devrandom) replace this with HolderCommitmentTransaction
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
struct HolderSignedTx {
/// txid of the transaction in tx, just used to make comparison faster
txid: Txid,
(14, htlc_outputs, vec_type)
});
+#[cfg(anchors)]
+impl HolderSignedTx {
+ fn non_dust_htlcs(&self) -> Vec<HTLCOutputInCommitment> {
+ self.htlc_outputs.iter().filter_map(|(htlc, _, _)| {
+ if let Some(_) = htlc.transaction_output_index {
+ Some(htlc.clone())
+ } else {
+ None
+ }
+ })
+ .collect()
+ }
+}
+
/// We use this to track static counterparty commitment transaction data and to generate any
/// justice or 2nd-stage preimage/timeout transactions.
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
struct CounterpartyCommitmentParameters {
counterparty_delayed_payment_base_key: PublicKey,
counterparty_htlc_base_key: PublicKey,
/// transaction causing it.
///
/// Used to determine when the on-chain event can be considered safe from a chain reorganization.
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
struct OnchainEventEntry {
txid: Txid,
height: u32,
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
enum OnchainEvent {
/// An outbound HTLC failing after a transaction is confirmed. Used
/// * when an outbound HTLC output is spent by us after the HTLC timed out
);
-#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq))]
+#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq, Eq))]
#[derive(Clone)]
pub(crate) enum ChannelMonitorUpdateStep {
LatestHolderCommitmentTXInfo {
}
/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY.
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
struct IrrevocablyResolvedHTLC {
commitment_tx_output_idx: Option<u32>,
/// The txid of the transaction which resolved the HTLC, this may be a commitment (if the HTLC
// of block connection between ChannelMonitors and the ChannelManager.
funding_spend_seen: bool,
+ /// Set to `Some` of the confirmed transaction spending the funding input of the channel after
+ /// reaching `ANTI_REORG_DELAY` confirmations.
funding_spend_confirmed: Option<Txid>,
+
confirmed_commitment_tx_counterparty_output: CommitmentTxCounterpartyOutputInfo,
/// The set of HTLCs which have been either claimed or failed on chain and have reached
/// the requisite confirmations on the claim/fail transaction (either ANTI_REORG_DELAY or the
B::Target: BroadcasterInterface,
L::Target: Logger,
{
- self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger)
+ self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger);
}
/// Updates a ChannelMonitor on the basis of some new information provided by the Channel
}
/// Used by ChannelManager deserialization to broadcast the latest holder state if its copy of
- /// the Channel was out-of-date. You may use it to get a broadcastable holder toxic tx in case of
- /// fallen-behind, i.e when receiving a channel_reestablish with a proof that our counterparty side knows
- /// a higher revocation secret than the holder commitment number we are aware of. Broadcasting these
- /// transactions are UNSAFE, as they allow counterparty side to punish you. Nevertheless you may want to
- /// broadcast them if counterparty don't close channel with his higher commitment transaction after a
- /// substantial amount of time (a month or even a year) to get back funds. Best may be to contact
- /// out-of-band the other node operator to coordinate with him if option is available to you.
- /// In any-case, choice is up to the user.
+ /// the Channel was out-of-date.
+ ///
+ /// You may also use this to broadcast the latest local commitment transaction, either because
+ /// a monitor update failed with [`ChannelMonitorUpdateStatus::PermanentFailure`] or because we've
+ /// fallen behind (i.e. we've received proof that our counterparty side knows a revocation
+ /// secret we gave them that they shouldn't know).
+ ///
+ /// Broadcasting these transactions in the second case is UNSAFE, as they allow counterparty
+ /// side to punish you. Nevertheless you may want to broadcast them if counterparty doesn't
+ /// close channel with their commitment transaction after a substantial amount of time. Best
+ /// may be to contact the other node operator out-of-band to coordinate other options available
+ /// to you. In any-case, the choice is up to you.
+ ///
+ /// [`ChannelMonitorUpdateStatus::PermanentFailure`]: super::ChannelMonitorUpdateStatus::PermanentFailure
pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
where L::Target: Logger {
self.inner.lock().unwrap().get_latest_holder_commitment_txn(logger)
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
}
let mut ret = Ok(());
+ let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&*fee_estimator);
for update in updates.updates.iter() {
match update {
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs } => {
},
ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } => {
log_trace!(logger, "Updating ChannelMonitor with payment preimage");
- let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&*fee_estimator);
self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage, broadcaster, &bounded_fee_estimator, logger)
},
ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => {
self.lockdown_from_offchain = true;
if *should_broadcast {
self.broadcast_latest_holder_commitment_txn(broadcaster, logger);
+ // If the channel supports anchor outputs, we'll need to emit an external
+ // event to be consumed such that a child transaction is broadcast with a
+ // high enough feerate for the parent commitment transaction to confirm.
+ if self.onchain_tx_handler.opt_anchors() {
+ let funding_output = HolderFundingOutput::build(
+ self.funding_redeemscript.clone(), self.channel_value_satoshis,
+ self.onchain_tx_handler.opt_anchors(),
+ );
+ let best_block_height = self.best_block.height();
+ let commitment_package = PackageTemplate::build_package(
+ self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
+ PackageSolvingData::HolderFundingOutput(funding_output),
+ best_block_height, false, best_block_height,
+ );
+ self.onchain_tx_handler.update_claims_view(
+ &[], vec![commitment_package], best_block_height, best_block_height,
+ broadcaster, &bounded_fee_estimator, logger,
+ );
+ }
} else if !self.holder_tx_signed {
- log_error!(logger, "You have a toxic holder commitment transaction avaible in channel monitor, read comment in ChannelMonitor::get_latest_holder_commitment_txn to be informed of manual action to take");
+ log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast");
+ log_error!(logger, " in channel monitor for channel {}!", log_bytes!(self.funding_info.0.to_channel_id()));
+ log_error!(logger, " Read the docs for ChannelMonitor::get_latest_holder_commitment_txn and take manual action!");
} else {
// If we generated a MonitorEvent::CommitmentTxConfirmed, the ChannelManager
// will still give us a ChannelForceClosed event with !should_broadcast, but we
pub fn get_and_clear_pending_events(&mut self) -> Vec<Event> {
let mut ret = Vec::new();
mem::swap(&mut ret, &mut self.pending_events);
+ #[cfg(anchors)]
+ for claim_event in self.onchain_tx_handler.get_and_clear_pending_claim_events().drain(..) {
+ match claim_event {
+ ClaimEvent::BumpCommitment {
+ package_target_feerate_sat_per_1000_weight, commitment_tx, anchor_output_idx,
+ } => {
+ let commitment_txid = commitment_tx.txid();
+ debug_assert_eq!(self.current_holder_commitment_tx.txid, commitment_txid);
+ let pending_htlcs = self.current_holder_commitment_tx.non_dust_htlcs();
+ let commitment_tx_fee_satoshis = self.channel_value_satoshis -
+ commitment_tx.output.iter().fold(0u64, |sum, output| sum + output.value);
+ ret.push(Event::BumpTransaction(BumpTransactionEvent::ChannelClose {
+ package_target_feerate_sat_per_1000_weight,
+ commitment_tx,
+ commitment_tx_fee_satoshis,
+ anchor_descriptor: AnchorDescriptor {
+ channel_keys_id: self.channel_keys_id,
+ channel_value_satoshis: self.channel_value_satoshis,
+ outpoint: BitcoinOutPoint {
+ txid: commitment_txid,
+ vout: anchor_output_idx,
+ },
+ },
+ pending_htlcs,
+ }));
+ },
+ }
+ }
ret
}
CounterpartyOfferedHTLCOutput::build(*per_commitment_point,
self.counterparty_commitment_params.counterparty_delayed_payment_base_key,
self.counterparty_commitment_params.counterparty_htlc_base_key,
- preimage.unwrap(), htlc.clone()))
+ preimage.unwrap(), htlc.clone(), self.onchain_tx_handler.opt_anchors()))
} else {
PackageSolvingData::CounterpartyReceivedHTLCOutput(
CounterpartyReceivedHTLCOutput::build(*per_commitment_point,
self.counterparty_commitment_params.counterparty_delayed_payment_base_key,
self.counterparty_commitment_params.counterparty_htlc_base_key,
- htlc.clone()))
+ htlc.clone(), self.onchain_tx_handler.opt_anchors()))
};
let aggregation = if !htlc.offered { false } else { true };
let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0);
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
let txid = commitment_tx.txid();
let mut holder_transactions = vec![commitment_tx];
+ // When anchor outputs are present, the HTLC transactions are only valid once the commitment
+ // transaction confirms.
+ if self.onchain_tx_handler.opt_anchors() {
+ return holder_transactions;
+ }
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
if let Some(vout) = htlc.0.transaction_output_index {
let preimage = if !htlc.0.offered {
let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript);
let txid = commitment_tx.txid();
let mut holder_transactions = vec![commitment_tx];
+ // When anchor outputs are present, the HTLC transactions are only final once the commitment
+ // transaction confirms due to the CSV 1 encumberance.
+ if self.onchain_tx_handler.opt_anchors() {
+ return holder_transactions;
+ }
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
if let Some(vout) = htlc.0.transaction_output_index {
let preimage = if !htlc.0.offered {
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
txid,
transaction: Some((*tx).clone()),
- height: height,
+ height,
event: OnchainEvent::FundingSpendConfirmation {
on_local_output_csv: balance_spendable_csv,
commitment_tx_to_counterparty_output,
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
if should_broadcast {
- let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone());
+ let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.opt_anchors());
let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), false, self.best_block.height());
claimable_outpoints.push(commitment_package);
self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
self.holder_tx_signed = true;
- // Because we're broadcasting a commitment transaction, we should construct the package
- // assuming it gets confirmed in the next block. Sadly, we have code which considers
- // "not yet confirmed" things as discardable, so we cannot do that here.
- let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
- let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
- if !new_outputs.is_empty() {
- watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
+ // We can't broadcast our HTLC transactions while the commitment transaction is
+ // unconfirmed. We'll delay doing so until we detect the confirmed commitment in
+ // `transactions_confirmed`.
+ if !self.onchain_tx_handler.opt_anchors() {
+ // Because we're broadcasting a commitment transaction, we should construct the package
+ // assuming it gets confirmed in the next block. Sadly, we have code which considers
+ // "not yet confirmed" things as discardable, so we cannot do that here.
+ let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
+ let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
+ if !new_outputs.is_empty() {
+ watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
+ }
+ claimable_outpoints.append(&mut new_outpoints);
}
- claimable_outpoints.append(&mut new_outpoints);
}
// Find which on-chain events have reached their confirmation threshold.
}
fn should_broadcast_holder_commitment_txn<L: Deref>(&self, logger: &L) -> bool where L::Target: Logger {
+ // There's no need to broadcast our commitment transaction if we've seen one confirmed (even
+ // with 1 confirmation) as it'll be rejected as duplicate/conflicting.
+ if self.funding_spend_confirmed.is_some() ||
+ self.onchain_events_awaiting_threshold_conf.iter().find(|event| match event.event {
+ OnchainEvent::FundingSpendConfirmation { .. } => true,
+ _ => false,
+ }).is_some()
+ {
+ return false;
+ }
// We need to consider all HTLCs which are:
// * in any unrevoked counterparty commitment transaction, as they could broadcast said
// transactions and we'd end up in a race, or
fn is_resolving_htlc_output<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) where L::Target: Logger {
'outer_loop: for input in &tx.input {
let mut payment_data = None;
- let witness_items = input.witness.len();
- let htlctype = input.witness.last().map(|w| w.len()).and_then(HTLCType::scriptlen_to_htlctype);
- let prev_last_witness_len = input.witness.second_to_last().map(|w| w.len()).unwrap_or(0);
- let revocation_sig_claim = (witness_items == 3 && htlctype == Some(HTLCType::OfferedHTLC) && prev_last_witness_len == 33)
- || (witness_items == 3 && htlctype == Some(HTLCType::AcceptedHTLC) && prev_last_witness_len == 33);
- let accepted_preimage_claim = witness_items == 5 && htlctype == Some(HTLCType::AcceptedHTLC)
- && input.witness.second_to_last().unwrap().len() == 32;
+ let htlc_claim = HTLCClaim::from_witness(&input.witness);
+ let revocation_sig_claim = htlc_claim == Some(HTLCClaim::Revocation);
+ let accepted_preimage_claim = htlc_claim == Some(HTLCClaim::AcceptedPreimage);
#[cfg(not(fuzzing))]
- let accepted_timeout_claim = witness_items == 3 && htlctype == Some(HTLCType::AcceptedHTLC) && !revocation_sig_claim;
- let offered_preimage_claim = witness_items == 3 && htlctype == Some(HTLCType::OfferedHTLC) &&
- !revocation_sig_claim && input.witness.second_to_last().unwrap().len() == 32;
-
+ let accepted_timeout_claim = htlc_claim == Some(HTLCClaim::AcceptedTimeout);
+ let offered_preimage_claim = htlc_claim == Some(HTLCClaim::OfferedPreimage);
#[cfg(not(fuzzing))]
- let offered_timeout_claim = witness_items == 5 && htlctype == Some(HTLCType::OfferedHTLC);
+ let offered_timeout_claim = htlc_claim == Some(HTLCClaim::OfferedTimeout);
let mut payment_preimage = PaymentPreimage([0; 32]);
- if accepted_preimage_claim {
- payment_preimage.0.copy_from_slice(input.witness.second_to_last().unwrap());
- } else if offered_preimage_claim {
+ if offered_preimage_claim || accepted_preimage_claim {
payment_preimage.0.copy_from_slice(input.witness.second_to_last().unwrap());
}
let entry = OnchainEventEntry {
txid: tx.txid(),
transaction: Some(tx.clone()),
- height: height,
+ height,
event: OnchainEvent::MaturingOutput { descriptor: spendable_output.clone() },
};
log_info!(logger, "Received spendable output {}, spendable at height {}", log_spendable!(spendable_output), entry.confirmation_threshold());
use ln::{PaymentPreimage, PaymentHash};
use ln::chan_utils;
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
- use ln::channelmanager::PaymentSendFailure;
- use ln::features::InitFeatures;
+ use ln::channelmanager::{self, PaymentSendFailure};
use ln::functional_test_utils::*;
use ln::script::ShutdownScript;
use util::errors::APIError;
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
let channel = create_announced_chan_between_nodes(
- &nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ &nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
create_announced_chan_between_nodes(
- &nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ &nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance somewhat
send_payment(&nodes[0], &[&nodes[1]], 10_000_000);
use util::ser::{Writeable, Writer, Readable, ReadableArgs};
use chain::transaction::OutPoint;
+use ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
use ln::{chan_utils, PaymentPreimage};
use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction};
use ln::msgs::UnsignedChannelAnnouncement;
/// Information about a spendable output to a P2WSH script. See
/// SpendableOutputDescriptor::DelayedPaymentOutput for more details on how to spend this.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DelayedPaymentOutputDescriptor {
/// The outpoint which is spendable
pub outpoint: OutPoint,
/// Information about a spendable output to our "payment key". See
/// SpendableOutputDescriptor::StaticPaymentOutput for more details on how to spend this.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StaticPaymentOutputDescriptor {
/// The outpoint which is spendable
pub outpoint: OutPoint,
/// spend on-chain. The information needed to do this is provided in this enum, including the
/// outpoint describing which txid and output index is available, the full output which exists at
/// that txid/index, and any keys or other information required to sign.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SpendableOutputDescriptor {
/// An output to a script which was provided via KeysInterface directly, either from
/// `get_destination_script()` or `get_shutdown_scriptpubkey()`, thus you should already know
/// chosen to forgo their output as dust.
fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
+ /// Computes the signature for a commitment transaction's anchor output used as an
+ /// input within `anchor_tx`, which spends the commitment transaction, at index `input`.
+ fn sign_holder_anchor_input(
+ &self, anchor_tx: &mut Transaction, input: usize, secp_ctx: &Secp256k1<secp256k1::All>,
+ ) -> Result<Signature, ()>;
+
/// Signs a channel announcement message with our funding key and our node secret key (aka
/// node_id or network_key), proving it comes from one of the channel participants.
///
witness.push(witness_script.clone().into_bytes());
Ok(witness)
}
+
}
impl BaseSign for InMemorySigner {
Ok(closing_tx.trust().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
}
+ fn sign_holder_anchor_input(
+ &self, anchor_tx: &mut Transaction, input: usize, secp_ctx: &Secp256k1<secp256k1::All>,
+ ) -> Result<Signature, ()> {
+ let witness_script = chan_utils::get_anchor_redeemscript(&self.holder_channel_pubkeys.funding_pubkey);
+ let sighash = sighash::SighashCache::new(&*anchor_tx).segwit_signature_hash(
+ input, &witness_script, ANCHOR_OUTPUT_VALUE_SATOSHI, EcdsaSighashType::All,
+ ).unwrap();
+ Ok(sign(secp_ctx, &hash_to_message!(&sighash[..]), &self.funding_key))
+ }
+
fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>)
-> Result<(Signature, Signature), ()> {
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
pub(crate) mod package;
/// The best known block as identified by its hash and height.
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Eq)]
pub struct BestBlock {
block_hash: BlockHash,
height: u32,
fn get_relevant_txids(&self) -> Vec<Txid>;
}
-/// An error enum representing a failure to persist a channel monitor update.
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum ChannelMonitorUpdateErr {
+/// An enum representing the status of a channel monitor update persistence.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ChannelMonitorUpdateStatus {
+ /// The update has been durably persisted and all copies of the relevant [`ChannelMonitor`]
+ /// have been updated.
+ ///
+ /// This includes performing any `fsync()` calls required to ensure the update is guaranteed to
+ /// be available on restart even if the application crashes.
+ Completed,
/// Used to indicate a temporary failure (eg connection to a watchtower or remote backup of
/// our state failed, but is expected to succeed at some point in the future).
///
/// Such a failure will "freeze" a channel, preventing us from revoking old states or
- /// submitting new commitment transactions to the counterparty. Once the update(s) that failed
- /// have been successfully applied, a [`MonitorEvent::UpdateCompleted`] event should be returned
- /// via [`Watch::release_pending_monitor_events`] which will then restore the channel to an
- /// operational state.
- ///
- /// Note that a given ChannelManager will *never* re-generate a given ChannelMonitorUpdate. If
- /// you return a TemporaryFailure you must ensure that it is written to disk safely before
- /// writing out the latest ChannelManager state.
- ///
- /// Even when a channel has been "frozen" updates to the ChannelMonitor can continue to occur
- /// (eg if an inbound HTLC which we forwarded was claimed upstream resulting in us attempting
- /// to claim it on this channel) and those updates must be applied wherever they can be. At
- /// least one such updated ChannelMonitor must be persisted otherwise PermanentFailure should
- /// be returned to get things on-chain ASAP using only the in-memory copy. Obviously updates to
- /// the channel which would invalidate previous ChannelMonitors are not made when a channel has
- /// been "frozen".
- ///
- /// Note that even if updates made after TemporaryFailure succeed you must still provide a
- /// [`MonitorEvent::UpdateCompleted`] to ensure you have the latest monitor and re-enable
- /// normal channel operation. Note that this is normally generated through a call to
- /// [`ChainMonitor::channel_monitor_updated`].
- ///
- /// Note that the update being processed here will not be replayed for you when you return a
- /// [`MonitorEvent::UpdateCompleted`] event via [`Watch::release_pending_monitor_events`], so
- /// you must store the update itself on your own local disk prior to returning a
- /// TemporaryFailure. You may, of course, employ a journaling approach, storing only the
- /// ChannelMonitorUpdate on disk without updating the monitor itself, replaying the journal at
- /// reload-time.
+ /// submitting new commitment transactions to the counterparty. Once the update(s) which failed
+ /// have been successfully applied, a [`MonitorEvent::Completed`] can be used to restore the
+ /// channel to an operational state.
+ ///
+ /// Note that a given [`ChannelManager`] will *never* re-generate a [`ChannelMonitorUpdate`].
+ /// If you return this error you must ensure that it is written to disk safely before writing
+ /// the latest [`ChannelManager`] state, or you should return [`PermanentFailure`] instead.
+ ///
+ /// Even when a channel has been "frozen", updates to the [`ChannelMonitor`] can continue to
+ /// occur (e.g. if an inbound HTLC which we forwarded was claimed upstream, resulting in us
+ /// attempting to claim it on this channel) and those updates must still be persisted.
+ ///
+ /// No updates to the channel will be made which could invalidate other [`ChannelMonitor`]s
+ /// until a [`MonitorEvent::Completed`] is provided, even if you return no error on a later
+ /// monitor update for the same channel.
///
/// For deployments where a copy of ChannelMonitors and other local state are backed up in a
/// remote location (with local copies persisted immediately), it is anticipated that all
- /// updates will return TemporaryFailure until the remote copies could be updated.
+ /// updates will return [`InProgress`] until the remote copies could be updated.
///
- /// [`ChainMonitor::channel_monitor_updated`]: chainmonitor::ChainMonitor::channel_monitor_updated
- TemporaryFailure,
- /// Used to indicate no further channel monitor updates will be allowed (eg we've moved on to a
- /// different watchtower and cannot update with all watchtowers that were previously informed
- /// of this channel).
+ /// [`PermanentFailure`]: ChannelMonitorUpdateStatus::PermanentFailure
+ /// [`InProgress`]: ChannelMonitorUpdateStatus::InProgress
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+ InProgress,
+ /// Used to indicate no further channel monitor updates will be allowed (likely a disk failure
+ /// or a remote copy of this [`ChannelMonitor`] is no longer reachable and thus not updatable).
///
- /// At reception of this error, ChannelManager will force-close the channel and return at
- /// least a final ChannelMonitorUpdate::ChannelForceClosed which must be delivered to at
- /// least one ChannelMonitor copy. Revocation secret MUST NOT be released and offchain channel
- /// update must be rejected.
+ /// When this is returned, [`ChannelManager`] will force-close the channel but *not* broadcast
+ /// our current commitment transaction. This avoids a dangerous case where a local disk failure
+ /// (e.g. the Linux-default remounting of the disk as read-only) causes [`PermanentFailure`]s
+ /// for all monitor updates. If we were to broadcast our latest commitment transaction and then
+ /// restart, we could end up reading a previous [`ChannelMonitor`] and [`ChannelManager`],
+ /// revoking our now-broadcasted state before seeing it confirm and losing all our funds.
///
- /// This failure may also signal a failure to update the local persisted copy of one of
- /// the channel monitor instance.
+ /// Note that this is somewhat of a tradeoff - if the disk is really gone and we may have lost
+ /// the data permanently, we really should broadcast immediately. If the data can be recovered
+ /// with manual intervention, we'd rather close the channel, rejecting future updates to it,
+ /// and broadcast the latest state only if we have HTLCs to claim which are timing out (which
+ /// we do as long as blocks are connected).
///
- /// Note that even when you fail a holder commitment transaction update, you must store the
- /// update to ensure you can claim from it in case of a duplicate copy of this ChannelMonitor
- /// broadcasts it (e.g distributed channel-monitor deployment)
+ /// In order to broadcast the latest local commitment transaction, you'll need to call
+ /// [`ChannelMonitor::get_latest_holder_commitment_txn`] and broadcast the resulting
+ /// transactions once you've safely ensured no further channel updates can be generated by your
+ /// [`ChannelManager`].
+ ///
+ /// Note that at least one final [`ChannelMonitorUpdate`] may still be provided, which must
+ /// still be processed by a running [`ChannelMonitor`]. This final update will mark the
+ /// [`ChannelMonitor`] as finalized, ensuring no further updates (e.g. revocation of the latest
+ /// commitment transaction) are allowed.
+ ///
+ /// Note that even if you return a [`PermanentFailure`] due to unavailability of secondary
+ /// [`ChannelMonitor`] copies, you should still make an attempt to store the update where
+ /// possible to ensure you can claim HTLC outputs on the latest commitment transaction
+ /// broadcasted later.
///
/// In case of distributed watchtowers deployment, the new version must be written to disk, as
/// state may have been stored but rejected due to a block forcing a commitment broadcast. This
/// storage is used to claim outputs of rejected state confirmed onchain by another watchtower,
/// lagging behind on block processing.
+ ///
+ /// [`PermanentFailure`]: ChannelMonitorUpdateStatus::PermanentFailure
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
PermanentFailure,
}
/// If an implementation maintains multiple instances of a channel's monitor (e.g., by storing
/// backup copies), then it must ensure that updates are applied across all instances. Otherwise, it
/// could result in a revoked transaction being broadcast, allowing the counterparty to claim all
-/// funds in the channel. See [`ChannelMonitorUpdateErr`] for more details about how to handle
+/// funds in the channel. See [`ChannelMonitorUpdateStatus`] for more details about how to handle
/// multiple instances.
///
-/// [`PermanentFailure`]: ChannelMonitorUpdateErr::PermanentFailure
+/// [`PermanentFailure`]: ChannelMonitorUpdateStatus::PermanentFailure
pub trait Watch<ChannelSigner: Sign> {
/// Watches a channel identified by `funding_txo` using `monitor`.
///
/// with any spends of outputs returned by [`get_outputs_to_watch`]. In practice, this means
/// calling [`block_connected`] and [`block_disconnected`] on the monitor.
///
- /// Note: this interface MUST error with `ChannelMonitorUpdateErr::PermanentFailure` if
+ /// Note: this interface MUST error with [`ChannelMonitorUpdateStatus::PermanentFailure`] if
/// the given `funding_txo` has previously been registered via `watch_channel`.
///
/// [`get_outputs_to_watch`]: channelmonitor::ChannelMonitor::get_outputs_to_watch
/// [`block_connected`]: channelmonitor::ChannelMonitor::block_connected
/// [`block_disconnected`]: channelmonitor::ChannelMonitor::block_disconnected
- fn watch_channel(&self, funding_txo: OutPoint, monitor: ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr>;
+ fn watch_channel(&self, funding_txo: OutPoint, monitor: ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
/// Updates a channel identified by `funding_txo` by applying `update` to its monitor.
///
/// Implementations must call [`update_monitor`] with the given update. See
- /// [`ChannelMonitorUpdateErr`] for invariants around returning an error.
+ /// [`ChannelMonitorUpdateStatus`] for invariants around returning an error.
///
/// [`update_monitor`]: channelmonitor::ChannelMonitor::update_monitor
- fn update_channel(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr>;
+ fn update_channel(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> ChannelMonitorUpdateStatus;
/// Returns any monitor events since the last call. Subsequent calls must only return new
/// events.
/// to disk.
///
/// For details on asynchronous [`ChannelMonitor`] updating and returning
- /// [`MonitorEvent::UpdateCompleted`] here, see [`ChannelMonitorUpdateErr::TemporaryFailure`].
+ /// [`MonitorEvent::Completed`] here, see [`ChannelMonitorUpdateStatus::InProgress`].
fn release_pending_monitor_events(&self) -> Vec<(OutPoint, Vec<MonitorEvent>, Option<PublicKey>)>;
}
/// Note that use as part of a [`Watch`] implementation involves reentrancy. Therefore, the `Filter`
/// should not block on I/O. Implementations should instead queue the newly monitored data to be
/// processed later. Then, in order to block until the data has been processed, any [`Watch`]
-/// invocation that has called the `Filter` must return [`TemporaryFailure`].
+/// invocation that has called the `Filter` must return [`InProgress`].
///
-/// [`TemporaryFailure`]: ChannelMonitorUpdateErr::TemporaryFailure
+/// [`InProgress`]: ChannelMonitorUpdateStatus::InProgress
/// [BIP 157]: https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki
/// [BIP 158]: https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki
pub trait Filter {
///
/// [`ChannelMonitor`]: channelmonitor::ChannelMonitor
/// [`ChannelMonitor::block_connected`]: channelmonitor::ChannelMonitor::block_connected
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct WatchedOutput {
/// First block where the transaction output may have been spent.
pub block_hash: Option<BlockHash>,
use ln::msgs::DecodeError;
use ln::PaymentPreimage;
+#[cfg(anchors)]
+use ln::chan_utils;
use ln::chan_utils::{ChannelTransactionParameters, HolderCommitmentTransaction};
+#[cfg(anchors)]
+use chain::chaininterface::ConfirmationTarget;
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, LowerBoundedFeeEstimator};
use chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER};
use chain::keysinterface::{Sign, KeysInterface};
+#[cfg(anchors)]
+use chain::package::PackageSolvingData;
use chain::package::PackageTemplate;
use util::logger::Logger;
use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, VecWriter};
use core::cmp;
use core::ops::Deref;
use core::mem::replace;
+#[cfg(anchors)]
+use core::mem::swap;
use bitcoin::hashes::Hash;
const MAX_ALLOC_SIZE: usize = 64*1024;
/// transaction causing it.
///
/// Used to determine when the on-chain event can be considered safe from a chain reorganization.
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
struct OnchainEventEntry {
txid: Txid,
height: u32,
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
enum OnchainEvent {
/// Outpoint under claim process by our own tx, once this one get enough confirmations, we remove it from
/// bump-txn candidate buffer.
}
}
+// Represents the different types of claims for which events are yielded externally to satisfy said
+// claims.
+#[cfg(anchors)]
+pub(crate) enum ClaimEvent {
+ /// Event yielded to signal that the commitment transaction fee must be bumped to claim any
+ /// encumbered funds and proceed to HTLC resolution, if any HTLCs exist.
+ BumpCommitment {
+ package_target_feerate_sat_per_1000_weight: u32,
+ commitment_tx: Transaction,
+ anchor_output_idx: u32,
+ },
+}
+
+/// Represents the different ways an output can be claimed (i.e., spent to an address under our
+/// control) onchain.
+pub(crate) enum OnchainClaim {
+ /// A finalized transaction pending confirmation spending the output to claim.
+ Tx(Transaction),
+ #[cfg(anchors)]
+ /// An event yielded externally to signal additional inputs must be added to a transaction
+ /// pending confirmation spending the output to claim.
+ Event(ClaimEvent),
+}
/// OnchainTxHandler receives claiming requests, aggregates them if it's sound, broadcast and
/// do RBF bumping if possible.
pub(crate) pending_claim_requests: HashMap<Txid, PackageTemplate>,
#[cfg(not(test))]
pending_claim_requests: HashMap<Txid, PackageTemplate>,
+ #[cfg(anchors)]
+ pending_claim_events: HashMap<Txid, ClaimEvent>,
// Used to link outpoints claimed in a connected block to a pending claim request.
// Key is outpoint than monitor parsing has detected we have keys/scripts to claim
locktimed_packages,
pending_claim_requests,
onchain_events_awaiting_threshold_conf,
+ #[cfg(anchors)]
+ pending_claim_events: HashMap::new(),
secp_ctx,
})
}
claimable_outpoints: HashMap::new(),
locktimed_packages: BTreeMap::new(),
onchain_events_awaiting_threshold_conf: Vec::new(),
+ #[cfg(anchors)]
+ pending_claim_events: HashMap::new(),
secp_ctx,
}
self.holder_commitment.to_broadcaster_value_sat()
}
- /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize coutnerparty onchain) lays on the assumption of claim transactions getting confirmed before timelock expiration
- /// (CSV or CLTV following cases). In case of high-fee spikes, claim tx may stuck in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or Child-Pay-For-Parent.
- /// Panics if there are signing errors, because signing operations in reaction to on-chain events
- /// are not expected to fail, and if they do, we may lose funds.
- fn generate_claim_tx<F: Deref, L: Deref>(&mut self, cur_height: u32, cached_request: &PackageTemplate, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L) -> Option<(Option<u32>, u64, Transaction)>
+ #[cfg(anchors)]
+ pub(crate) fn get_and_clear_pending_claim_events(&mut self) -> Vec<ClaimEvent> {
+ let mut ret = HashMap::new();
+ swap(&mut ret, &mut self.pending_claim_events);
+ ret.into_iter().map(|(_, event)| event).collect::<Vec<_>>()
+ }
+
+ /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize counterparty
+ /// onchain) lays on the assumption of claim transactions getting confirmed before timelock
+ /// expiration (CSV or CLTV following cases). In case of high-fee spikes, claim tx may get stuck
+ /// in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or
+ /// Child-Pay-For-Parent.
+ ///
+ /// Panics if there are signing errors, because signing operations in reaction to on-chain
+ /// events are not expected to fail, and if they do, we may lose funds.
+ fn generate_claim<F: Deref, L: Deref>(&mut self, cur_height: u32, cached_request: &PackageTemplate, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L) -> Option<(Option<u32>, u64, OnchainClaim)>
where F::Target: FeeEstimator,
L::Target: Logger,
{
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
let new_timer = Some(cached_request.get_height_timer(cur_height));
if cached_request.is_malleable() {
- let predicted_weight = cached_request.package_weight(&self.destination_script, self.channel_transaction_parameters.opt_anchors.is_some());
+ let predicted_weight = cached_request.package_weight(&self.destination_script);
if let Some((output_value, new_feerate)) =
cached_request.compute_package_output(predicted_weight, self.destination_script.dust_value().to_sat(), fee_estimator, logger) {
assert!(new_feerate != 0);
- let transaction = cached_request.finalize_package(self, output_value, self.destination_script.clone(), logger).unwrap();
+ let transaction = cached_request.finalize_malleable_package(self, output_value, self.destination_script.clone(), logger).unwrap();
log_trace!(logger, "...with timer {} and feerate {}", new_timer.unwrap(), new_feerate);
assert!(predicted_weight >= transaction.weight());
- return Some((new_timer, new_feerate, transaction))
+ return Some((new_timer, new_feerate, OnchainClaim::Tx(transaction)))
}
} else {
- // Note: Currently, amounts of holder outputs spending witnesses aren't used
- // as we can't malleate spending package to increase their feerate. This
- // should change with the remaining anchor output patchset.
- if let Some(transaction) = cached_request.finalize_package(self, 0, self.destination_script.clone(), logger) {
- return Some((None, 0, transaction));
+ // Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
+ // packages may support fee bumping through Child-Pays-For-Parent, indicated by those
+ // which require external funding.
+ #[cfg(not(anchors))]
+ let inputs = cached_request.inputs();
+ #[cfg(anchors)]
+ let mut inputs = cached_request.inputs();
+ debug_assert_eq!(inputs.len(), 1);
+ let tx = match cached_request.finalize_untractable_package(self, logger) {
+ Some(tx) => tx,
+ None => return None,
+ };
+ if !cached_request.requires_external_funding() {
+ return Some((None, 0, OnchainClaim::Tx(tx)));
}
+ #[cfg(anchors)]
+ return inputs.find_map(|input| match input {
+ // Commitment inputs with anchors support are the only untractable inputs supported
+ // thus far that require external funding.
+ PackageSolvingData::HolderFundingOutput(..) => {
+ debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
+ "Holder commitment transaction mismatch");
+ // We'll locate an anchor output we can spend within the commitment transaction.
+ let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
+ match chan_utils::get_anchor_output(&tx, funding_pubkey) {
+ // An anchor output was found, so we should yield a funding event externally.
+ Some((idx, _)) => {
+ // TODO: Use a lower confirmation target when both our and the
+ // counterparty's latest commitment don't have any HTLCs present.
+ let conf_target = ConfirmationTarget::HighPriority;
+ let package_target_feerate_sat_per_1000_weight = cached_request
+ .compute_package_feerate(fee_estimator, conf_target);
+ Some((
+ new_timer,
+ package_target_feerate_sat_per_1000_weight as u64,
+ OnchainClaim::Event(ClaimEvent::BumpCommitment {
+ package_target_feerate_sat_per_1000_weight,
+ commitment_tx: tx.clone(),
+ anchor_output_idx: idx,
+ }),
+ ))
+ },
+ // An anchor output was not found. There's nothing we can do other than
+ // attempt to broadcast the transaction with its current fee rate and hope
+ // it confirms. This is essentially the same behavior as a commitment
+ // transaction without anchor outputs.
+ None => Some((None, 0, OnchainClaim::Tx(tx.clone()))),
+ }
+ },
+ _ => {
+ debug_assert!(false, "Only HolderFundingOutput inputs should be untractable and require external funding");
+ None
+ },
+ });
}
None
}
// Generate claim transactions and track them to bump if necessary at
// height timer expiration (i.e in how many blocks we're going to take action).
for mut req in preprocessed_requests {
- if let Some((new_timer, new_feerate, tx)) = self.generate_claim_tx(cur_height, &req, &*fee_estimator, &*logger) {
+ if let Some((new_timer, new_feerate, claim)) = self.generate_claim(cur_height, &req, &*fee_estimator, &*logger) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
- let txid = tx.txid();
+ let txid = match claim {
+ OnchainClaim::Tx(tx) => {
+ log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
+ broadcaster.broadcast_transaction(&tx);
+ tx.txid()
+ },
+ #[cfg(anchors)]
+ OnchainClaim::Event(claim_event) => {
+ log_info!(logger, "Yielding onchain event to spend inputs {:?}", req.outpoints());
+ let txid = match claim_event {
+ ClaimEvent::BumpCommitment { ref commitment_tx, .. } => commitment_tx.txid(),
+ };
+ self.pending_claim_events.insert(txid, claim_event);
+ txid
+ },
+ };
for k in req.outpoints() {
log_info!(logger, "Registering claiming request for {}:{}", k.txid, k.vout);
self.claimable_outpoints.insert(k.clone(), (txid, conf_height));
}
self.pending_claim_requests.insert(txid, req);
- log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
- broadcaster.broadcast_transaction(&tx);
}
}
for outpoint in request.outpoints() {
log_debug!(logger, "Removing claim tracking for {} due to maturation of claim tx {}.", outpoint, claim_request);
self.claimable_outpoints.remove(&outpoint);
+ #[cfg(anchors)]
+ self.pending_claim_events.remove(&claim_request);
}
}
},
// Build, bump and rebroadcast tx accordingly
log_trace!(logger, "Bumping {} candidates", bump_candidates.len());
for (first_claim_txid, request) in bump_candidates.iter() {
- if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(cur_height, &request, &*fee_estimator, &*logger) {
- log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx));
- broadcaster.broadcast_transaction(&bump_tx);
+ if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(cur_height, &request, &*fee_estimator, &*logger) {
+ match bump_claim {
+ OnchainClaim::Tx(bump_tx) => {
+ log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx));
+ broadcaster.broadcast_transaction(&bump_tx);
+ },
+ #[cfg(anchors)]
+ OnchainClaim::Event(claim_event) => {
+ log_info!(logger, "Yielding RBF-bumped onchain event to spend inputs {:?}", request.outpoints());
+ self.pending_claim_events.insert(*first_claim_txid, claim_event);
+ },
+ }
if let Some(request) = self.pending_claim_requests.get_mut(first_claim_txid) {
request.set_timer(new_timer);
request.set_feerate(new_feerate);
self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
- for (_, request) in bump_candidates.iter_mut() {
- if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, fee_estimator, &&*logger) {
+ for (_first_claim_txid_height, request) in bump_candidates.iter_mut() {
+ if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(height, &request, fee_estimator, &&*logger) {
request.set_timer(new_timer);
request.set_feerate(new_feerate);
- log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
- broadcaster.broadcast_transaction(&bump_tx);
+ match bump_claim {
+ OnchainClaim::Tx(bump_tx) => {
+ log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
+ broadcaster.broadcast_transaction(&bump_tx);
+ },
+ #[cfg(anchors)]
+ OnchainClaim::Event(claim_event) => {
+ log_info!(logger, "Yielding onchain event after reorg to spend inputs {:?}", request.outpoints());
+ self.pending_claim_events.insert(_first_claim_txid_height.0, claim_event);
+ },
+ }
}
}
for (ancestor_claim_txid, request) in bump_candidates.drain() {
use io;
use prelude::*;
use core::cmp;
+#[cfg(anchors)]
+use core::convert::TryInto;
use core::mem;
use core::ops::Deref;
use bitcoin::{PackedLockTime, Sequence, Witness};
///
/// CSV and pubkeys are used as part of a witnessScript redeeming a balance output, amount is used
/// as part of the signature hash and revocation secret to generate a satisfying witness.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) struct RevokedOutput {
per_commitment_point: PublicKey,
counterparty_delayed_payment_base_key: PublicKey,
///
/// CSV is used as part of a witnessScript redeeming a balance output, amount is used as part
/// of the signature hash and revocation secret to generate a satisfying witness.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) struct RevokedHTLCOutput {
per_commitment_point: PublicKey,
counterparty_delayed_payment_base_key: PublicKey,
/// witnessScript.
///
/// The preimage is used as part of the witness.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) struct CounterpartyOfferedHTLCOutput {
per_commitment_point: PublicKey,
counterparty_delayed_payment_base_key: PublicKey,
counterparty_htlc_base_key: PublicKey,
preimage: PaymentPreimage,
- htlc: HTLCOutputInCommitment
+ htlc: HTLCOutputInCommitment,
+ opt_anchors: Option<()>,
}
impl CounterpartyOfferedHTLCOutput {
- pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment) -> Self {
+ pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self {
CounterpartyOfferedHTLCOutput {
per_commitment_point,
counterparty_delayed_payment_base_key,
counterparty_htlc_base_key,
preimage,
- htlc
+ htlc,
+ opt_anchors: if opt_anchors { Some(()) } else { None },
}
}
+
+ fn opt_anchors(&self) -> bool {
+ self.opt_anchors.is_some()
+ }
}
impl_writeable_tlv_based!(CounterpartyOfferedHTLCOutput, {
(0, per_commitment_point, required),
+ (1, opt_anchors, option),
(2, counterparty_delayed_payment_base_key, required),
(4, counterparty_htlc_base_key, required),
(6, preimage, required),
///
/// HTLCOutputInCommitment (hash, timelock, directon) and pubkeys are used to generate a suitable
/// witnessScript.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) struct CounterpartyReceivedHTLCOutput {
per_commitment_point: PublicKey,
counterparty_delayed_payment_base_key: PublicKey,
counterparty_htlc_base_key: PublicKey,
- htlc: HTLCOutputInCommitment
+ htlc: HTLCOutputInCommitment,
+ opt_anchors: Option<()>,
}
impl CounterpartyReceivedHTLCOutput {
- pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment) -> Self {
+ pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self {
CounterpartyReceivedHTLCOutput {
per_commitment_point,
counterparty_delayed_payment_base_key,
counterparty_htlc_base_key,
- htlc
+ htlc,
+ opt_anchors: if opt_anchors { Some(()) } else { None },
}
}
+
+ fn opt_anchors(&self) -> bool {
+ self.opt_anchors.is_some()
+ }
}
impl_writeable_tlv_based!(CounterpartyReceivedHTLCOutput, {
(0, per_commitment_point, required),
+ (1, opt_anchors, option),
(2, counterparty_delayed_payment_base_key, required),
(4, counterparty_htlc_base_key, required),
(6, htlc, required),
///
/// Either offered or received, the amount is always used as part of the bip143 sighash.
/// Preimage is only included as part of the witness in former case.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderHTLCOutput {
preimage: Option<PaymentPreimage>,
amount: u64,
/// A struct to describe the channel output on the funding transaction.
///
/// witnessScript is used as part of the witness redeeming the funding utxo.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
+ funding_amount: Option<u64>,
+ opt_anchors: Option<()>,
}
+
impl HolderFundingOutput {
- pub(crate) fn build(funding_redeemscript: Script) -> Self {
+ pub(crate) fn build(funding_redeemscript: Script, funding_amount: u64, opt_anchors: bool) -> Self {
HolderFundingOutput {
funding_redeemscript,
+ funding_amount: Some(funding_amount),
+ opt_anchors: if opt_anchors { Some(()) } else { None },
}
}
+
+ fn opt_anchors(&self) -> bool {
+ self.opt_anchors.is_some()
+ }
}
impl_writeable_tlv_based!(HolderFundingOutput, {
(0, funding_redeemscript, required),
+ (1, opt_anchors, option),
+ (3, funding_amount, option),
});
/// A wrapper encapsulating all in-protocol differing outputs types.
///
/// The generic API offers access to an outputs common attributes or allow transformation such as
/// finalizing an input claiming the output.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) enum PackageSolvingData {
RevokedOutput(RevokedOutput),
RevokedHTLCOutput(RevokedHTLCOutput),
impl PackageSolvingData {
fn amount(&self) -> u64 {
let amt = match self {
- PackageSolvingData::RevokedOutput(ref outp) => { outp.amount },
- PackageSolvingData::RevokedHTLCOutput(ref outp) => { outp.amount },
- PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => { outp.htlc.amount_msat / 1000 },
- PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => { outp.htlc.amount_msat / 1000 },
+ PackageSolvingData::RevokedOutput(ref outp) => outp.amount,
+ PackageSolvingData::RevokedHTLCOutput(ref outp) => outp.amount,
+ PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => outp.htlc.amount_msat / 1000,
+ PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => outp.htlc.amount_msat / 1000,
// Note: Currently, amounts of holder outputs spending witnesses aren't used
// as we can't malleate spending package to increase their feerate. This
// should change with the remaining anchor output patchset.
- PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() },
- PackageSolvingData::HolderFundingOutput(..) => { unreachable!() },
+ PackageSolvingData::HolderHTLCOutput(..) => unreachable!(),
+ PackageSolvingData::HolderFundingOutput(ref outp) => {
+ debug_assert!(outp.opt_anchors());
+ outp.funding_amount.unwrap()
+ }
};
amt
}
- fn weight(&self, opt_anchors: bool) -> usize {
+ fn weight(&self) -> usize {
let weight = match self {
PackageSolvingData::RevokedOutput(ref outp) => { outp.weight as usize },
PackageSolvingData::RevokedHTLCOutput(ref outp) => { outp.weight as usize },
- PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { weight_offered_htlc(opt_anchors) as usize },
- PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { weight_received_htlc(opt_anchors) as usize },
+ PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => { weight_offered_htlc(outp.opt_anchors()) as usize },
+ PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => { weight_received_htlc(outp.opt_anchors()) as usize },
// Note: Currently, weights of holder outputs spending witnesses aren't used
// as we can't malleate spending package to increase their feerate. This
// should change with the remaining anchor output patchset.
/// A malleable package might be aggregated with other packages to save on fees.
/// A untractable package has been counter-signed and aggregable will break cached counterparty
/// signatures.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) enum PackageMalleability {
Malleable,
Untractable,
///
/// As packages are time-sensitive, we fee-bump and rebroadcast them at scheduled intervals.
/// Failing to confirm a package translate as a loss of funds for the user.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub struct PackageTemplate {
// List of onchain outputs and solving data to generate satisfying witnesses.
inputs: Vec<(BitcoinOutPoint, PackageSolvingData)>,
pub(crate) fn outpoints(&self) -> Vec<&BitcoinOutPoint> {
self.inputs.iter().map(|(o, _)| o).collect()
}
+ pub(crate) fn inputs(&self) -> impl ExactSizeIterator<Item = &PackageSolvingData> {
+ self.inputs.iter().map(|(_, i)| i)
+ }
pub(crate) fn split_package(&mut self, split_outp: &BitcoinOutPoint) -> Option<PackageTemplate> {
match self.malleability {
PackageMalleability::Malleable => {
}
/// Gets the amount of all outptus being spent by this package, only valid for malleable
/// packages.
- fn package_amount(&self) -> u64 {
+ pub(crate) fn package_amount(&self) -> u64 {
let mut amounts = 0;
for (_, outp) in self.inputs.iter() {
amounts += outp.amount();
self.inputs.iter().map(|(_, outp)| outp.absolute_tx_timelock(self.height_original))
.max().expect("There must always be at least one output to spend in a PackageTemplate")
}
- pub(crate) fn package_weight(&self, destination_script: &Script, opt_anchors: bool) -> usize {
+ pub(crate) fn package_weight(&self, destination_script: &Script) -> usize {
let mut inputs_weight = 0;
let mut witnesses_weight = 2; // count segwit flags
for (_, outp) in self.inputs.iter() {
// previous_out_point: 36 bytes ; var_int: 1 byte ; sequence: 4 bytes
inputs_weight += 41 * WITNESS_SCALE_FACTOR;
- witnesses_weight += outp.weight(opt_anchors);
+ witnesses_weight += outp.weight();
}
// version: 4 bytes ; count_tx_in: 1 byte ; count_tx_out: 1 byte ; lock_time: 4 bytes
let transaction_weight = 10 * WITNESS_SCALE_FACTOR;
let output_weight = (8 + 1 + destination_script.len()) * WITNESS_SCALE_FACTOR;
inputs_weight + witnesses_weight + transaction_weight + output_weight
}
- pub(crate) fn finalize_package<L: Deref, Signer: Sign>(&self, onchain_handler: &mut OnchainTxHandler<Signer>, value: u64, destination_script: Script, logger: &L) -> Option<Transaction>
- where L::Target: Logger,
- {
- match self.malleability {
- PackageMalleability::Malleable => {
- let mut bumped_tx = Transaction {
- version: 2,
- lock_time: PackedLockTime::ZERO,
- input: vec![],
- output: vec![TxOut {
- script_pubkey: destination_script,
- value,
- }],
- };
- for (outpoint, _) in self.inputs.iter() {
- bumped_tx.input.push(TxIn {
- previous_output: *outpoint,
- script_sig: Script::new(),
- sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
- witness: Witness::new(),
- });
- }
- for (i, (outpoint, out)) in self.inputs.iter().enumerate() {
- log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);
- if !out.finalize_input(&mut bumped_tx, i, onchain_handler) { return None; }
- }
- log_debug!(logger, "Finalized transaction {} ready to broadcast", bumped_tx.txid());
- return Some(bumped_tx);
- },
- PackageMalleability::Untractable => {
- debug_assert_eq!(value, 0, "value is ignored for non-malleable packages, should be zero to ensure callsites are correct");
- if let Some((outpoint, outp)) = self.inputs.first() {
- if let Some(final_tx) = outp.get_finalized_tx(outpoint, onchain_handler) {
- log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);
- log_debug!(logger, "Finalized transaction {} ready to broadcast", final_tx.txid());
- return Some(final_tx);
- }
- return None;
- } else { panic!("API Error: Package must not be inputs empty"); }
- },
+ pub(crate) fn finalize_malleable_package<L: Deref, Signer: Sign>(
+ &self, onchain_handler: &mut OnchainTxHandler<Signer>, value: u64, destination_script: Script, logger: &L
+ ) -> Option<Transaction> where L::Target: Logger {
+ debug_assert!(self.is_malleable());
+ let mut bumped_tx = Transaction {
+ version: 2,
+ lock_time: PackedLockTime::ZERO,
+ input: vec![],
+ output: vec![TxOut {
+ script_pubkey: destination_script,
+ value,
+ }],
+ };
+ for (outpoint, _) in self.inputs.iter() {
+ bumped_tx.input.push(TxIn {
+ previous_output: *outpoint,
+ script_sig: Script::new(),
+ sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
+ witness: Witness::new(),
+ });
+ }
+ for (i, (outpoint, out)) in self.inputs.iter().enumerate() {
+ log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);
+ if !out.finalize_input(&mut bumped_tx, i, onchain_handler) { return None; }
}
+ log_debug!(logger, "Finalized transaction {} ready to broadcast", bumped_tx.txid());
+ Some(bumped_tx)
+ }
+ pub(crate) fn finalize_untractable_package<L: Deref, Signer: Sign>(
+ &self, onchain_handler: &mut OnchainTxHandler<Signer>, logger: &L,
+ ) -> Option<Transaction> where L::Target: Logger {
+ debug_assert!(!self.is_malleable());
+ if let Some((outpoint, outp)) = self.inputs.first() {
+ if let Some(final_tx) = outp.get_finalized_tx(outpoint, onchain_handler) {
+ log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);
+ log_debug!(logger, "Finalized transaction {} ready to broadcast", final_tx.txid());
+ return Some(final_tx);
+ }
+ return None;
+ } else { panic!("API Error: Package must not be inputs empty"); }
}
/// In LN, output claimed are time-sensitive, which means we have to spend them before reaching some timelock expiration. At in-channel
/// output detection, we generate a first version of a claim tx and associate to it a height timer. A height timer is an absolute block
}
None
}
+
+ #[cfg(anchors)]
+ /// Computes a feerate based on the given confirmation target. If a previous feerate was used,
+ /// and the new feerate is below it, we'll use a 25% increase of the previous feerate instead of
+ /// the new one.
+ pub(crate) fn compute_package_feerate<F: Deref>(
+ &self, fee_estimator: &LowerBoundedFeeEstimator<F>, conf_target: ConfirmationTarget,
+ ) -> u32 where F::Target: FeeEstimator {
+ let feerate_estimate = fee_estimator.bounded_sat_per_1000_weight(conf_target);
+ if self.feerate_previous != 0 {
+ // If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
+ if feerate_estimate as u64 > self.feerate_previous {
+ feerate_estimate
+ } else {
+ // ...else just increase the previous feerate by 25% (because that's a nice number)
+ (self.feerate_previous + (self.feerate_previous / 4)).try_into().unwrap_or(u32::max_value())
+ }
+ } else {
+ feerate_estimate
+ }
+ }
+
+ /// Determines whether a package contains an input which must have additional external inputs
+ /// attached to help the spending transaction reach confirmation.
+ pub(crate) fn requires_external_funding(&self) -> bool {
+ self.inputs.iter().find(|input| match input.1 {
+ PackageSolvingData::HolderFundingOutput(ref outp) => outp.opt_anchors(),
+ _ => false,
+ }).is_some()
+ }
+
pub (crate) fn build_package(txid: Txid, vout: u32, input_solving_data: PackageSolvingData, soonest_conf_deadline: u32, aggregable: bool, height_original: u32) -> Self {
let malleability = match input_solving_data {
- PackageSolvingData::RevokedOutput(..) => { PackageMalleability::Malleable },
- PackageSolvingData::RevokedHTLCOutput(..) => { PackageMalleability::Malleable },
- PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { PackageMalleability::Malleable },
- PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { PackageMalleability::Malleable },
- PackageSolvingData::HolderHTLCOutput(..) => { PackageMalleability::Untractable },
- PackageSolvingData::HolderFundingOutput(..) => { PackageMalleability::Untractable },
+ PackageSolvingData::RevokedOutput(..) => PackageMalleability::Malleable,
+ PackageSolvingData::RevokedHTLCOutput(..) => PackageMalleability::Malleable,
+ PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => PackageMalleability::Malleable,
+ PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => PackageMalleability::Malleable,
+ PackageSolvingData::HolderHTLCOutput(..) => PackageMalleability::Untractable,
+ PackageSolvingData::HolderFundingOutput(..) => PackageMalleability::Untractable,
};
let mut inputs = Vec::with_capacity(1);
inputs.push((BitcoinOutPoint { txid, vout }, input_solving_data));
}
macro_rules! dumb_counterparty_output {
- ($secp_ctx: expr, $amt: expr) => {
+ ($secp_ctx: expr, $amt: expr, $opt_anchors: expr) => {
{
let dumb_scalar = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap();
let dumb_point = PublicKey::from_secret_key(&$secp_ctx, &dumb_scalar);
let hash = PaymentHash([1; 32]);
let htlc = HTLCOutputInCommitment { offered: true, amount_msat: $amt, cltv_expiry: 0, payment_hash: hash, transaction_output_index: None };
- PackageSolvingData::CounterpartyReceivedHTLCOutput(CounterpartyReceivedHTLCOutput::build(dumb_point, dumb_point, dumb_point, htlc))
+ PackageSolvingData::CounterpartyReceivedHTLCOutput(CounterpartyReceivedHTLCOutput::build(dumb_point, dumb_point, dumb_point, htlc, $opt_anchors))
}
}
}
macro_rules! dumb_counterparty_offered_output {
- ($secp_ctx: expr, $amt: expr) => {
+ ($secp_ctx: expr, $amt: expr, $opt_anchors: expr) => {
{
let dumb_scalar = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap();
let dumb_point = PublicKey::from_secret_key(&$secp_ctx, &dumb_scalar);
let hash = PaymentHash([1; 32]);
let preimage = PaymentPreimage([2;32]);
let htlc = HTLCOutputInCommitment { offered: false, amount_msat: $amt, cltv_expiry: 1000, payment_hash: hash, transaction_output_index: None };
- PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(dumb_point, dumb_point, dumb_point, preimage, htlc))
+ PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(dumb_point, dumb_point, dumb_point, preimage, htlc, $opt_anchors))
}
}
}
let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
let secp_ctx = Secp256k1::new();
let revk_outp = dumb_revk_output!(secp_ctx);
- let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0);
+ let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0, false);
let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100);
let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, true, 100);
fn test_package_amounts() {
let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
let secp_ctx = Secp256k1::new();
- let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000);
+ let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, false);
let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
assert_eq!(package.package_amount(), 1000);
{
let revk_outp = dumb_revk_output!(secp_ctx);
let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100);
- for &opt_anchors in [false, true].iter() {
- assert_eq!(package.package_weight(&Script::new(), opt_anchors), weight_sans_output + WEIGHT_REVOKED_OUTPUT as usize);
- }
+ assert_eq!(package.package_weight(&Script::new()), weight_sans_output + WEIGHT_REVOKED_OUTPUT as usize);
}
{
- let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000);
- let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
for &opt_anchors in [false, true].iter() {
- assert_eq!(package.package_weight(&Script::new(), opt_anchors), weight_sans_output + weight_received_htlc(opt_anchors) as usize);
+ let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, opt_anchors);
+ let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
+ assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_received_htlc(opt_anchors) as usize);
}
}
{
- let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000);
- let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
for &opt_anchors in [false, true].iter() {
- assert_eq!(package.package_weight(&Script::new(), opt_anchors), weight_sans_output + weight_offered_htlc(opt_anchors) as usize);
+ let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000, opt_anchors);
+ let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
+ assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_offered_htlc(opt_anchors) as usize);
}
}
}
pub use alloc::string::ToString;
}
-#[cfg(all(feature = "std", test))]
+#[cfg(all(not(feature = "_bench_unstable"), feature = "std", test))]
mod debug_sync;
-#[cfg(all(feature = "backtrace", feature = "std", test))]
+#[cfg(all(not(feature = "_bench_unstable"), feature = "backtrace", feature = "std", test))]
extern crate backtrace;
#[cfg(feature = "std")]
mod sync {
- #[cfg(test)]
+ #[cfg(all(not(feature = "_bench_unstable"), test))]
pub use debug_sync::*;
- #[cfg(not(test))]
+ #[cfg(any(feature = "_bench_unstable", not(test)))]
pub use ::std::sync::{Arc, Mutex, Condvar, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
- #[cfg(not(test))]
+ #[cfg(any(feature = "_bench_unstable", not(test)))]
pub use crate::util::fairrwlock::FairRwLock;
}
use util::crypto::sign;
pub(crate) const MAX_HTLCS: u16 = 483;
+pub(crate) const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133;
+pub(crate) const OFFERED_HTLC_SCRIPT_WEIGHT_ANCHORS: usize = 136;
+// The weight of `accepted_htlc_script` can vary in function of its CLTV argument value. We define a
+// range that encompasses both its non-anchors and anchors variants.
+pub(crate) const MIN_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 136;
+pub(crate) const MAX_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 143;
/// Gets the weight for an HTLC-Success transaction.
#[inline]
if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT }
}
-#[derive(PartialEq)]
-pub(crate) enum HTLCType {
- AcceptedHTLC,
- OfferedHTLC
+#[derive(PartialEq, Eq)]
+pub(crate) enum HTLCClaim {
+ OfferedTimeout,
+ OfferedPreimage,
+ AcceptedTimeout,
+ AcceptedPreimage,
+ Revocation,
}
-impl HTLCType {
- /// Check if a given tx witnessScript len matchs one of a pre-signed HTLC
- pub(crate) fn scriptlen_to_htlctype(witness_script_len: usize) -> Option<HTLCType> {
- if witness_script_len == 133 {
- Some(HTLCType::OfferedHTLC)
- } else if witness_script_len >= 136 && witness_script_len <= 139 {
- Some(HTLCType::AcceptedHTLC)
+impl HTLCClaim {
+ /// Check if a given input witness attempts to claim a HTLC.
+ pub(crate) fn from_witness(witness: &Witness) -> Option<Self> {
+ debug_assert_eq!(OFFERED_HTLC_SCRIPT_WEIGHT_ANCHORS, MIN_ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ if witness.len() < 2 {
+ return None;
+ }
+ let witness_script = witness.last().unwrap();
+ let second_to_last = witness.second_to_last().unwrap();
+ if witness_script.len() == OFFERED_HTLC_SCRIPT_WEIGHT {
+ if witness.len() == 3 && second_to_last.len() == 33 {
+ // <revocation sig> <revocationpubkey> <witness_script>
+ Some(Self::Revocation)
+ } else if witness.len() == 3 && second_to_last.len() == 32 {
+ // <remotehtlcsig> <payment_preimage> <witness_script>
+ Some(Self::OfferedPreimage)
+ } else if witness.len() == 5 && second_to_last.len() == 0 {
+ // 0 <remotehtlcsig> <localhtlcsig> <> <witness_script>
+ Some(Self::OfferedTimeout)
+ } else {
+ None
+ }
+ } else if witness_script.len() == OFFERED_HTLC_SCRIPT_WEIGHT_ANCHORS {
+ // It's possible for the weight of `offered_htlc_script` and `accepted_htlc_script` to
+ // match so we check for both here.
+ if witness.len() == 3 && second_to_last.len() == 33 {
+ // <revocation sig> <revocationpubkey> <witness_script>
+ Some(Self::Revocation)
+ } else if witness.len() == 3 && second_to_last.len() == 32 {
+ // <remotehtlcsig> <payment_preimage> <witness_script>
+ Some(Self::OfferedPreimage)
+ } else if witness.len() == 5 && second_to_last.len() == 0 {
+ // 0 <remotehtlcsig> <localhtlcsig> <> <witness_script>
+ Some(Self::OfferedTimeout)
+ } else if witness.len() == 3 && second_to_last.len() == 0 {
+ // <remotehtlcsig> <> <witness_script>
+ Some(Self::AcceptedTimeout)
+ } else if witness.len() == 5 && second_to_last.len() == 32 {
+ // 0 <remotehtlcsig> <localhtlcsig> <payment_preimage> <witness_script>
+ Some(Self::AcceptedPreimage)
+ } else {
+ None
+ }
+ } else if witness_script.len() > MIN_ACCEPTED_HTLC_SCRIPT_WEIGHT &&
+ witness_script.len() <= MAX_ACCEPTED_HTLC_SCRIPT_WEIGHT {
+ // Handle remaining range of ACCEPTED_HTLC_SCRIPT_WEIGHT.
+ if witness.len() == 3 && second_to_last.len() == 33 {
+ // <revocation sig> <revocationpubkey> <witness_script>
+ Some(Self::Revocation)
+ } else if witness.len() == 3 && second_to_last.len() == 0 {
+ // <remotehtlcsig> <> <witness_script>
+ Some(Self::AcceptedTimeout)
+ } else if witness.len() == 5 && second_to_last.len() == 32 {
+ // 0 <remotehtlcsig> <localhtlcsig> <payment_preimage> <witness_script>
+ Some(Self::AcceptedPreimage)
+ } else {
+ None
+ }
} else {
None
}
old_secrets: [([u8; 32], u64); 49],
}
+impl Eq for CounterpartyCommitmentSecrets {}
impl PartialEq for CounterpartyCommitmentSecrets {
fn eq(&self, other: &Self) -> bool {
for (&(ref secret, ref idx), &(ref o_secret, ref o_idx)) in self.old_secrets.iter().zip(other.old_secrets.iter()) {
/// Derives a per-commitment-transaction revocation key from its constituent parts.
///
-/// Only the cheating participant owns a valid witness to propagate a revoked
+/// Only the cheating participant owns a valid witness to propagate a revoked
/// commitment transaction, thus per_commitment_secret always come from cheater
/// and revocation_base_secret always come from punisher, which is the broadcaster
/// of the transaction spending with this key knowledge.
/// the public equivalend of derive_private_revocation_key - using only public keys to derive a
/// public key instead of private keys.
///
-/// Only the cheating participant owns a valid witness to propagate a revoked
+/// Only the cheating participant owns a valid witness to propagate a revoked
/// commitment transaction, thus per_commitment_point always come from cheater
/// and revocation_base_point always come from punisher, which is the broadcaster
/// of the transaction spending with this key knowledge.
/// channel basepoints via the new function, or they were obtained via
/// CommitmentTransaction.trust().keys() because we trusted the source of the
/// pre-calculated keys.
-#[derive(PartialEq, Clone)]
+#[derive(PartialEq, Eq, Clone)]
pub struct TxCreationKeys {
/// The broadcaster's per-commitment public key which was used to derive the other keys.
pub per_commitment_point: PublicKey,
});
/// One counterparty's public keys which do not change over the life of a channel.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub struct ChannelPublicKeys {
/// The public key which is used to sign all commitment transactions, as it appears in the
/// on-chain channel lock-in 2-of-2 multisig output.
res
}
-#[derive(Clone, PartialEq)]
/// Information about an HTLC as it appears in a commitment transaction
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HTLCOutputInCommitment {
/// Whether the HTLC was "offered" (ie outbound in relation to this commitment transaction).
/// Note that this is not the same as whether it is ountbound *from us*. To determine that you
} else {
htlc_success_tx_weight(opt_anchors)
};
- let total_fee = feerate_per_kw as u64 * weight / 1000;
+ let output_value = if opt_anchors {
+ htlc.amount_msat / 1000
+ } else {
+ let total_fee = feerate_per_kw as u64 * weight / 1000;
+ htlc.amount_msat / 1000 - total_fee
+ };
let mut txouts: Vec<TxOut> = Vec::new();
txouts.push(TxOut {
script_pubkey: get_revokeable_redeemscript(revocation_key, contest_delay, broadcaster_delayed_payment_key).to_v0_p2wsh(),
- value: htlc.amount_msat / 1000 - total_fee //TODO: BOLT 3 does not specify if we should add amount_msat before dividing or if we should divide by 1000 before subtracting (as we do here)
+ value: output_value,
});
Transaction {
.into_script()
}
+#[cfg(anchors)]
+/// Locates the output with an anchor script paying to `funding_pubkey` within `commitment_tx`.
+pub(crate) fn get_anchor_output<'a>(commitment_tx: &'a Transaction, funding_pubkey: &PublicKey) -> Option<(u32, &'a TxOut)> {
+ let anchor_script = chan_utils::get_anchor_redeemscript(funding_pubkey).to_v0_p2wsh();
+ commitment_tx.output.iter().enumerate()
+ .find(|(_, txout)| txout.script_pubkey == anchor_script)
+ .map(|(idx, txout)| (idx as u32, txout))
+}
+
+/// Returns the witness required to satisfy and spend an anchor input.
+pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signature) -> Witness {
+ let anchor_redeem_script = chan_utils::get_anchor_redeemscript(funding_key);
+ let mut funding_sig = funding_sig.serialize_der().to_vec();
+ funding_sig.push(EcdsaSighashType::All as u8);
+ Witness::from_vec(vec![funding_sig, anchor_redeem_script.to_bytes()])
+}
+
/// Per-channel data used to build transactions in conjunction with the per-commitment data (CommitmentTransaction).
/// The fields are organized by holder/counterparty.
///
pub counterparty_parameters: Option<CounterpartyChannelTransactionParameters>,
/// The late-bound funding outpoint
pub funding_outpoint: Option<chain::transaction::OutPoint>,
- /// Are anchors used for this channel. Boolean is serialization backwards-compatible
+ /// Are anchors (zero fee HTLC transaction variant) used for this channel. Boolean is
+ /// serialization backwards-compatible.
pub opt_anchors: Option<()>
}
fn deref(&self) -> &Self::Target { &self.inner }
}
+impl Eq for HolderCommitmentTransaction {}
impl PartialEq for HolderCommitmentTransaction {
// We dont care whether we are signed in equality comparison
fn eq(&self, o: &Self) -> bool {
///
/// This class can be used inside a signer implementation to generate a signature given the relevant
/// secret key.
-#[derive(Clone, Hash, PartialEq)]
+#[derive(Clone, Hash, PartialEq, Eq)]
pub struct ClosingTransaction {
to_holder_value_sat: u64,
to_counterparty_value_sat: u64,
built: BuiltCommitmentTransaction,
}
+impl Eq for CommitmentTransaction {}
impl PartialEq for CommitmentTransaction {
fn eq(&self, o: &Self) -> bool {
let eq = self.commitment_number == o.commitment_number &&
// You may not use this file except in accordance with one or both of these
// licenses.
-//! Functional tests which test the correct handling of ChannelMonitorUpdateErr returns from
+//! Functional tests which test the correct handling of ChannelMonitorUpdateStatus returns from
//! monitor updates.
//! There are a bunch of these as their handling is relatively error-prone so they are split out
//! here. See also the chanmon_fail_consistency fuzz test.
use bitcoin::network::constants::Network;
use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor};
use chain::transaction::OutPoint;
-use chain::{ChannelMonitorUpdateErr, Listen, Watch};
-use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure};
+use chain::{ChannelMonitorUpdateStatus, Listen, Watch};
+use ln::channelmanager::{self, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure};
use ln::channel::AnnouncementSigsState;
-use ln::features::InitFeatures;
use ln::msgs;
use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler};
use util::config::UserConfig;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, payment_hash_1, _, payment_secret_1) = get_route_and_payment_hash!(&nodes[0], nodes[1], 1000000);
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::PermanentFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::PermanentFailure);
unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash_1, &Some(payment_secret_1)), true, APIError::ChannelUnavailable {..}, {});
check_added_monitors!(nodes[0], 2);
_ => panic!("Unexpected event"),
};
+ assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
+
// TODO: Once we hit the chain with the failure transaction we should check that we get a
// PaymentPathFailed event
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channel
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let outpoint = OutPoint { txid: chan.3.txid(), index: 0 };
// Rebalance the network to generate htlc in the two directions
&mut io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
assert!(new_monitor == *monitor);
let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
- assert!(chain_mon.watch_channel(outpoint, new_monitor).is_ok());
+ assert_eq!(chain_mon.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
chain_mon
};
let header = BlockHeader {
};
chain_mon.chain_monitor.block_connected(&Block { header, txdata: vec![] }, 200);
- // Set the persister's return value to be a TemporaryFailure.
- persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ // Set the persister's return value to be a InProgress.
+ persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
// Try to update ChannelMonitor
nodes[1].node.claim_funds(preimage);
nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]);
if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan.2) {
if let Ok((_, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) {
- // Check that even though the persister is returning a TemporaryFailure,
+ // Check that even though the persister is returning a InProgress,
// because the update is bogus, ultimately the error that's returned
// should be a PermanentFailure.
- if let Err(ChannelMonitorUpdateErr::PermanentFailure) = chain_mon.chain_monitor.update_channel(outpoint, update.clone()) {} else { panic!("Expected monitor error to be permanent"); }
- logger.assert_log_regex("lightning::chain::chainmonitor".to_string(), regex::Regex::new("Failed to persist ChannelMonitor update for channel [0-9a-f]*: TemporaryFailure").unwrap(), 1);
- if let Ok(_) = nodes[0].chain_monitor.update_channel(outpoint, update) {} else { assert!(false); }
+ if let ChannelMonitorUpdateStatus::PermanentFailure = chain_mon.chain_monitor.update_channel(outpoint, update.clone()) {} else { panic!("Expected monitor error to be permanent"); }
+ logger.assert_log_regex("lightning::chain::chainmonitor".to_string(), regex::Regex::new("Persistence of ChannelMonitorUpdate for channel [0-9a-f]* in progress").unwrap(), 1);
+ assert_eq!(nodes[0].chain_monitor.update_channel(outpoint, update), ChannelMonitorUpdateStatus::Completed);
} else { assert!(false); }
} else { assert!(false); };
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (route, payment_hash_1, payment_preimage_1, payment_secret_1) = get_route_and_payment_hash!(&nodes[0], nodes[1], 1000000);
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
{
- unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash_1, &Some(payment_secret_1)), false, APIError::MonitorUpdateFailed, {});
+ unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash_1, &Some(payment_secret_1)), false, APIError::MonitorUpdateInProgress, {});
check_added_monitors!(nodes[0], 1);
}
reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
}
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[0], 0);
// Now set it to failed again...
let (route, payment_hash_2, _, payment_secret_2) = get_route_and_payment_hash!(&nodes[0], nodes[1], 1000000);
{
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
- unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash_2, &Some(payment_secret_2)), false, APIError::MonitorUpdateFailed, {});
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+ unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash_2, &Some(payment_secret_2)), false, APIError::MonitorUpdateInProgress, {});
check_added_monitors!(nodes[0], 1);
}
// * First we route a payment, then get a temporary monitor update failure when trying to
// route a second payment. We then claim the first payment.
// * If disconnect_count is set, we will disconnect at this point (which is likely as
- // TemporaryFailure likely indicates net disconnect which resulted in failing to update
- // the ChannelMonitor on a watchtower).
+ // InProgress likely indicates net disconnect which resulted in failing to update the
+ // ChannelMonitor on a watchtower).
// * If !(disconnect_count & 16) we deliver a update_fulfill_htlc/CS for the first payment
// immediately, otherwise we wait disconnect and deliver them via the reconnect
// channel_reestablish processing (ie disconnect_count & 16 makes no sense if
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
// Now try to send a second payment which will fail to send
let (route, payment_hash_2, payment_preimage_2, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
{
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
- unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash_2, &Some(payment_secret_2)), false, APIError::MonitorUpdateFailed, {});
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+ unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash_2, &Some(payment_secret_2)), false, APIError::MonitorUpdateInProgress, {});
check_added_monitors!(nodes[0], 1);
}
}
// Now fix monitor updating...
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[0], 0);
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (route, our_payment_hash, payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
{
let send_event = SendEvent::from_event(nodes[0].node.get_and_clear_pending_msg_events().remove(0));
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &send_event.commitment_msg);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Failed to update ChannelMonitor".to_string(), 1);
check_added_monitors!(nodes[1], 1);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
assert!(updates.update_fee.is_none());
assert_eq!(*node_id, nodes[0].node.get_our_node_id());
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &updates.commitment_signed);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
nodes[0].logger.assert_log("lightning::ln::channelmanager".to_string(), "Failed to update ChannelMonitor".to_string(), 1);
_ => panic!("Unexpected event"),
}
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[0], 0);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (route, our_payment_hash, payment_preimage_1, payment_secret_1) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
{
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
let bs_raa = commitment_signed_dance!(nodes[1], nodes[0], send_event.commitment_msg, false, true, false, true);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &bs_raa);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Failed to update ChannelMonitor".to_string(), 1);
assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
check_added_monitors!(nodes[1], 1);
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
send_payment(&nodes[0], &[&nodes[1]], 5000000);
let (route, our_payment_hash_1, payment_preimage_1, our_payment_secret_1) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
check_added_monitors!(nodes[1], 1);
let bs_raa = get_event_msg!(nodes[1], MessageSendEvent::SendRevokeAndACK, nodes[0].node.get_our_node_id());
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[0].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &send_event_2.msgs[0]);
nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &send_event_2.commitment_msg);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_raa);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
- nodes[0].logger.assert_log("lightning::ln::channelmanager".to_string(), "Previous monitor update failure prevented responses to RAA".to_string(), 1);
+ nodes[0].logger.assert_log("lightning::ln::channelmanager".to_string(), "Existing pending monitor update prevented responses to RAA".to_string(), 1);
check_added_monitors!(nodes[0], 1);
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[0], 0);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance a bit so that we can send backwards from 2 to 1.
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
// Now fail monitor updating.
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.handle_revoke_and_ack(&nodes[2].node.get_our_node_id(), &bs_revoke_and_ack);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Failed to update ChannelMonitor".to_string(), 1);
check_added_monitors!(nodes[0], 1);
}
- chanmon_cfgs[1].persister.set_update_ret(Ok(())); // We succeed in updating the monitor for the first channel
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed); // We succeed in updating the monitor for the first channel
send_event = SendEvent::from_event(nodes[0].node.get_and_clear_pending_msg_events().remove(0));
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], send_event.commitment_msg, false, true);
// Restore monitor updating, ensuring we immediately get a fail-back update and a
// update_add update.
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_2.2).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let as_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
assert_eq!(get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap(), as_reestablish);
assert_eq!(get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap(), bs_reestablish);
get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id())
.contents.flags & 2, 0); // The "disabled" bit should be unset as we just reconnected
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_1.2).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (route, payment_hash_1, payment_preimage_1, payment_secret_1) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
let (payment_preimage_2, payment_hash_2, payment_secret_2) = get_payment_preimage_hash!(nodes[1]);
// Now we have a CS queued up which adds a new HTLC (which will need a RAA/CS response from
// nodes[1]) followed by an RAA. Fail the monitor updating prior to the CS, deliver the RAA,
// then restore channel monitor updates.
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &payment_event.commitment_msg);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &as_raa);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
- nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Previous monitor update failure prevented responses to RAA".to_string(), 1);
+ nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Existing pending monitor update prevented responses to RAA".to_string(), 1);
check_added_monitors!(nodes[1], 1);
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
// nodes[1] should be AwaitingRAA here!
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
// Forward a payment for B to claim
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
check_added_monitors!(nodes[1], 1);
expect_payment_claimed!(nodes[1], payment_hash_1, 1_000_000);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let as_reconnect = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
let bs_reconnect = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
// Now deliver a's reestablish, freeing the claim from the holding cell, but fail the monitor
// update.
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_reconnect);
let _bs_channel_update = get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
// Now un-fail the monitor, which will result in B sending its original commitment update,
// receiving the commitment update from A, and the resulting commitment dances.
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
{
let mut lock;
get_channel_ref!(nodes[0], lock, channel_id).announcement_sigs_state = AnnouncementSigsState::PeerReceived;
check_added_monitors!(nodes[0], 1);
}
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let payment_event = SendEvent::from_event(events.pop().unwrap());
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let as_reconnect = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
let bs_reconnect = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reconnect);
let _as_channel_update = get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
// Route the first payment outbound, holding the last RAA for B until we are set up so that we
// can deliver it and fail the monitor update.
let payment_event = SendEvent::from_event(events.pop().unwrap());
assert_eq!(payment_event.node_id, nodes[1].node.get_our_node_id());
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
// Deliver the final RAA for the first payment, which does not require a response. RAAs
// generally require a commitment_signed, so the fact that we're expecting an opposite response
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Previous monitor update failure prevented generation of RAA".to_string(), 1);
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance a bit so that we can send backwards from 3 to 2.
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000);
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.claim_funds(payment_preimage_1);
expect_payment_claimed!(nodes[1], payment_hash_1, 1_000_000);
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Temporary failure claiming HTLC, treating as success: Failed to update ChannelMonitor".to_string(), 1);
// Successfully update the monitor on the 1<->2 channel, but the 0<->1 channel should still be
// paused, so forward shouldn't succeed until we call channel_monitor_updated().
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let mut events = nodes[2].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance a bit so that we can send backwards from 3 to 1.
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000);
nodes[1].node.handle_update_add_htlc(&nodes[2].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[2], payment_event.commitment_msg, false);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], vec![HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_2.2 }]);
check_added_monitors!(nodes[1], 1);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Failed to update ChannelMonitor".to_string(), 1);
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_1.2).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
// Forward a payment for B to claim
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
let as_raa = commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false, true, false, true);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.claim_funds(payment_preimage_1);
expect_payment_claimed!(nodes[1], payment_hash_1, 1_000_000);
check_added_monitors!(nodes[1], 1);
assert_eq!(events.len(), 0);
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Temporary failure claiming HTLC, treating as success: Failed to update ChannelMonitor".to_string(), 1);
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 43, None).unwrap();
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
let (temporary_channel_id, funding_tx, funding_output) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 43);
nodes[0].node.funding_transaction_generated(&temporary_channel_id, &nodes[1].node.get_our_node_id(), funding_tx.clone()).unwrap();
check_added_monitors!(nodes[0], 0);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
let funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
let channel_id = OutPoint { txid: funding_created_msg.funding_txid, index: funding_created_msg.funding_output_index }.to_channel_id();
nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msg);
check_added_monitors!(nodes[1], 1);
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id()));
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
nodes[0].logger.assert_log("lightning::ln::channelmanager".to_string(), "Failed to update ChannelMonitor".to_string(), 1);
check_added_monitors!(nodes[0], 1);
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[0], 0);
assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
}
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
check_added_monitors!(nodes[1], 0);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let (chan_2_ann, _, chan_2_id, _) = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known());
- let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let (chan_2_ann, _, chan_2_id, _) = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[3], 100000);
// Set it so that the first monitor update (for the path 0 -> 1 -> 3) succeeds, but the second
// (for the path 0 -> 2 -> 3) fails.
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
- chanmon_cfgs[0].persister.set_next_update_ret(Some(Err(ChannelMonitorUpdateErr::TemporaryFailure)));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
+ chanmon_cfgs[0].persister.set_next_update_ret(Some(ChannelMonitorUpdateStatus::InProgress));
// Now check that we get the right return value, indicating that the first path succeeded but
- // the second got a MonitorUpdateFailed err. This implies PaymentSendFailure::PartialFailure as
- // some paths succeeded, preventing retry.
+ // the second got a MonitorUpdateInProgress err. This implies
+ // PaymentSendFailure::PartialFailure as some paths succeeded, preventing retry.
if let Err(PaymentSendFailure::PartialFailure { results, ..}) = nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)) {
assert_eq!(results.len(), 2);
if let Ok(()) = results[0] {} else { panic!(); }
- if let Err(APIError::MonitorUpdateFailed) = results[1] {} else { panic!(); }
+ if let Err(APIError::MonitorUpdateInProgress) = results[1] {} else { panic!(); }
} else { panic!(); }
check_added_monitors!(nodes[0], 2);
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
// Pass the first HTLC of the payment along to nodes[3].
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
send_payment(&nodes[0], &[&nodes[1]], 100_000_00);
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(&nodes[1], nodes[0], 1_000_000);
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let as_connect_msg = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let bs_connect_msg = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_connect_msg);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known()).2;
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 2000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
send_payment(&nodes[0], &[&nodes[1]], 1000);
{
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let as_connect_msg = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let bs_connect_msg = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_connect_msg);
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_id = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 15_000_000, 7_000_000_000, InitFeatures::known(), InitFeatures::known()).2;
+ let chan_id = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 15_000_000, 7_000_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (route, payment_hash_1, payment_preimage_1, payment_secret_1) = get_route_and_payment_hash!(&nodes[0], nodes[1], 100000);
let (payment_preimage_2, payment_hash_2, payment_secret_2) = get_payment_preimage_hash!(&nodes[1]);
nodes[0].node.send_payment(&route, payment_hash_2, &Some(payment_secret_2)).unwrap();
check_added_monitors!(nodes[0], 0);
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[0].node.claim_funds(payment_preimage_0);
check_added_monitors!(nodes[0], 1);
expect_payment_claimed!(nodes[0], payment_hash_0, 100_000);
nodes[0].node = &nodes_0_deserialized;
assert!(nodes_0_read.is_empty());
- nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0.clone(), chan_0_monitor).unwrap();
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0.clone(), chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
check_added_monitors!(nodes[0], 1);
} else {
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
// Now reconnect the two
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
// If we finish updating the monitor, we should free the holding cell right away (this did
// not occur prior to #756).
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (funding_txo, mon_id, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_id).unwrap().clone();
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(funding_txo, mon_id);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known()).2;
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 100_000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), Some(config)]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let (_, _, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let (_, _, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[0].node.close_channel(&channel_id, &nodes[1].node.get_our_node_id()).unwrap();
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()));
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()));
check_added_monitors!(nodes[1], 1);
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()));
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()));
check_added_monitors!(nodes[0], 1);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, latest_update, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::PermanentFailure));
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::PermanentFailure);
assert!(nodes[0].node.close_channel(&channel_id, &nodes[1].node.get_our_node_id()).is_ok());
check_closed_broadcast!(nodes[0], true);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(config)]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::PermanentFailure));
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::PermanentFailure);
assert!(nodes[0].node.close_channel(&channel_id, &nodes[1].node.get_our_node_id()).is_ok());
let shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &shutdown);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 2);
check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: "ChannelMonitor storage failure".to_string() });
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let (_, _, channel_id, _) = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let (_, _, channel_id, _) = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
let (payment_preimage_2, payment_hash_2, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
// `claim_funds` results in a ChannelMonitorUpdate.
nodes[1].node.claim_funds(payment_preimage_1);
check_added_monitors!(nodes[1], 1);
expect_payment_claimed!(nodes[1], payment_hash_1, 1_000_000);
let (funding_tx, latest_update_1, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
// Previously, this would've panicked due to a double-call to `Channel::monitor_update_failed`,
// which had some asserts that prevented it from being called twice.
nodes[1].node.claim_funds(payment_preimage_2);
check_added_monitors!(nodes[1], 1);
expect_payment_claimed!(nodes[1], payment_hash_2, 1_000_000);
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (_, latest_update_2, _) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.force_channel_monitor_updated(funding_tx, latest_update_1);
use bitcoin::secp256k1;
use ln::{PaymentPreimage, PaymentHash};
-use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures};
+use ln::features::{ChannelTypeFeatures, InitFeatures};
use ln::msgs;
use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
use ln::script::{self, ShutdownScript};
-use ln::channelmanager::{CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
+use ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
use ln::chan_utils;
use chain::BestBlock;
($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => {
if $outbound == local { // "offered HTLC output"
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + (feerate_per_kw as u64 * htlc_timeout_tx_weight(self.opt_anchors()) / 1000) {
+ let htlc_tx_fee = if self.opt_anchors() {
+ 0
+ } else {
+ feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000
+ };
+ if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
included_non_dust_htlcs.push((htlc_in_tx, $source));
} else {
}
} else {
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + (feerate_per_kw as u64 * htlc_success_tx_weight(self.opt_anchors()) / 1000) {
+ let htlc_tx_fee = if self.opt_anchors() {
+ 0
+ } else {
+ feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000
+ };
+ if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
included_non_dust_htlcs.push((htlc_in_tx, $source));
} else {
on_holder_tx_holding_cell_htlcs_count: 0,
};
- let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * htlc_timeout_tx_weight(self.opt_anchors()) / 1000) + self.counterparty_dust_limit_satoshis;
- let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * htlc_success_tx_weight(self.opt_anchors()) / 1000) + self.holder_dust_limit_satoshis;
+ let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.opt_anchors() {
+ (0, 0)
+ } else {
+ let dust_buffer_feerate = self.get_dust_buffer_feerate(outbound_feerate_update) as u64;
+ (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000,
+ dust_buffer_feerate * htlc_success_tx_weight(false) / 1000)
+ };
+ let counterparty_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis;
+ let holder_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
for ref htlc in self.pending_inbound_htlcs.iter() {
stats.pending_htlcs_value_msat += htlc.amount_msat;
if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
on_holder_tx_holding_cell_htlcs_count: 0,
};
- let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * htlc_success_tx_weight(self.opt_anchors()) / 1000) + self.counterparty_dust_limit_satoshis;
- let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * htlc_timeout_tx_weight(self.opt_anchors()) / 1000) + self.holder_dust_limit_satoshis;
+ let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.opt_anchors() {
+ (0, 0)
+ } else {
+ let dust_buffer_feerate = self.get_dust_buffer_feerate(outbound_feerate_update) as u64;
+ (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000,
+ dust_buffer_feerate * htlc_success_tx_weight(false) / 1000)
+ };
+ let counterparty_dust_limit_success_sat = htlc_success_dust_limit + self.counterparty_dust_limit_satoshis;
+ let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
for ref htlc in self.pending_outbound_htlcs.iter() {
stats.pending_htlcs_value_msat += htlc.amount_msat;
if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat {
fn next_local_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 {
assert!(self.is_outbound());
- let real_dust_limit_success_sat = (self.feerate_per_kw as u64 * htlc_success_tx_weight(self.opt_anchors()) / 1000) + self.holder_dust_limit_satoshis;
- let real_dust_limit_timeout_sat = (self.feerate_per_kw as u64 * htlc_timeout_tx_weight(self.opt_anchors()) / 1000) + self.holder_dust_limit_satoshis;
+ let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.opt_anchors() {
+ (0, 0)
+ } else {
+ (self.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000,
+ self.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000)
+ };
+ let real_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
+ let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
let mut addl_htlcs = 0;
if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
fn next_remote_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 {
assert!(!self.is_outbound());
- let real_dust_limit_success_sat = (self.feerate_per_kw as u64 * htlc_success_tx_weight(self.opt_anchors()) / 1000) + self.counterparty_dust_limit_satoshis;
- let real_dust_limit_timeout_sat = (self.feerate_per_kw as u64 * htlc_timeout_tx_weight(self.opt_anchors()) / 1000) + self.counterparty_dust_limit_satoshis;
+ let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.opt_anchors() {
+ (0, 0)
+ } else {
+ (self.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000,
+ self.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000)
+ };
+ let real_dust_limit_success_sat = htlc_success_dust_limit + self.counterparty_dust_limit_satoshis;
+ let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis;
let mut addl_htlcs = 0;
if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
}
}
- let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * htlc_timeout_tx_weight(self.opt_anchors()) / 1000) + self.counterparty_dust_limit_satoshis;
+ let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.opt_anchors() {
+ (0, 0)
+ } else {
+ let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
+ (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000,
+ dust_buffer_feerate * htlc_success_tx_weight(false) / 1000)
+ };
+ let exposure_dust_limit_timeout_sats = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis;
if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat;
if on_counterparty_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
}
}
- let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * htlc_success_tx_weight(self.opt_anchors()) / 1000) + self.holder_dust_limit_satoshis;
+ let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat;
if on_holder_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
return;
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == (ChannelState::PeerDisconnected as u32) {
+ // While the below code should be idempotent, it's simpler to just return early, as
+ // redundant disconnect events can fire, though they should be rare.
+ return;
+ }
+
if self.announcement_sigs_state == AnnouncementSigsState::MessageSent || self.announcement_sigs_state == AnnouncementSigsState::Committed {
self.announcement_sigs_state = AnnouncementSigsState::NotSent;
}
log_trace!(logger, "Peer disconnection resulted in {} remote-announced HTLC drops on channel {}", inbound_drop_count, log_bytes!(self.channel_id()));
}
- /// Indicates that a ChannelMonitor update failed to be stored by the client and further
- /// updates are partially paused.
- /// This must be called immediately after the call which generated the ChannelMonitor update
- /// which failed. The messages which were generated from that call which generated the
- /// monitor update failure must *not* have been sent to the remote end, and must instead
- /// have been dropped. They will be regenerated when monitor_updating_restored is called.
- pub fn monitor_update_failed(&mut self, resend_raa: bool, resend_commitment: bool,
+ /// Indicates that a ChannelMonitor update is in progress and has not yet been fully persisted.
+ /// This must be called immediately after the [`chain::Watch`] call which returned
+ /// [`ChannelMonitorUpdateStatus::InProgress`].
+ /// The messages which were generated with the monitor update must *not* have been sent to the
+ /// remote end, and must instead have been dropped. They will be regenerated when
+ /// [`Self::monitor_updating_restored`] is called.
+ ///
+ /// [`chain::Watch`]: crate::chain::Watch
+ /// [`ChannelMonitorUpdateStatus::InProgress`]: crate::chain::ChannelMonitorUpdateStatus::InProgress
+ pub fn monitor_updating_paused(&mut self, resend_raa: bool, resend_commitment: bool,
resend_channel_ready: bool, mut pending_forwards: Vec<(PendingHTLCInfo, u64)>,
mut pending_fails: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
mut pending_finalized_claimed_htlcs: Vec<HTLCSource>
let were_node_one = node_id.serialize()[..] < self.counterparty_node_id.serialize()[..];
let msg = msgs::UnsignedChannelAnnouncement {
- features: ChannelFeatures::known(),
+ features: channelmanager::provided_channel_features(),
chain_hash,
short_channel_id: self.get_short_channel_id().unwrap(),
node_id_1: if were_node_one { node_id } else { self.get_counterparty_node_id() },
}
}
- let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * htlc_success_tx_weight(self.opt_anchors()) / 1000) + self.counterparty_dust_limit_satoshis;
+ let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.opt_anchors() {
+ (0, 0)
+ } else {
+ let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
+ (dust_buffer_feerate * htlc_success_tx_weight(false) / 1000,
+ dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000)
+ };
+ let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.counterparty_dust_limit_satoshis;
if amount_msat / 1000 < exposure_dust_limit_success_sats {
let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + amount_msat;
if on_counterparty_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
}
}
- let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * htlc_timeout_tx_weight(self.opt_anchors()) / 1000) + self.holder_dust_limit_satoshis;
+ let exposure_dust_limit_timeout_sats = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
if amount_msat / 1000 < exposure_dust_limit_timeout_sats {
let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + amount_msat;
if on_holder_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
use bitcoin::network::constants::Network;
use hex;
use ln::PaymentHash;
- use ln::channelmanager::{HTLCSource, PaymentId};
+ use ln::channelmanager::{self, HTLCSource, PaymentId};
use ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator};
use ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
- use ln::features::{InitFeatures, ChannelTypeFeatures};
+ use ln::features::ChannelTypeFeatures;
use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate, MAX_VALUE_MSAT};
use ln::script::ShutdownScript;
use ln::chan_utils;
#[test]
fn upfront_shutdown_script_incompatibility() {
- let features = InitFeatures::known().clear_shutdown_anysegwit();
+ let features = channelmanager::provided_init_features().clear_shutdown_anysegwit();
let non_v0_segwit_shutdown_script =
ShutdownScript::new_witness_program(WitnessVersion::V16, &[0, 40]).unwrap();
let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&bounded_fee_estimator, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
+ let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&bounded_fee_estimator, &&keys_provider, node_a_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config, 0, 42).unwrap();
// Now change the fee so we can check that the fee in the open_channel message is the
// same as the old fee.
// Create Node A's channel pointing to Node B's pubkey
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
+ let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config, 0, 42).unwrap();
// Create Node B's channel by receiving Node A's open_channel message
// Make sure A's dust limit is as we expect.
let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash());
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
- let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42).unwrap();
+ let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(), &open_channel_msg, 7, &config, 0, &&logger, 42).unwrap();
// Node B --> Node A: accept channel, explicitly setting B's dust limit.
let mut accept_channel_msg = node_b_chan.accept_inbound_channel(0);
accept_channel_msg.dust_limit_satoshis = 546;
- node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap();
+ node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &channelmanager::provided_init_features()).unwrap();
node_a_chan.holder_dust_limit_satoshis = 1560;
// Put some inbound and outbound HTLCs in A's channel.
let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut chan = Channel::<EnforcingSigner>::new_outbound(&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
+ let mut chan = Channel::<EnforcingSigner>::new_outbound(&fee_est, &&keys_provider, node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config, 0, 42).unwrap();
let commitment_tx_fee_0_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 0, chan.opt_anchors());
let commitment_tx_fee_1_htlc = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 1, chan.opt_anchors());
// Create Node A's channel pointing to Node B's pubkey
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
+ let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config, 0, 42).unwrap();
// Create Node B's channel by receiving Node A's open_channel message
let open_channel_msg = node_a_chan.get_open_channel(chain_hash);
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
- let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42).unwrap();
+ let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(), &open_channel_msg, 7, &config, 0, &&logger, 42).unwrap();
// Node B --> Node A: accept channel
let accept_channel_msg = node_b_chan.accept_inbound_channel(0);
- node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap();
+ node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &channelmanager::provided_init_features()).unwrap();
// Node A --> Node B: funding created
let output_script = node_a_chan.get_funding_redeemscript();
// Test that `new_outbound` creates a channel with the correct value for
// `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value,
// which is set to the lower bound + 1 (2%) of the `channel_value`.
- let chan_1 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_2_percent, 0, 42).unwrap();
+ let chan_1 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config_2_percent, 0, 42).unwrap();
let chan_1_value_msat = chan_1.channel_value_satoshis * 1000;
assert_eq!(chan_1.holder_max_htlc_value_in_flight_msat, (chan_1_value_msat as f64 * 0.02) as u64);
// Test with the upper bound - 1 of valid values (99%).
- let chan_2 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_99_percent, 0, 42).unwrap();
+ let chan_2 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config_99_percent, 0, 42).unwrap();
let chan_2_value_msat = chan_2.channel_value_satoshis * 1000;
assert_eq!(chan_2.holder_max_htlc_value_in_flight_msat, (chan_2_value_msat as f64 * 0.99) as u64);
// Test that `new_from_req` creates a channel with the correct value for
// `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value,
// which is set to the lower bound - 1 (2%) of the `channel_value`.
- let chan_3 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_2_percent, 0, &&logger, 42).unwrap();
+ let chan_3 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &channelmanager::provided_init_features(), &chan_1_open_channel_msg, 7, &config_2_percent, 0, &&logger, 42).unwrap();
let chan_3_value_msat = chan_3.channel_value_satoshis * 1000;
assert_eq!(chan_3.holder_max_htlc_value_in_flight_msat, (chan_3_value_msat as f64 * 0.02) as u64);
// Test with the upper bound - 1 of valid values (99%).
- let chan_4 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_99_percent, 0, &&logger, 42).unwrap();
+ let chan_4 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &channelmanager::provided_init_features(), &chan_1_open_channel_msg, 7, &config_99_percent, 0, &&logger, 42).unwrap();
let chan_4_value_msat = chan_4.channel_value_satoshis * 1000;
assert_eq!(chan_4.holder_max_htlc_value_in_flight_msat, (chan_4_value_msat as f64 * 0.99) as u64);
// Test that `new_outbound` uses the lower bound of the configurable percentage values (1%)
// if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1.
- let chan_5 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_0_percent, 0, 42).unwrap();
+ let chan_5 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config_0_percent, 0, 42).unwrap();
let chan_5_value_msat = chan_5.channel_value_satoshis * 1000;
assert_eq!(chan_5.holder_max_htlc_value_in_flight_msat, (chan_5_value_msat as f64 * 0.01) as u64);
// Test that `new_outbound` uses the upper bound of the configurable percentage values
// (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value
// than 100.
- let chan_6 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_101_percent, 0, 42).unwrap();
+ let chan_6 = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config_101_percent, 0, 42).unwrap();
let chan_6_value_msat = chan_6.channel_value_satoshis * 1000;
assert_eq!(chan_6.holder_max_htlc_value_in_flight_msat, chan_6_value_msat);
// Test that `new_from_req` uses the lower bound of the configurable percentage values (1%)
// if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1.
- let chan_7 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_0_percent, 0, &&logger, 42).unwrap();
+ let chan_7 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &channelmanager::provided_init_features(), &chan_1_open_channel_msg, 7, &config_0_percent, 0, &&logger, 42).unwrap();
let chan_7_value_msat = chan_7.channel_value_satoshis * 1000;
assert_eq!(chan_7.holder_max_htlc_value_in_flight_msat, (chan_7_value_msat as f64 * 0.01) as u64);
// Test that `new_from_req` uses the upper bound of the configurable percentage values
// (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value
// than 100.
- let chan_8 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_101_percent, 0, &&logger, 42).unwrap();
+ let chan_8 = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider, inbound_node_id, &channelmanager::provided_init_features(), &chan_1_open_channel_msg, 7, &config_101_percent, 0, &&logger, 42).unwrap();
let chan_8_value_msat = chan_8.channel_value_satoshis * 1000;
assert_eq!(chan_8.holder_max_htlc_value_in_flight_msat, chan_8_value_msat);
}
let mut outbound_node_config = UserConfig::default();
outbound_node_config.channel_handshake_config.their_channel_reserve_proportional_millionths = (outbound_selected_channel_reserve_perc * 1_000_000.0) as u32;
- let chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, outbound_node_id, &InitFeatures::known(), channel_value_satoshis, 100_000, 42, &outbound_node_config, 0, 42).unwrap();
+ let chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(), channel_value_satoshis, 100_000, 42, &outbound_node_config, 0, 42).unwrap();
let expected_outbound_selected_chan_reserve = cmp::max(MIN_THEIR_CHAN_RESERVE_SATOSHIS, (chan.channel_value_satoshis as f64 * outbound_selected_channel_reserve_perc) as u64);
assert_eq!(chan.holder_selected_channel_reserve_satoshis, expected_outbound_selected_chan_reserve);
inbound_node_config.channel_handshake_config.their_channel_reserve_proportional_millionths = (inbound_selected_channel_reserve_perc * 1_000_000.0) as u32;
if outbound_selected_channel_reserve_perc + inbound_selected_channel_reserve_perc < 1.0 {
- let chan_inbound_node = Channel::<EnforcingSigner>::new_from_req(&&fee_est, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_open_channel_msg, 7, &inbound_node_config, 0, &&logger, 42).unwrap();
+ let chan_inbound_node = Channel::<EnforcingSigner>::new_from_req(&&fee_est, &&keys_provider, inbound_node_id, &channelmanager::provided_init_features(), &chan_open_channel_msg, 7, &inbound_node_config, 0, &&logger, 42).unwrap();
let expected_inbound_selected_chan_reserve = cmp::max(MIN_THEIR_CHAN_RESERVE_SATOSHIS, (chan.channel_value_satoshis as f64 * inbound_selected_channel_reserve_perc) as u64);
assert_eq!(chan_inbound_node.counterparty_selected_channel_reserve_satoshis.unwrap(), expected_outbound_selected_chan_reserve);
} else {
// Channel Negotiations failed
- let result = Channel::<EnforcingSigner>::new_from_req(&&fee_est, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_open_channel_msg, 7, &inbound_node_config, 0, &&logger, 42);
+ let result = Channel::<EnforcingSigner>::new_from_req(&&fee_est, &&keys_provider, inbound_node_id, &channelmanager::provided_init_features(), &chan_open_channel_msg, 7, &inbound_node_config, 0, &&logger, 42);
assert!(result.is_err());
}
}
// Create a channel.
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
+ let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config, 0, 42).unwrap();
assert!(node_a_chan.counterparty_forwarding_info.is_none());
assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1); // the default
assert!(node_a_chan.counterparty_forwarding_info().is_none());
let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let mut config = UserConfig::default();
config.channel_handshake_config.announced_channel = false;
- let mut chan = Channel::<InMemorySigner>::new_outbound(&LowerBoundedFeeEstimator::new(&feeest), &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0, 42).unwrap(); // Nothing uses their network key in this test
+ let mut chan = Channel::<InMemorySigner>::new_outbound(&LowerBoundedFeeEstimator::new(&feeest), &&keys_provider, counterparty_node_id, &channelmanager::provided_init_features(), 10_000_000, 100000, 42, &config, 0, 42).unwrap(); // Nothing uses their network key in this test
chan.holder_dust_limit_satoshis = 546;
chan.counterparty_selected_channel_reserve_satoshis = Some(0); // Filled in in accept_channel
"020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe04000000000000000001da0d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009acd6a827a76bfee50806178dfe0495cd4e1d9c58279c194c7b01520fe68cb8d022024d439047c368883e570997a7d40f0b430cb5a742f507965e7d3063ae3feccca01473044022048762cf546bbfe474f1536365ea7c416e3c0389d60558bc9412cb148fb6ab68202207215d7083b75c96ff9d2b08c59c34e287b66820f530b486a9aa4cdd9c347d5b9012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with seven outputs untrimmed (maximum feerate)
- chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
- chan.feerate_per_kw = 644;
-
- test_commitment_with_anchors!("3045022100e0106830467a558c07544a3de7715610c1147062e7d091deeebe8b5c661cda9402202ad049c1a6d04834317a78483f723c205c9f638d17222aafc620800cc1b6ae35",
- "3045022100ef82a405364bfc4007e63a7cc82925a513d79065bdbc216d60b6a4223a323f8a02200716730b8561f3c6d362eaf47f202e99fb30d0557b61b92b5f9134f8e2de3681",
- "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80094a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994e80300000000000022002010f88bf09e56f14fb4543fd26e47b0db50ea5de9cf3fc46434792471082621aed0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a4f996a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100ef82a405364bfc4007e63a7cc82925a513d79065bdbc216d60b6a4223a323f8a02200716730b8561f3c6d362eaf47f202e99fb30d0557b61b92b5f9134f8e2de368101483045022100e0106830467a558c07544a3de7715610c1147062e7d091deeebe8b5c661cda9402202ad049c1a6d04834317a78483f723c205c9f638d17222aafc620800cc1b6ae3501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
-
- { 0,
- "304402205912d91c58016f593d9e46fefcdb6f4125055c41a17b03101eaaa034b9028ab60220520d4d239c85c66e4c75c5b413620b62736e227659d7821b308e2b8ced3e728e",
- "30440220473166a5adcca68550bab80403f410a726b5bd855030527e3fefa8c1e4b4fd7b02203b1dc91d8d69039473036cb5c34398b99e8eb90ae500c22130a557b62294b188",
- "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a0200000000010000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402205912d91c58016f593d9e46fefcdb6f4125055c41a17b03101eaaa034b9028ab60220520d4d239c85c66e4c75c5b413620b62736e227659d7821b308e2b8ced3e728e834730440220473166a5adcca68550bab80403f410a726b5bd855030527e3fefa8c1e4b4fd7b02203b1dc91d8d69039473036cb5c34398b99e8eb90ae500c22130a557b62294b188012000000000000000000000000000000000000000000000000000000000000000008d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac6851b2756800000000" },
-
- { 1,
- "3045022100c6b4113678039ee1e43a6cba5e3224ed2355ffc05e365a393afe8843dc9a76860220566d01fd52d65a89ba8595023884f9e8f2e9a310a6b9b85281c0bce06863430c",
- "3045022100d0d86307ea55d5daa80f453ad6d64b78fe8a6504aac25407c73e8502c0702c1602206a0809a02aa00c8dc4a53d976bb05d4605d8bb0b7b26b973a5c4e2734d8afbb4",
- "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a0300000000010000000124060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c6b4113678039ee1e43a6cba5e3224ed2355ffc05e365a393afe8843dc9a76860220566d01fd52d65a89ba8595023884f9e8f2e9a310a6b9b85281c0bce06863430c83483045022100d0d86307ea55d5daa80f453ad6d64b78fe8a6504aac25407c73e8502c0702c1602206a0809a02aa00c8dc4a53d976bb05d4605d8bb0b7b26b973a5c4e2734d8afbb401008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" },
-
- { 2,
- "304402203c3a699fb80a38112aafd73d6e3a9b7d40bc2c3ed8b7fbc182a20f43b215172202204e71821b984d1af52c4b8e2cd4c572578c12a965866130c2345f61e4c2d3fef4",
- "304402205bcfa92f83c69289a412b0b6dd4f2a0fe0b0fc2d45bd74706e963257a09ea24902203783e47883e60b86240e877fcbf33d50b1742f65bc93b3162d1be26583b367ee",
- "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a040000000001000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402203c3a699fb80a38112aafd73d6e3a9b7d40bc2c3ed8b7fbc182a20f43b215172202204e71821b984d1af52c4b8e2cd4c572578c12a965866130c2345f61e4c2d3fef48347304402205bcfa92f83c69289a412b0b6dd4f2a0fe0b0fc2d45bd74706e963257a09ea24902203783e47883e60b86240e877fcbf33d50b1742f65bc93b3162d1be26583b367ee012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" },
-
- { 3,
- "304402200f089bcd20f25475216307d32aa5b6c857419624bfba1da07335f51f6ba4645b02206ce0f7153edfba23b0d4b2afc26bb3157d404368cb8ea0ca7cf78590dcdd28cf",
- "3045022100e4516da08f72c7a4f7b2f37aa84a0feb54ae2cc5b73f0da378e81ae0ca8119bf02207751b2628d8e2f62b4b9abccda4866246c1bfcc82e3d416ad562fd212102c28f",
- "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a050000000001000000010c0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402200f089bcd20f25475216307d32aa5b6c857419624bfba1da07335f51f6ba4645b02206ce0f7153edfba23b0d4b2afc26bb3157d404368cb8ea0ca7cf78590dcdd28cf83483045022100e4516da08f72c7a4f7b2f37aa84a0feb54ae2cc5b73f0da378e81ae0ca8119bf02207751b2628d8e2f62b4b9abccda4866246c1bfcc82e3d416ad562fd212102c28f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
-
- { 4,
- "3045022100aa72cfaf0965020c73a12c77276c6411ca68c4de36ac1998adf86c917a899a43022060da0a159fecfe0bed37c3962d767f12f90e30fed8a8f34b1301775c21a2bd3a",
- "304402203cd12065c2a42963c762e6b1a981e17695616ecb6f9fb33d8b0717cdd7ca0ee4022065500005c491c1dcf2fe9c4024f74b1c90785d572527055a491278f901143904",
- "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a06000000000100000001da0d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100aa72cfaf0965020c73a12c77276c6411ca68c4de36ac1998adf86c917a899a43022060da0a159fecfe0bed37c3962d767f12f90e30fed8a8f34b1301775c21a2bd3a8347304402203cd12065c2a42963c762e6b1a981e17695616ecb6f9fb33d8b0717cdd7ca0ee4022065500005c491c1dcf2fe9c4024f74b1c90785d572527055a491278f901143904012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
- } );
-
// commitment tx with six outputs untrimmed (minimum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 648;
"020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf103000000000000000001d90d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022024cd52e4198c8ae0e414a86d86b5a65ea7450f2eb4e783096736d93395eca5ce022078f0094745b45be4d4b2b04dd5978c9e66ba49109e5704403e84aaf5f387d6be01483045022100bbfb9d0a946d420807c86e985d636cceb16e71c3694ed186316251a00cbd807202207773223f9a337e145f64673825be9b30d07ef1542c82188b264bedcf7cda78c6012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with six outputs untrimmed (minimum feerate)
+ // anchors: commitment tx with six outputs untrimmed (minimum dust limit)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 645;
+ chan.holder_dust_limit_satoshis = 1001;
test_commitment_with_anchors!("3044022025d97466c8049e955a5afce28e322f4b34d2561118e52332fb400f9b908cc0a402205dc6fba3a0d67ee142c428c535580cd1f2ff42e2f89b47e0c8a01847caffc312",
"3045022100d57697c707b6f6d053febf24b98e8989f186eea42e37e9e91663ec2c70bb8f70022079b0715a472118f262f43016a674f59c015d9cafccec885968e76d9d9c5d0051",
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80084a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994abc996a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100d57697c707b6f6d053febf24b98e8989f186eea42e37e9e91663ec2c70bb8f70022079b0715a472118f262f43016a674f59c015d9cafccec885968e76d9d9c5d005101473044022025d97466c8049e955a5afce28e322f4b34d2561118e52332fb400f9b908cc0a402205dc6fba3a0d67ee142c428c535580cd1f2ff42e2f89b47e0c8a01847caffc31201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
{ 0,
- "30440220446f9e5c375db6a61d6eeee8b59219a30a4a37372afc2670a1a2889c78e9b943022061895f6088fb48b490ab2140a4842c277b64bf25ff591625dd0356e0c96ab7a8",
- "3045022100c1621ba26a99c263fd885feff5fda5ca2cc73df080b3a49ecf15164ee244d2a5022037f4cc7fd4441af39a83a0e44c3b1db7d64a4c8080e8697f9e952f85421a34d8",
- "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b28534856132000200000000010000000123060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220446f9e5c375db6a61d6eeee8b59219a30a4a37372afc2670a1a2889c78e9b943022061895f6088fb48b490ab2140a4842c277b64bf25ff591625dd0356e0c96ab7a883483045022100c1621ba26a99c263fd885feff5fda5ca2cc73df080b3a49ecf15164ee244d2a5022037f4cc7fd4441af39a83a0e44c3b1db7d64a4c8080e8697f9e952f85421a34d801008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" },
+ "3045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc282",
+ "3045022100b7c49846466b13b190ff739bbe3005c105482fc55539e55b1c561f76b6982b6c02200e5c35808619cf543c8405cff9fedd25f333a4a2f6f6d5e8af8150090c40ef09",
+ "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320002000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc28283483045022100b7c49846466b13b190ff739bbe3005c105482fc55539e55b1c561f76b6982b6c02200e5c35808619cf543c8405cff9fedd25f333a4a2f6f6d5e8af8150090c40ef0901008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" },
{ 1,
- "3044022027a3ffcb8a007e3349d75382efbd4b3fb99fcbd479a18555e58697bd1278d5c402205c8303d46211c3ae8975fe84a0df08b4623119fecd03bc93b49d7f7a0c64c710",
- "3045022100b697aca55c6fb15e5348bb7387b584815fd15e8dd306afe0c477cb550d0c2d40022050b0f7e370f7604d2fec781fefe86715dbe95dff4dab88d628f509d62f854de1",
- "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b28534856132000300000000010000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022027a3ffcb8a007e3349d75382efbd4b3fb99fcbd479a18555e58697bd1278d5c402205c8303d46211c3ae8975fe84a0df08b4623119fecd03bc93b49d7f7a0c64c71083483045022100b697aca55c6fb15e5348bb7387b584815fd15e8dd306afe0c477cb550d0c2d40022050b0f7e370f7604d2fec781fefe86715dbe95dff4dab88d628f509d62f854de1012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" },
+ "3045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e",
+ "3045022100d29330f24db213b262068706099b39c15fa7e070c3fcdf8836c09723fc4d365602203ce57d01e9f28601e461a0b5c4a50119b270bde8b70148d133a6849c70b115ac",
+ "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320003000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e83483045022100d29330f24db213b262068706099b39c15fa7e070c3fcdf8836c09723fc4d365602203ce57d01e9f28601e461a0b5c4a50119b270bde8b70148d133a6849c70b115ac012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" },
{ 2,
- "30440220013975ae356e6daf22a86a29f21c4f35aca82ed8f731a1103c60c74f5ed1c5aa02200350d4e5455cdbcacb7ccf174db5bed8286019e509a113f6b4c5e606ee12c9d7",
- "3045022100e69a29f78779577830e73f327073c93168896f1b89432124b7846f5def9cd9cb02204433db3697e6ed7ac89574ca066a749640e0c9e114ac2e0ee4545741fcf7b7e9",
- "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b2853485613200040000000001000000010b0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220013975ae356e6daf22a86a29f21c4f35aca82ed8f731a1103c60c74f5ed1c5aa02200350d4e5455cdbcacb7ccf174db5bed8286019e509a113f6b4c5e606ee12c9d783483045022100e69a29f78779577830e73f327073c93168896f1b89432124b7846f5def9cd9cb02204433db3697e6ed7ac89574ca066a749640e0c9e114ac2e0ee4545741fcf7b7e901008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
+ "3044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c1",
+ "304402202d4ce515cd9000ec37575972d70b8d24f73909fb7012e8ebd8c2066ef6fe187902202830b53e64ea565fecd0f398100691da6bb2a5cf9bb0d1926f1d71d05828a11e",
+ "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320004000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c18347304402202d4ce515cd9000ec37575972d70b8d24f73909fb7012e8ebd8c2066ef6fe187902202830b53e64ea565fecd0f398100691da6bb2a5cf9bb0d1926f1d71d05828a11e01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
{ 3,
- "304402205257017423644c7e831f30bc0c334eecfe66e9a6d2e92d157c5bece576b2be4f022047b21cf8e955e22b7471940563922d1a5852fb95459ca32905c7d46a19141664",
- "304402204f5de65a624e3f757adffb678bd887eb4e656538c5ea7044922f6ee3eed8a06202206ff6f7bfe73b565343cae76131ac658f1a9c60d3ca2343358cda60b9e35f94c8",
- "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320005000000000100000001d90d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402205257017423644c7e831f30bc0c334eecfe66e9a6d2e92d157c5bece576b2be4f022047b21cf8e955e22b7471940563922d1a5852fb95459ca32905c7d46a191416648347304402204f5de65a624e3f757adffb678bd887eb4e656538c5ea7044922f6ee3eed8a06202206ff6f7bfe73b565343cae76131ac658f1a9c60d3ca2343358cda60b9e35f94c8012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
+ "3044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc615",
+ "3045022100b20cd63e0587d1711beaebda4730775c4ac8b8b2ec78fe18a0c44c3f168c25230220079abb7fc4924e2fca5950842e5b9e416735585026914570078c4ef62f286226",
+ "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320005000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc61583483045022100b20cd63e0587d1711beaebda4730775c4ac8b8b2ec78fe18a0c44c3f168c25230220079abb7fc4924e2fca5950842e5b9e416735585026914570078c4ef62f286226012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
} );
// commitment tx with six outputs untrimmed (maximum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 2069;
+ chan.holder_dust_limit_satoshis = 546;
test_commitment!("304502210090b96a2498ce0c0f2fadbec2aab278fed54c1a7838df793ec4d2c78d96ec096202204fdd439c50f90d483baa7b68feeef4bd33bc277695405447bcd0bfb2ca34d7bc",
"3045022100ad9a9bbbb75d506ca3b716b336ee3cf975dd7834fcf129d7dd188146eb58a8b4022061a759ee417339f7fe2ea1e8deb83abb6a74db31a09b7648a932a639cda23e33",
"02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d03000000000000000001f2090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207475aeb0212ef9bf5130b60937817ad88c9a87976988ef1f323f026148cc4a850220739fea17ad3257dcad72e509c73eebe86bee30b178467b9fdab213d631b109df01483045022100d315522e09e7d53d2a659a79cb67fef56d6c4bddf3f46df6772d0d20a7beb7c8022070bcc17e288607b6a72be0bd83368bb6d53488db266c1cdb4d72214e4f02ac33012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with six outputs untrimmed (maximum feerate)
- chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
- chan.feerate_per_kw = 2060;
-
- test_commitment_with_anchors!("304402206208aeb34e404bd052ce3f298dfa832891c9d42caec99fe2a0d2832e9690b94302201b034bfcc6fa9faec667a9b7cbfe0b8d85e954aa239b66277887b5088aff08c3",
- "304402201ce37a44b95213358c20f44404d6db7a6083bea6f58de6c46547ae41a47c9f8202206db1d45be41373e92f90d346381febbea8c78671b28c153e30ad1db3441a9497",
- "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80084a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ab88f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402201ce37a44b95213358c20f44404d6db7a6083bea6f58de6c46547ae41a47c9f8202206db1d45be41373e92f90d346381febbea8c78671b28c153e30ad1db3441a94970147304402206208aeb34e404bd052ce3f298dfa832891c9d42caec99fe2a0d2832e9690b94302201b034bfcc6fa9faec667a9b7cbfe0b8d85e954aa239b66277887b5088aff08c301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
-
- { 0,
- "30440220011f999016570bbab9f3125377d0f35096b4dbe155f97c20f71829ead2817d1602201f23f7e17f6928734601c5d8613431eed5c90aa41c3106e8c1cb02ce32aacb5d",
- "3044022017da96dfb0eb4061fa0162dc6fa6b2e07ecc5040ab5e6cb07be59838460b3e58022079371ffc95002cc1dc2891ec38198c9c25aca8164304fe114f1b55e2ffd1ddd5",
- "02000000000101e7f364cf3a554b670767e723ef14b2af7a3eac70bd79dbde9256f384369c062d0200000000010000000175020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220011f999016570bbab9f3125377d0f35096b4dbe155f97c20f71829ead2817d1602201f23f7e17f6928734601c5d8613431eed5c90aa41c3106e8c1cb02ce32aacb5d83473044022017da96dfb0eb4061fa0162dc6fa6b2e07ecc5040ab5e6cb07be59838460b3e58022079371ffc95002cc1dc2891ec38198c9c25aca8164304fe114f1b55e2ffd1ddd501008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" },
-
- { 1,
- "304402202d2d9681409b0a0987bd4a268ffeb112df85c4c988ac2a3a2475cb00a61912c302206aa4f4d1388b7d3282bc847871af3cca30766cc8f1064e3a41ec7e82221e10f7",
- "304402206426d67911aa6ff9b1cb147b093f3f65a37831a86d7c741d999afc0666e1773d022000bb71821650c70ea58d9bcdd03af736c41a5a8159d436c3ee0408a07394dcce",
- "02000000000101e7f364cf3a554b670767e723ef14b2af7a3eac70bd79dbde9256f384369c062d0300000000010000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202d2d9681409b0a0987bd4a268ffeb112df85c4c988ac2a3a2475cb00a61912c302206aa4f4d1388b7d3282bc847871af3cca30766cc8f1064e3a41ec7e82221e10f78347304402206426d67911aa6ff9b1cb147b093f3f65a37831a86d7c741d999afc0666e1773d022000bb71821650c70ea58d9bcdd03af736c41a5a8159d436c3ee0408a07394dcce012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" },
-
- { 2,
- "3045022100f51cdaa525b7d4304548c642bb7945215eb5ae7d32874517cde67ca23ab0a12202206286d59e4b19926c6ac844be6f3ab8149a1ddb9c70f5026b7e83e40a6c08e6e1",
- "304502210091b16b1ac63b867e7a5ca0344f7b2aa1cdd49d4b72eac86a31e7ec6f069e20640220402bfb571ba3a9c49e3b0061c89303453803d0241059d899222aaac4799b5076",
- "02000000000101e7f364cf3a554b670767e723ef14b2af7a3eac70bd79dbde9256f384369c062d040000000001000000015d060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f51cdaa525b7d4304548c642bb7945215eb5ae7d32874517cde67ca23ab0a12202206286d59e4b19926c6ac844be6f3ab8149a1ddb9c70f5026b7e83e40a6c08e6e18348304502210091b16b1ac63b867e7a5ca0344f7b2aa1cdd49d4b72eac86a31e7ec6f069e20640220402bfb571ba3a9c49e3b0061c89303453803d0241059d899222aaac4799b507601008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
-
- { 3,
- "304402202f058d99cb5a54f90773d43ba4e7a0089efd9f8269ef2da1b85d48a3e230555402205acc4bd6561830867d45cd7b84bba9fa35ad2b345016471c1737142bc99782c4",
- "304402202913f9cacea54efd2316cffa91219def9e0e111977216c1e76e9da80befab14f022000a9a69e8f37ebe4a39107ab50fab0dde537334588f8f412bbaca57b179b87a6",
- "02000000000101e7f364cf3a554b670767e723ef14b2af7a3eac70bd79dbde9256f384369c062d05000000000100000001f2090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202f058d99cb5a54f90773d43ba4e7a0089efd9f8269ef2da1b85d48a3e230555402205acc4bd6561830867d45cd7b84bba9fa35ad2b345016471c1737142bc99782c48347304402202913f9cacea54efd2316cffa91219def9e0e111977216c1e76e9da80befab14f022000a9a69e8f37ebe4a39107ab50fab0dde537334588f8f412bbaca57b179b87a6012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
- } );
-
// commitment tx with five outputs untrimmed (minimum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 2070;
"02000000000101403ad7602b43293497a3a2235a12ecefda4f3a1f1d06e49b1786d945685de1ff02000000000000000001f1090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ae5fc7717ae684bc1fcf9020854e5dbe9842c9e7472879ac06ff95ac2bb10e4e022057728ada4c00083a3e65493fb5d50a232165948a1a0f530ef63185c2c8c56504014730440220408ad3009827a8fccf774cb285587686bfb2ed041f89a89453c311ce9c8ee0f902203c7392d9f8306d3a46522a66bd2723a7eb2628cb2d9b34d4c104f1766bf37502012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with five outputs untrimmed (minimum feerate)
- chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
- chan.feerate_per_kw = 2061;
-
- test_commitment_with_anchors!("3045022100a2faf2ad7e323b2a82e07dc40b6847207ca6ad7b089f2c21dea9a4d37e52d59d02204c9480ce0358eb51d92a4342355a97e272e3cc45f86c612a76a3fe32fc3c4cb4",
- "304402204ab07c659412dd2cd6043b1ad811ab215e901b6b5653e08cb3d2fe63d3e3dc57022031c7b3d130f9380ef09581f4f5a15cb6f359a2e0a597146b96c3533a26d6f4cd",
- "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837eab80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a18916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402204ab07c659412dd2cd6043b1ad811ab215e901b6b5653e08cb3d2fe63d3e3dc57022031c7b3d130f9380ef09581f4f5a15cb6f359a2e0a597146b96c3533a26d6f4cd01483045022100a2faf2ad7e323b2a82e07dc40b6847207ca6ad7b089f2c21dea9a4d37e52d59d02204c9480ce0358eb51d92a4342355a97e272e3cc45f86c612a76a3fe32fc3c4cb401475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
-
- { 0,
- "3045022100e10744f572a2cd1d787c969e894b792afaed21217ee0480df0112d2fa3ef96ea02202af4f66eb6beebc36d8e98719ed6b4be1b181659fcb561fc491d8cfebff3aa85",
- "3045022100c3dc3ea50a0ca20e350f97b50c52c5514717cfa36cb9600918caac5cb556842b022049af018d676dde0c8e28ecf325f3ff5c1594261c4f7511d501f9d62d0594d2a2",
- "02000000000101cf32732fe2d1387ed4e2335f69ddd3c0f337dabc03269e742531f89d35e161d10200000000010000000174020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e10744f572a2cd1d787c969e894b792afaed21217ee0480df0112d2fa3ef96ea02202af4f66eb6beebc36d8e98719ed6b4be1b181659fcb561fc491d8cfebff3aa8583483045022100c3dc3ea50a0ca20e350f97b50c52c5514717cfa36cb9600918caac5cb556842b022049af018d676dde0c8e28ecf325f3ff5c1594261c4f7511d501f9d62d0594d2a201008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" },
-
- { 1,
- "3045022100e1f51fb72fec604b029b348a3bb6363454e1869f5b1e24fd736f860c8039f8070220030a2c90186437d8c9b47d4897798c024521b1274991c4cdc125970b346094b1",
- "3045022100ec7ade6037e531629f24390ca9713782a04d648065d17fbe6b015981cdb296c202202d61049a6ecba2fb5314f3edcda2361cad187a89bea6e5d15185354d80c0c085",
- "02000000000101cf32732fe2d1387ed4e2335f69ddd3c0f337dabc03269e742531f89d35e161d1030000000001000000015c060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e1f51fb72fec604b029b348a3bb6363454e1869f5b1e24fd736f860c8039f8070220030a2c90186437d8c9b47d4897798c024521b1274991c4cdc125970b346094b183483045022100ec7ade6037e531629f24390ca9713782a04d648065d17fbe6b015981cdb296c202202d61049a6ecba2fb5314f3edcda2361cad187a89bea6e5d15185354d80c0c08501008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
-
- { 2,
- "304402203479f81a1d83c516957679dc98bf91d35deada967739a8e3869e3e8db08246130220053c8e154b97e3019048dcec3d51bfaf396f36861fbda6d33f0e2a57155c8b9f",
- "3045022100a558eb5caa04e35a4417c1f0123ac12eec5f6badee28f5764dc6b69486e594f802201589b12784e242f205832d2d032149bd4e79433ec304c05394241fc7dcba5a71",
- "02000000000101cf32732fe2d1387ed4e2335f69ddd3c0f337dabc03269e742531f89d35e161d104000000000100000001f1090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402203479f81a1d83c516957679dc98bf91d35deada967739a8e3869e3e8db08246130220053c8e154b97e3019048dcec3d51bfaf396f36861fbda6d33f0e2a57155c8b9f83483045022100a558eb5caa04e35a4417c1f0123ac12eec5f6badee28f5764dc6b69486e594f802201589b12784e242f205832d2d032149bd4e79433ec304c05394241fc7dcba5a71012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
- } );
-
// commitment tx with five outputs untrimmed (maximum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 2194;
"02000000000101153cd825fdb3aa624bfe513e8031d5d08c5e582fb3d1d1fe8faf27d3eed410cd020000000000000000019a090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c9e6f0454aa598b905a35e641a70cc9f67b5f38cc4b00843a041238c4a9f1c4a0220260a2822a62da97e44583e837245995ca2e36781769c52f19e498efbdcca262b014830450221008a9f2ea24cd455c2b64c1472a5fa83865b0a5f49a62b661801e884cf2849af8302204d44180e50bf6adfcf1c1e581d75af91aba4e28681ce4a5ee5f3cbf65eca10f3012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with five outputs untrimmed (maximum feerate)
- chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
- chan.feerate_per_kw = 2184;
-
- test_commitment_with_anchors!("3044022013d326f80ff7607cf366c823fcbbcb7a2b10322484825f151e6c4c756af24b8f02201ba05b9d8beb7cea2947f9f4d9e03f90435e93db2dd48b32eb9ca3f3dd042c79",
- "30440220555c05261f72c5b4702d5c83a608630822b473048724b08640d6e75e345094250220448950b74a96a56963928ba5db8b457661a742c855e69d239b3b6ab73de307a3",
- "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837eab80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a4f906a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220555c05261f72c5b4702d5c83a608630822b473048724b08640d6e75e345094250220448950b74a96a56963928ba5db8b457661a742c855e69d239b3b6ab73de307a301473044022013d326f80ff7607cf366c823fcbbcb7a2b10322484825f151e6c4c756af24b8f02201ba05b9d8beb7cea2947f9f4d9e03f90435e93db2dd48b32eb9ca3f3dd042c7901475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
-
- { 0,
- "304402202e03ba1390998b3487e9a7fefcb66814c09abea0ef1bcc915dbaefbcf310569a02206bd10493a105ac69048e9bcedcb8e3301ef81b55018d911a4afd297297f98d30",
- "304402200c3952ca04be0c60dcc0b7873a0829f560607524943554ae4a27d8d967166199022021a68657b88e22f9bf9ac6065be412685aff643d17049f04f2e99e86197dabb1",
- "020000000001015b03043e20eb467029305a22af4c3b915e793743f192c5d225cf1d3c6e8c03010200000000010000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202e03ba1390998b3487e9a7fefcb66814c09abea0ef1bcc915dbaefbcf310569a02206bd10493a105ac69048e9bcedcb8e3301ef81b55018d911a4afd297297f98d308347304402200c3952ca04be0c60dcc0b7873a0829f560607524943554ae4a27d8d967166199022021a68657b88e22f9bf9ac6065be412685aff643d17049f04f2e99e86197dabb101008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" },
-
- { 1,
- "304402201f8a6adda2403bc400c919ea69d72d315337291e00d02cde085ea32953dbc50002202d65230da98df7af8ebefd2b60b457d0945232988ee2d7460a94a77d414a9acc",
- "3045022100ea69c9273b8914ac62b5b7082d6ac1da2b7b065ebf2ef3cd6403f5305ce3f26802203d98736ea97638895a898dfcc5ee0d0c55eb496b3964df0bb25d223688ea8b87",
- "020000000001015b03043e20eb467029305a22af4c3b915e793743f192c5d225cf1d3c6e8c0301030000000001000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201f8a6adda2403bc400c919ea69d72d315337291e00d02cde085ea32953dbc50002202d65230da98df7af8ebefd2b60b457d0945232988ee2d7460a94a77d414a9acc83483045022100ea69c9273b8914ac62b5b7082d6ac1da2b7b065ebf2ef3cd6403f5305ce3f26802203d98736ea97638895a898dfcc5ee0d0c55eb496b3964df0bb25d223688ea8b8701008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
-
- { 2,
- "3045022100ea6e4c9b8f56dd9cf5799492a201cdd65b8bc9bc089c3cff34107896ae313f90022034760f7760975cc68e8917a7f62894e25583da7be11af557c4fc402661d0cbf8",
- "30440220717012f2f7ef6cac590aaf66c2109132c93ffba245959ac62d82e394ba80191302203f00fd9cb37c92c6b0ad4b33e62c3e55b04e5c2cfa0adcca5a9bc49774eeca8a",
- "020000000001015b03043e20eb467029305a22af4c3b915e793743f192c5d225cf1d3c6e8c0301040000000001000000019b090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ea6e4c9b8f56dd9cf5799492a201cdd65b8bc9bc089c3cff34107896ae313f90022034760f7760975cc68e8917a7f62894e25583da7be11af557c4fc402661d0cbf8834730440220717012f2f7ef6cac590aaf66c2109132c93ffba245959ac62d82e394ba80191302203f00fd9cb37c92c6b0ad4b33e62c3e55b04e5c2cfa0adcca5a9bc49774eeca8a012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
- } );
-
// commitment tx with four outputs untrimmed (minimum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 2195;
"020000000001018130a10f09b13677ba2885a8bca32860f3a952e5912b829a473639b5a2c07b900100000000000000000199090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d193b7ecccad8057571620a0b1ffa6c48e9483311723b59cf536043b20bc51550220546d4bd37b3b101ecda14f6c907af46ec391abce1cd9c7ce22b1a62b534f2f2a01473044022014d66f11f9cacf923807eba49542076c5fe5cccf252fb08fe98c78ef3ca6ab5402201b290dbe043cc512d9d78de074a5a129b8759bc6a6c546b190d120b690bd6e82012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with four outputs untrimmed (minimum feerate)
+ // anchors: commitment tx with four outputs untrimmed (minimum dust limit)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 2185;
+ chan.holder_dust_limit_satoshis = 2001;
test_commitment_with_anchors!("3044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c0",
"3045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd5",
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80064a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994b80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ac5916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd501473044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
{ 0,
- "304502210094480e38afb41d10fae299224872f19c53abe23c7033a1c0642c48713e7863a10220726dd9456407682667dc4bd9c66975acb3744961770b5002f7eb9c0df9ef2f3e",
- "304402203148dac61513dc0361738cba30cb341a1e580f8acd5ab0149bf65bd670688cf002207e5d9a0fcbbea2c263bc714fa9e9c44d7f582ea447f366119fc614a23de32f1f",
- "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc0200000000010000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050048304502210094480e38afb41d10fae299224872f19c53abe23c7033a1c0642c48713e7863a10220726dd9456407682667dc4bd9c66975acb3744961770b5002f7eb9c0df9ef2f3e8347304402203148dac61513dc0361738cba30cb341a1e580f8acd5ab0149bf65bd670688cf002207e5d9a0fcbbea2c263bc714fa9e9c44d7f582ea447f366119fc614a23de32f1f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
+ "304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb",
+ "30440220669de9ca7910eff65a7773ebd14a9fc371fe88cde5b8e2a81609d85c87ac939b02201ac29472fa4067322e92d75b624942d60be5050139b20bb363db75be79eb946f",
+ "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc02000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb834730440220669de9ca7910eff65a7773ebd14a9fc371fe88cde5b8e2a81609d85c87ac939b02201ac29472fa4067322e92d75b624942d60be5050139b20bb363db75be79eb946f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
{ 1,
- "304402200dbde868dbc20c6a2433fe8979ba5e3f966b1c2d1aeb615f1c42e9c938b3495402202eec5f663c8b601c2061c1453d35de22597c137d1907a2feaf714d551035cb6e",
- "3045022100b896bded41d7feac7af25c19e35c53037c53b50e73cfd01eb4ba139c7fdf231602203a3be049d3d89396c4dc766d82ce31e237da8bc3a93e2c7d35992d1932d9cfeb",
- "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc030000000001000000019a090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402200dbde868dbc20c6a2433fe8979ba5e3f966b1c2d1aeb615f1c42e9c938b3495402202eec5f663c8b601c2061c1453d35de22597c137d1907a2feaf714d551035cb6e83483045022100b896bded41d7feac7af25c19e35c53037c53b50e73cfd01eb4ba139c7fdf231602203a3be049d3d89396c4dc766d82ce31e237da8bc3a93e2c7d35992d1932d9cfeb012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
+ "3045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd7271",
+ "3045022100e3104ed8b239f8019e5f0a1a73d7782a94a8c36e7984f476c3a0b3cb0e62e27902207e3d52884600985f8a2098e53a5c30dd6a5e857733acfaa07ab2162421ed2688",
+ "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc03000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd727183483045022100e3104ed8b239f8019e5f0a1a73d7782a94a8c36e7984f476c3a0b3cb0e62e27902207e3d52884600985f8a2098e53a5c30dd6a5e857733acfaa07ab2162421ed2688012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
} );
// commitment tx with four outputs untrimmed (maximum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 3702;
+ chan.holder_dust_limit_satoshis = 546;
test_commitment!("304502210092a587aeb777f869e7ff0d7898ea619ee26a3dacd1f3672b945eea600be431100220077ee9eae3528d15251f2a52b607b189820e57a6ccfac8d1af502b132ee40169",
"3045022100e5efb73c32d32da2d79702299b6317de6fb24a60476e3855926d78484dd1b3c802203557cb66a42c944ef06e00bcc4da35a5bcb2f185aab0f8e403e519e1d66aaf75",
"020000000001018db483bff65c70ee71d8282aeec5a880e2e2b39e45772bda5460403095c62e3f0100000000000000000176050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022057649739b0eb74d541ead0dfdb3d4b2c15aa192720031044c3434c67812e5ca902201e5ede42d960ae551707f4a6b34b09393cf4dee2418507daa022e3550dbb58170147304402207faad26678c8850e01b4a0696d60841f7305e1832b786110ee9075cb92ed14a30220516ef8ee5dfa80824ea28cbcec0dd95f8b847146257c16960db98507db15ffdc012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with four outputs untrimmed (maximum feerate)
- chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
- chan.feerate_per_kw = 3686;
-
- test_commitment_with_anchors!("30440220784485cf7a0ad7979daf2c858ffdaf5298d0020cea7aea466843e7948223bd9902206031b81d25e02a178c64e62f843577fdcdfc7a1decbbfb54cd895de692df85ca",
- "3045022100c268496aad5c3f97f25cf41c1ba5483a12982de29b222051b6de3daa2229413b02207f3c82d77a2c14f0096ed9bb4c34649483bb20fa71f819f71af44de6593e8bb2",
- "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80064a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994b80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a29896a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c268496aad5c3f97f25cf41c1ba5483a12982de29b222051b6de3daa2229413b02207f3c82d77a2c14f0096ed9bb4c34649483bb20fa71f819f71af44de6593e8bb2014730440220784485cf7a0ad7979daf2c858ffdaf5298d0020cea7aea466843e7948223bd9902206031b81d25e02a178c64e62f843577fdcdfc7a1decbbfb54cd895de692df85ca01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
-
- { 0,
- "304402202cfe6618926ca9f1574f8c4659b425e9790b4677ba2248d77901290806130ffe02204ab37bb0287abcdb8b750b018d41a09effe37cb65ff801fa70d3f1a416599841",
- "3044022030b318139715e3b34f19be852cc01c1c0e1599e8b926a73df2bfb70dd186ddee022062a2b7398aed9f563b4014da04a1a99debd0ff663ceece68a547df5982dc2d72",
- "020000000001012c32e55722e4b96324d8e5b398d583a20780b25202816adc32dc3157dee731c90200000000010000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202cfe6618926ca9f1574f8c4659b425e9790b4677ba2248d77901290806130ffe02204ab37bb0287abcdb8b750b018d41a09effe37cb65ff801fa70d3f1a41659984183473044022030b318139715e3b34f19be852cc01c1c0e1599e8b926a73df2bfb70dd186ddee022062a2b7398aed9f563b4014da04a1a99debd0ff663ceece68a547df5982dc2d7201008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" },
-
- { 1,
- "30440220687af8544d335376620a6f4b5412bfd0da48de047c1785674f26e669d4a3ff82022058591c1e3a6c50017427d38a8f756eb685bdab88ec73838eed3530048861f9d5",
- "30440220109f1a62b5a13d28d5b7634dd7693b1d5994eb404c4bb4a9a80aa540d3984d170220307251107ff8499a23e99abce7dda4f1c707c98abddb9405a83de0081cde8ace",
- "020000000001012c32e55722e4b96324d8e5b398d583a20780b25202816adc32dc3157dee731c90300000000010000000176050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220687af8544d335376620a6f4b5412bfd0da48de047c1785674f26e669d4a3ff82022058591c1e3a6c50017427d38a8f756eb685bdab88ec73838eed3530048861f9d5834730440220109f1a62b5a13d28d5b7634dd7693b1d5994eb404c4bb4a9a80aa540d3984d170220307251107ff8499a23e99abce7dda4f1c707c98abddb9405a83de0081cde8ace012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
- } );
-
// commitment tx with three outputs untrimmed (minimum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 3703;
"0200000000010120060e4a29579d429f0f27c17ee5f1ee282f20d706d6f90b63d35946d8f3029a0000000000000000000175050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c34c61735f93f2e324cc873c3b248111ccf8f6db15d5969583757010d4ad2b4602207867bb919b2ddd6387873e425345c9b7fd18d1d66aba41f3607bc2896ef3c30a01483045022100988c143e2110067117d2321bdd4bd16ca1734c98b29290d129384af0962b634e02206c1b02478878c5f547018b833986578f90c3e9be669fe5788ad0072a55acbb05012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with three outputs untrimmed (minimum feerate)
+ // anchors: commitment tx with three outputs untrimmed (minimum dust limit)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 3687;
+ chan.holder_dust_limit_satoshis = 3001;
test_commitment_with_anchors!("3045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c228377",
"3045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d",
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80054a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aa28b6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d01483045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c22837701475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
{ 0,
- "3045022100b287bb8e079a62dcb3aaa8b6c67c0f434a87ebf64ab0bcfb2fc14b55576b859f02206d37c2eb5fd04cfc9eb0534c76a28a98da251b84a931377cce307af39dfaed74",
- "3045022100a497c64faea286ec4221f48628086dc6403fd7b60a23c4176e8ebbca15ae70dc0220754e20e968e96cf6421fd2a672c8c26d3bc6e19218cfc8fc2aa51fce026c14b1",
- "02000000000101542562b326c08e3a076d9cfca2be175041366591da334d8d513ff1686fd95a600200000000010000000175050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100b287bb8e079a62dcb3aaa8b6c67c0f434a87ebf64ab0bcfb2fc14b55576b859f02206d37c2eb5fd04cfc9eb0534c76a28a98da251b84a931377cce307af39dfaed7483483045022100a497c64faea286ec4221f48628086dc6403fd7b60a23c4176e8ebbca15ae70dc0220754e20e968e96cf6421fd2a672c8c26d3bc6e19218cfc8fc2aa51fce026c14b1012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
+ "3044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c",
+ "3045022100af7a8b7c7ff2080c68995254cb66d64d9954edcc5baac3bb4f27ed2d29aaa6120220421c27da7a60574a9263f271e0f3bd34594ec6011095190022b3b54596ea03de",
+ "02000000000101542562b326c08e3a076d9cfca2be175041366591da334d8d513ff1686fd95a6002000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c83483045022100af7a8b7c7ff2080c68995254cb66d64d9954edcc5baac3bb4f27ed2d29aaa6120220421c27da7a60574a9263f271e0f3bd34594ec6011095190022b3b54596ea03de012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
} );
// commitment tx with three outputs untrimmed (maximum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 4914;
+ chan.holder_dust_limit_satoshis = 546;
test_commitment!("3045022100b4b16d5f8cc9fc4c1aff48831e832a0d8990e133978a66e302c133550954a44d022073573ce127e2200d316f6b612803a5c0c97b8d20e1e44dbe2ac0dd2fb8c95244",
"3045022100d72638bc6308b88bb6d45861aae83e5b9ff6e10986546e13bce769c70036e2620220320be7c6d66d22f30b9fcd52af66531505b1310ca3b848c19285b38d8a1a8c19",
"02000000000101a9172908eace869cc35128c31fc2ab502f72e4dff31aab23e0244c4b04b11ab00000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f43591c156038ba217756006bb3c55f7d113a325cdd7d9303c82115372858d68022016355b5aadf222bc8d12e426c75f4a03423917b2443a103eb2a498a3a2234374014730440220585dee80fafa264beac535c3c0bb5838ac348b156fdc982f86adc08dfc9bfd250220130abb82f9f295cc9ef423dcfef772fde2acd85d9df48cc538981d26a10a9c10012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" }
} );
- // anchors: commitment tx with three outputs untrimmed (maximum feerate)
- chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
- chan.feerate_per_kw = 4893;
-
- test_commitment_with_anchors!("3045022100a8771147109e4d3f44a5976c3c3de98732bbb77308d21444dbe0d76faf06480e02200b4e916e850c3d1f918de87bbbbb07843ffea1d4658dfe060b6f9ccd96d34be8",
- "30440220086288faceab47461eb2d808e9e9b0cb3ffc24a03c2f18db7198247d38f10e58022031d1c2782a58c8c6ce187d0019eb47a83babdf3040e2caff299ab48f7e12b1fa",
- "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80054a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a87856a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220086288faceab47461eb2d808e9e9b0cb3ffc24a03c2f18db7198247d38f10e58022031d1c2782a58c8c6ce187d0019eb47a83babdf3040e2caff299ab48f7e12b1fa01483045022100a8771147109e4d3f44a5976c3c3de98732bbb77308d21444dbe0d76faf06480e02200b4e916e850c3d1f918de87bbbbb07843ffea1d4658dfe060b6f9ccd96d34be801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
-
- { 0,
- "30450221008db80f8531104820b3e894492b4463f074f965b542e1b5c153ddfb108a5ea642022030b203d857a2b3581c2087a7bf17c95d04fadc1c6cdae88c620477f2dccb1ee4",
- "3045022100e5fbae857c47dbfc050a05924bd449fc9804798bd6442002c578437dc34450810220296589bc387645512345299e307116aaac4ce9fc752abcd1936b802d03526312",
- "02000000000101d515a15e9175fd315bb8d4e768f28684801a9e5a9acdfeba34f7b3b3b3a9ba1d0200000000010000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221008db80f8531104820b3e894492b4463f074f965b542e1b5c153ddfb108a5ea642022030b203d857a2b3581c2087a7bf17c95d04fadc1c6cdae88c620477f2dccb1ee483483045022100e5fbae857c47dbfc050a05924bd449fc9804798bd6442002c578437dc34450810220296589bc387645512345299e307116aaac4ce9fc752abcd1936b802d03526312012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" }
- } );
-
// commitment tx with two outputs untrimmed (minimum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 4915;
+ chan.holder_dust_limit_satoshis = 546;
test_commitment!("304402203a286936e74870ca1459c700c71202af0381910a6bfab687ef494ef1bc3e02c902202506c362d0e3bee15e802aa729bf378e051644648253513f1c085b264cc2a720",
"30450221008a953551f4d67cb4df3037207fc082ddaf6be84d417b0bd14c80aab66f1b01a402207508796dc75034b2dee876fe01dc05a08b019f3e5d689ac8842ade2f1befccf5",
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484fa926a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221008a953551f4d67cb4df3037207fc082ddaf6be84d417b0bd14c80aab66f1b01a402207508796dc75034b2dee876fe01dc05a08b019f3e5d689ac8842ade2f1befccf50147304402203a286936e74870ca1459c700c71202af0381910a6bfab687ef494ef1bc3e02c902202506c362d0e3bee15e802aa729bf378e051644648253513f1c085b264cc2a72001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {});
- // anchors: commitment tx with two outputs untrimmed (minimum feerate)
+ // anchors: commitment tx with two outputs untrimmed (minimum dust limit)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 4894;
+ chan.holder_dust_limit_satoshis = 4001;
test_commitment_with_anchors!("3045022100e784a66b1588575801e237d35e510fd92a81ae3a4a2a1b90c031ad803d07b3f3022021bc5f16501f167607d63b681442da193eb0a76b4b7fd25c2ed4f8b28fd35b95",
"30450221009f16ac85d232e4eddb3fcd750a68ebf0b58e3356eaada45d3513ede7e817bf4c02207c2b043b4e5f971261975406cb955219fa56bffe5d834a833694b5abc1ce4cfd",
// commitment tx with two outputs untrimmed (maximum feerate)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 9651180;
+ chan.holder_dust_limit_satoshis = 546;
test_commitment!("304402200a8544eba1d216f5c5e530597665fa9bec56943c0f66d98fc3d028df52d84f7002201e45fa5c6bc3a506cc2553e7d1c0043a9811313fc39c954692c0d47cfce2bbd3",
"3045022100e11b638c05c650c2f63a421d36ef8756c5ce82f2184278643520311cdf50aa200220259565fb9c8e4a87ccaf17f27a3b9ca4f20625754a0920d9c6c239d8156a11de",
"304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379",
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484040047304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a3790147304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {});
- // anchors: commitment tx with one output untrimmed (minimum feerate)
+ // anchors: commitment tx with one output untrimmed (minimum dust limit)
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 6216010;
+ chan.holder_dust_limit_satoshis = 4001;
test_commitment_with_anchors!("30450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf",
"30450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1",
// commitment tx with fee greater than funder amount
chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000
chan.feerate_per_kw = 9651936;
+ chan.holder_dust_limit_satoshis = 546;
test_commitment!("304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a2",
"304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379",
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5e881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aae9c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c37ac4fc8538677631230c4b286f36b6f54c51fb4b34ef0bd0ba219ba47452630220278e09a745454ea380f3694392ed113762c68dd209b48360f547541088be9e4501483045022100c592f6b80d35b4f5d1e3bc9788f51141a0065be6013bad53a1977f7c444651660220278ac06ead9016bfb8dc476f186eabace2b02793b2f308442f5b0d5f24a6894801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
{ 0,
- "304402202060a5acb12105e92f27d7b86e6caf1e003d9d82068338e5a8a9a0d14cba11260220030ca4dba8fad24a2e395906220c991eccd5369bc4b0f216d217b5f86d1fc61d",
- "3044022044f5425fe630fa614f349f55642e4a0b76e2583054b21543821660d9e8f3735702207f70424835b541874ca8bf0443cca4028afa2f6c03a17b0688df85d5c44eeefc",
- "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe29020000000001000000011e070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202060a5acb12105e92f27d7b86e6caf1e003d9d82068338e5a8a9a0d14cba11260220030ca4dba8fad24a2e395906220c991eccd5369bc4b0f216d217b5f86d1fc61d83473044022044f5425fe630fa614f349f55642e4a0b76e2583054b21543821660d9e8f3735702207f70424835b541874ca8bf0443cca4028afa2f6c03a17b0688df85d5c44eeefc012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" },
+ "3045022100de8a0649d54fd2e4fc04502c77df9b65da839bbd01854f818f129338b99564b2022009528dbb12c00e874cb2149b1dccc600c69ea5e4042ebf584984fcb029c2d1ec",
+ "304402203e7c2622fa3ca29355d37a0ea991bfd7cdb54e6122a1d98d3229d092131f55cd022055263f7f8f32f4cd2f86da63ca106bd7badf0b19ee9833d80cd3b9216eeafd74",
+ "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe2902000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100de8a0649d54fd2e4fc04502c77df9b65da839bbd01854f818f129338b99564b2022009528dbb12c00e874cb2149b1dccc600c69ea5e4042ebf584984fcb029c2d1ec8347304402203e7c2622fa3ca29355d37a0ea991bfd7cdb54e6122a1d98d3229d092131f55cd022055263f7f8f32f4cd2f86da63ca106bd7badf0b19ee9833d80cd3b9216eeafd74012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" },
{ 1,
- "304402206fde7eb6d7a47fdc63705d3db2169054e229f10342dea66f150b163381f48a0802201be28509c2de9be4b7ab72c569c6fd51c0ce0904fea459142f31d442cd043eb8",
- "3045022100ad0236a78dbd029d3a8f583f7f82ee62892273d45303d00ef5a03fecf8903a36022004b2db33f8ff2f4a08ca6127c9cbfd9144c691a2feb9287e36ae6bc7c83c5a5f",
- "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe2903000000000100000001e0120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206fde7eb6d7a47fdc63705d3db2169054e229f10342dea66f150b163381f48a0802201be28509c2de9be4b7ab72c569c6fd51c0ce0904fea459142f31d442cd043eb883483045022100ad0236a78dbd029d3a8f583f7f82ee62892273d45303d00ef5a03fecf8903a36022004b2db33f8ff2f4a08ca6127c9cbfd9144c691a2feb9287e36ae6bc7c83c5a5f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568f9010000" },
+ "3045022100de6eee8474376ea316d007b33103b4543a46bdf6fda5cbd5902b28a5bc14584f022002989e7b4f7813b77acbe4babcf96d7ffbbe0bf14cba24672364f8e591479edb",
+ "3045022100c10688346a9d84647bde7027da07f0d79c6d4129307e4c6c9aea7bdbf25ac3350220269104209793c32c47491698c4e46ebea9c3293a1e4403f9abda39f79698f6b5",
+ "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe290300000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100de6eee8474376ea316d007b33103b4543a46bdf6fda5cbd5902b28a5bc14584f022002989e7b4f7813b77acbe4babcf96d7ffbbe0bf14cba24672364f8e591479edb83483045022100c10688346a9d84647bde7027da07f0d79c6d4129307e4c6c9aea7bdbf25ac3350220269104209793c32c47491698c4e46ebea9c3293a1e4403f9abda39f79698f6b501008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568f9010000" },
{ 2,
- "304402205eebc78d8ae6a36c27ef80172359eb757fb18e99fa75b28c37ffe3444b967bc7022060a01c33398d4d8244c42c762fb699e9f61c1f034ff976df2c94350c5a6032a7",
- "3045022100ad3fd523594e1b876316401774a30ee6c48bb7fa0efd768bf9a2d022201311ff02207bed627ed8e01041137f03dbaf03c836970be27a4d50f69d90cf1282ff2815e3",
- "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe2904000000000100000001e0120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402205eebc78d8ae6a36c27ef80172359eb757fb18e99fa75b28c37ffe3444b967bc7022060a01c33398d4d8244c42c762fb699e9f61c1f034ff976df2c94350c5a6032a783483045022100ad3fd523594e1b876316401774a30ee6c48bb7fa0efd768bf9a2d022201311ff02207bed627ed8e01041137f03dbaf03c836970be27a4d50f69d90cf1282ff2815e301008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568fa010000" }
+ "3045022100fe87da8124ceecbcabb9d599c5339f40277c7c7406514fafbccbf180c7c09cf40220429c7fb6d0fd3705e931ab1219ab0432af38ae4d676008cc1964fbeb8cd35d2e",
+ "3044022040ac769a851da31d8e4863e5f94719204f716c82a1ce6d6c52193d9a33b84bce022035df97b078ce80f20dca2109e4c6075af0b50148811452e7290e68b2680fced4",
+ "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe290400000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fe87da8124ceecbcabb9d599c5339f40277c7c7406514fafbccbf180c7c09cf40220429c7fb6d0fd3705e931ab1219ab0432af38ae4d676008cc1964fbeb8cd35d2e83473044022040ac769a851da31d8e4863e5f94719204f716c82a1ce6d6c52193d9a33b84bce022035df97b078ce80f20dca2109e4c6075af0b50148811452e7290e68b2680fced401008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568fa010000" }
} );
}
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&feeest, &&keys_provider,
- node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
+ node_b_node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config, 0, 42).unwrap();
let mut channel_type_features = ChannelTypeFeatures::only_static_remote_key();
channel_type_features.set_zero_conf_required();
open_channel_msg.channel_type = Some(channel_type_features);
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
let res = Channel::<EnforcingSigner>::new_from_req(&feeest, &&keys_provider,
- node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42);
+ node_b_node_id, &channelmanager::provided_init_features(), &open_channel_msg, 7, &config, 0, &&logger, 42);
assert!(res.is_ok());
}
}
use bitcoin::{LockTime, secp256k1, Sequence};
use chain;
-use chain::{Confirm, ChannelMonitorUpdateErr, Watch, BestBlock};
+use chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
use chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
use chain::transaction::{OutPoint, TransactionData};
// construct one themselves.
use ln::{inbound_payment, PaymentHash, PaymentPreimage, PaymentSecret};
use ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch};
-use ln::features::{ChannelTypeFeatures, InitFeatures, NodeFeatures};
+use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
+#[cfg(any(feature = "_test_utils", test))]
+use ln::features::InvoiceFeatures;
use routing::router::{PaymentParameters, Route, RouteHop, RoutePath, RouteParameters};
use ln::msgs;
use ln::onion_utils;
/// SCIDs being added once the funding transaction is confirmed at the channel's required
/// confirmation depth.
pub(super) short_to_chan_info: HashMap<u64, (PublicKey, [u8; 32])>,
- /// SCID/SCID Alias -> forward infos. Key of 0 means payments received.
- ///
- /// Note that because we may have an SCID Alias as the key we can have two entries per channel,
- /// though in practice we probably won't be receiving HTLCs for a channel both via the alias
- /// and via the classic SCID.
- ///
- /// Note that while this is held in the same mutex as the channels themselves, no consistency
- /// guarantees are made about the existence of a channel with the short id here, nor the short
- /// ids in the PendingHTLCInfo!
- pub(super) forward_htlcs: HashMap<u64, Vec<HTLCForwardInfo>>,
/// Map from payment hash to the payment data and any HTLCs which are to us and can be
/// failed/claimed by the user.
///
/// essentially you should default to using a SimpleRefChannelManager, and use a
/// SimpleArcChannelManager when you require a ChannelManager with a static lifetime, such as when
/// you're using lightning-net-tokio.
+//
+// Lock order:
+// The tree structure below illustrates the lock order requirements for the different locks of the
+// `ChannelManager`. Locks can be held at the same time if they are on the same branch in the tree,
+// and should then be taken in the order of the lowest to the highest level in the tree.
+// Note that locks on different branches shall not be taken at the same time, as doing so will
+// create a new lock order for those specific locks in the order they were taken.
+//
+// Lock order tree:
+//
+// `total_consistency_lock`
+// |
+// |__`forward_htlcs`
+// |
+// |__`channel_state`
+// | |
+// | |__`id_to_peer`
+// | |
+// | |__`per_peer_state`
+// | |
+// | |__`outbound_scid_aliases`
+// | |
+// | |__`pending_inbound_payments`
+// | |
+// | |__`pending_outbound_payments`
+// | |
+// | |__`best_block`
+// | |
+// | |__`pending_events`
+// | |
+// | |__`pending_background_events`
+//
pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
where M::Target: chain::Watch<Signer>,
T::Target: BroadcasterInterface,
chain_monitor: M,
tx_broadcaster: T,
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
#[cfg(test)]
pub(super) best_block: RwLock<BestBlock>,
#[cfg(not(test))]
best_block: RwLock<BestBlock>,
secp_ctx: Secp256k1<secp256k1::All>,
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
#[cfg(any(test, feature = "_test_utils"))]
pub(super) channel_state: Mutex<ChannelHolder<Signer>>,
#[cfg(not(any(test, feature = "_test_utils")))]
/// expose them to users via a PaymentReceived event. HTLCs which do not meet the requirements
/// here are failed when we process them as pending-forwardable-HTLCs, and entries are removed
/// after we generate a PaymentReceived upon receipt of all MPP parts or when they time out.
- /// Locked *after* channel_state.
+ ///
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
pending_inbound_payments: Mutex<HashMap<PaymentHash, PendingInboundPayment>>,
/// The session_priv bytes and retry metadata of outbound payments which are pending resolution.
///
/// See `PendingOutboundPayment` documentation for more info.
///
- /// Locked *after* channel_state.
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
pending_outbound_payments: Mutex<HashMap<PaymentId, PendingOutboundPayment>>,
+ /// SCID/SCID Alias -> forward infos. Key of 0 means payments received.
+ ///
+ /// Note that because we may have an SCID Alias as the key we can have two entries per channel,
+ /// though in practice we probably won't be receiving HTLCs for a channel both via the alias
+ /// and via the classic SCID.
+ ///
+ /// Note that no consistency guarantees are made about the existence of a channel with the
+ /// `short_channel_id` here, nor the `short_channel_id` in the `PendingHTLCInfo`!
+ ///
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
+ #[cfg(test)]
+ pub(super) forward_htlcs: Mutex<HashMap<u64, Vec<HTLCForwardInfo>>>,
+ #[cfg(not(test))]
+ forward_htlcs: Mutex<HashMap<u64, Vec<HTLCForwardInfo>>>,
+
/// The set of outbound SCID aliases across all our channels, including unconfirmed channels
/// and some closed channels which reached a usable state prior to being closed. This is used
/// only to avoid duplicates, and is not persisted explicitly to disk, but rebuilt from the
/// active channel list on load.
+ ///
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
outbound_scid_aliases: Mutex<HashSet<u64>>,
/// `channel_id` -> `counterparty_node_id`.
/// We should add `counterparty_node_id`s to `MonitorEvent`s, and eventually rely on it in the
/// future. That would make this map redundant, as only the `ChannelManager::per_peer_state` is
/// required to access the channel with the `counterparty_node_id`.
+ ///
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
id_to_peer: Mutex<HashMap<[u8; 32], PublicKey>>,
our_network_key: SecretKey,
/// operate on the inner value freely. Sadly, this prevents parallel operation when opening a
/// new channel.
///
- /// If also holding `channel_state` lock, must lock `channel_state` prior to `per_peer_state`.
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
per_peer_state: RwLock<HashMap<PublicKey, Mutex<PeerState>>>,
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
pending_events: Mutex<Vec<events::Event>>,
+ /// See `ChannelManager` struct-level documentation for lock order requirements.
pending_background_events: Mutex<Vec<BackgroundEvent>>,
/// Used when we have to take a BIG lock to make sure everything is self-consistent.
/// Essentially just when we're serializing ourselves out.
/// in over-/re-payment.
///
/// The results here are ordered the same as the paths in the route object which was passed to
- /// send_payment, and any Errs which are not APIError::MonitorUpdateFailed can be safely
- /// retried (though there is currently no API with which to do so).
+ /// send_payment, and any `Err`s which are not [`APIError::MonitorUpdateInProgress`] can be
+ /// safely retried via [`ChannelManager::retry_payment`].
///
- /// Any entries which contain Err(APIError::MonitorUpdateFailed) or Ok(()) MUST NOT be retried
- /// as they will result in over-/re-payment. These HTLCs all either successfully sent (in the
- /// case of Ok(())) or will send once channel_monitor_updated is called on the next-hop channel
- /// with the latest update_id.
+ /// Any entries which contain `Err(APIError::MonitorUpdateInprogress)` or `Ok(())` MUST NOT be
+ /// retried as they will result in over-/re-payment. These HTLCs all either successfully sent
+ /// (in the case of `Ok(())`) or will send once a [`MonitorEvent::Completed`] is provided for
+ /// the next-hop channel with the latest update_id.
PartialFailure {
/// The errors themselves, in the same order as the route hops.
results: Vec<Result<(), APIError>>,
}
}
-macro_rules! handle_monitor_err {
+macro_rules! handle_monitor_update_res {
($self: ident, $err: expr, $short_to_chan_info: expr, $chan: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $resend_channel_ready: expr, $failed_forwards: expr, $failed_fails: expr, $failed_finalized_fulfills: expr, $chan_id: expr) => {
match $err {
- ChannelMonitorUpdateErr::PermanentFailure => {
- log_error!($self.logger, "Closing channel {} due to monitor update ChannelMonitorUpdateErr::PermanentFailure", log_bytes!($chan_id[..]));
+ ChannelMonitorUpdateStatus::PermanentFailure => {
+ log_error!($self.logger, "Closing channel {} due to monitor update ChannelMonitorUpdateStatus::PermanentFailure", log_bytes!($chan_id[..]));
update_maps_on_chan_removal!($self, $short_to_chan_info, $chan);
// TODO: $failed_fails is dropped here, which will cause other channels to hit the
// chain in a confused state! We need to move them into the ChannelMonitor which
// given up the preimage yet, so might as well just wait until the payment is
// retried, avoiding the on-chain fees.
let res: Result<(), _> = Err(MsgHandleErrInternal::from_finish_shutdown("ChannelMonitor storage failure".to_owned(), *$chan_id, $chan.get_user_id(),
- $chan.force_shutdown(true), $self.get_channel_update_for_broadcast(&$chan).ok() ));
+ $chan.force_shutdown(false), $self.get_channel_update_for_broadcast(&$chan).ok() ));
(res, true)
},
- ChannelMonitorUpdateErr::TemporaryFailure => {
- log_info!($self.logger, "Disabling channel {} due to monitor update TemporaryFailure. On restore will send {} and process {} forwards, {} fails, and {} fulfill finalizations",
+ ChannelMonitorUpdateStatus::InProgress => {
+ log_info!($self.logger, "Disabling channel {} due to monitor update in progress. On restore will send {} and process {} forwards, {} fails, and {} fulfill finalizations",
log_bytes!($chan_id[..]),
if $resend_commitment && $resend_raa {
match $action_type {
if !$resend_raa {
debug_assert!($action_type == RAACommitmentOrder::CommitmentFirst || !$resend_commitment);
}
- $chan.monitor_update_failed($resend_raa, $resend_commitment, $resend_channel_ready, $failed_forwards, $failed_fails, $failed_finalized_fulfills);
+ $chan.monitor_updating_paused($resend_raa, $resend_commitment, $resend_channel_ready, $failed_forwards, $failed_fails, $failed_finalized_fulfills);
(Err(MsgHandleErrInternal::from_chan_no_close(ChannelError::Ignore("Failed to update ChannelMonitor".to_owned()), *$chan_id)), false)
},
+ ChannelMonitorUpdateStatus::Completed => {
+ (Ok(()), false)
+ },
}
};
($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $resend_channel_ready: expr, $failed_forwards: expr, $failed_fails: expr, $failed_finalized_fulfills: expr) => { {
- let (res, drop) = handle_monitor_err!($self, $err, $channel_state.short_to_chan_info, $entry.get_mut(), $action_type, $resend_raa, $resend_commitment, $resend_channel_ready, $failed_forwards, $failed_fails, $failed_finalized_fulfills, $entry.key());
+ let (res, drop) = handle_monitor_update_res!($self, $err, $channel_state.short_to_chan_info, $entry.get_mut(), $action_type, $resend_raa, $resend_commitment, $resend_channel_ready, $failed_forwards, $failed_fails, $failed_finalized_fulfills, $entry.key());
if drop {
$entry.remove_entry();
}
} };
($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $chan_id: expr, COMMITMENT_UPDATE_ONLY) => { {
debug_assert!($action_type == RAACommitmentOrder::CommitmentFirst);
- handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, false, true, false, Vec::new(), Vec::new(), Vec::new(), $chan_id)
+ handle_monitor_update_res!($self, $err, $channel_state, $entry, $action_type, false, true, false, Vec::new(), Vec::new(), Vec::new(), $chan_id)
} };
($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $chan_id: expr, NO_UPDATE) => {
- handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, false, false, false, Vec::new(), Vec::new(), Vec::new(), $chan_id)
+ handle_monitor_update_res!($self, $err, $channel_state, $entry, $action_type, false, false, false, Vec::new(), Vec::new(), Vec::new(), $chan_id)
};
($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_channel_ready: expr, OPTIONALLY_RESEND_FUNDING_LOCKED) => {
- handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, false, false, $resend_channel_ready, Vec::new(), Vec::new(), Vec::new())
+ handle_monitor_update_res!($self, $err, $channel_state, $entry, $action_type, false, false, $resend_channel_ready, Vec::new(), Vec::new(), Vec::new())
};
($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr) => {
- handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, false, Vec::new(), Vec::new(), Vec::new())
+ handle_monitor_update_res!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, false, Vec::new(), Vec::new(), Vec::new())
};
($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $failed_forwards: expr, $failed_fails: expr) => {
- handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, false, $failed_forwards, $failed_fails, Vec::new())
+ handle_monitor_update_res!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, false, $failed_forwards, $failed_fails, Vec::new())
};
}
-macro_rules! return_monitor_err {
- ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr) => {
- return handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment);
- };
- ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $failed_forwards: expr, $failed_fails: expr) => {
- return handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, $failed_forwards, $failed_fails);
- }
-}
-
-// Does not break in case of TemporaryFailure!
-macro_rules! maybe_break_monitor_err {
- ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr) => {
- match (handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment), $err) {
- (e, ChannelMonitorUpdateErr::PermanentFailure) => {
- break e;
- },
- (_, ChannelMonitorUpdateErr::TemporaryFailure) => { },
- }
- }
-}
-
macro_rules! send_channel_ready {
($short_to_chan_info: expr, $pending_msg_events: expr, $channel: expr, $channel_ready_msg: expr) => {
$pending_msg_events.push(events::MessageSendEvent::SendChannelReady {
// only case where we can get a new ChannelMonitorUpdate would be if we also
// have some commitment updates to send as well.
assert!($commitment_update.is_some());
- if let Err(e) = $self.chain_monitor.update_channel($channel_entry.get().get_funding_txo().unwrap(), monitor_update) {
- // channel_reestablish doesn't guarantee the order it returns is sensical
- // for the messages it returns, but if we're setting what messages to
- // re-transmit on monitor update success, we need to make sure it is sane.
- let mut order = $order;
- if $raa.is_none() {
- order = RAACommitmentOrder::CommitmentFirst;
+ match $self.chain_monitor.update_channel($channel_entry.get().get_funding_txo().unwrap(), monitor_update) {
+ ChannelMonitorUpdateStatus::Completed => {},
+ e => {
+ // channel_reestablish doesn't guarantee the order it returns is sensical
+ // for the messages it returns, but if we're setting what messages to
+ // re-transmit on monitor update success, we need to make sure it is sane.
+ let mut order = $order;
+ if $raa.is_none() {
+ order = RAACommitmentOrder::CommitmentFirst;
+ }
+ break handle_monitor_update_res!($self, e, $channel_state, $channel_entry, order, $raa.is_some(), true);
}
- break handle_monitor_err!($self, e, $channel_state, $channel_entry, order, $raa.is_some(), true);
}
}
channel_state: Mutex::new(ChannelHolder{
by_id: HashMap::new(),
short_to_chan_info: HashMap::new(),
- forward_htlcs: HashMap::new(),
claimable_htlcs: HashMap::new(),
pending_msg_events: Vec::new(),
}),
outbound_scid_aliases: Mutex::new(HashSet::new()),
pending_inbound_payments: Mutex::new(HashMap::new()),
pending_outbound_payments: Mutex::new(HashMap::new()),
+ forward_htlcs: Mutex::new(HashMap::new()),
id_to_peer: Mutex::new(HashMap::new()),
our_network_key: keys_manager.get_node_secret(Recipient::Node).unwrap(),
// Update the monitor with the shutdown script if necessary.
if let Some(monitor_update) = monitor_update {
- if let Err(e) = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update) {
- let (result, is_permanent) =
- handle_monitor_err!(self, e, channel_state.short_to_chan_info, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
- if is_permanent {
- remove_channel!(self, channel_state, chan_entry);
- break result;
- }
+ let update_res = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update);
+ let (result, is_permanent) =
+ handle_monitor_update_res!(self, update_res, channel_state.short_to_chan_info, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
+ if is_permanent {
+ remove_channel!(self, channel_state, chan_entry);
+ break result;
}
}
for htlc_source in failed_htlcs.drain(..) {
let receiver = HTLCDestination::NextHopChannel { node_id: Some(*counterparty_node_id), channel_id: *channel_id };
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), htlc_source.0, &htlc_source.1, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
+ self.fail_htlc_backwards_internal(htlc_source.0, &htlc_source.1, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
}
let _ = handle_error!(self, result, *counterparty_node_id);
log_debug!(self.logger, "Finishing force-closure of channel with {} HTLCs to fail", failed_htlcs.len());
for htlc_source in failed_htlcs.drain(..) {
let (source, payment_hash, counterparty_node_id, channel_id) = htlc_source;
- let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id: channel_id };
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
+ let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
+ self.fail_htlc_backwards_internal(source, &payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
}
if let Some((funding_txo, monitor_update)) = monitor_update_option {
// There isn't anything we can do if we get an update failure - we're already
channel_state, chan)
} {
Some((update_add, commitment_signed, monitor_update)) => {
- if let Err(e) = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
- maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
- // Note that MonitorUpdateFailed here indicates (per function docs)
- // that we will resend the commitment update once monitor updating
- // is restored. Therefore, we must return an error indicating that
- // it is unsafe to retry the payment wholesale, which we do in the
- // send_payment check for MonitorUpdateFailed, below.
- insert_outbound_payment!(); // Only do this after possibly break'ing on Perm failure above.
- return Err(APIError::MonitorUpdateFailed);
+ let update_err = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update);
+ let chan_id = chan.get().channel_id();
+ match (update_err,
+ handle_monitor_update_res!(self, update_err, channel_state, chan,
+ RAACommitmentOrder::CommitmentFirst, false, true))
+ {
+ (ChannelMonitorUpdateStatus::PermanentFailure, Err(e)) => break Err(e),
+ (ChannelMonitorUpdateStatus::Completed, Ok(())) => {
+ insert_outbound_payment!();
+ },
+ (ChannelMonitorUpdateStatus::InProgress, Err(_)) => {
+ // Note that MonitorUpdateInProgress here indicates (per function
+ // docs) that we will resend the commitment update once monitor
+ // updating completes. Therefore, we must return an error
+ // indicating that it is unsafe to retry the payment wholesale,
+ // which we do in the send_payment check for
+ // MonitorUpdateInProgress, below.
+ insert_outbound_payment!(); // Only do this after possibly break'ing on Perm failure above.
+ return Err(APIError::MonitorUpdateInProgress);
+ },
+ _ => unreachable!(),
}
- insert_outbound_payment!();
- log_debug!(self.logger, "Sending payment along path resulted in a commitment_signed for channel {}", log_bytes!(chan.get().channel_id()));
+ log_debug!(self.logger, "Sending payment along path resulted in a commitment_signed for channel {}", log_bytes!(chan_id));
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
node_id: path.first().unwrap().pubkey,
updates: msgs::CommitmentUpdate {
/// PaymentSendFailure for more info.
///
/// In general, a path may raise:
- /// * APIError::RouteError when an invalid route or forwarding parameter (cltv_delta, fee,
+ /// * [`APIError::RouteError`] when an invalid route or forwarding parameter (cltv_delta, fee,
/// node public key) is specified.
- /// * APIError::ChannelUnavailable if the next-hop channel is not available for updates
+ /// * [`APIError::ChannelUnavailable`] if the next-hop channel is not available for updates
/// (including due to previous monitor update failure or new permanent monitor update
/// failure).
- /// * APIError::MonitorUpdateFailed if a new monitor update failure prevented sending the
+ /// * [`APIError::MonitorUpdateInProgress`] if a new monitor update failure prevented sending the
/// relevant updates.
///
/// Note that depending on the type of the PaymentSendFailure the HTLC may have been
for (res, path) in results.iter().zip(route.paths.iter()) {
if res.is_ok() { has_ok = true; }
if res.is_err() { has_err = true; }
- if let &Err(APIError::MonitorUpdateFailed) = res {
- // MonitorUpdateFailed is inherently unsafe to retry, so we call it a
+ if let &Err(APIError::MonitorUpdateInProgress) = res {
+ // MonitorUpdateInProgress is inherently unsafe to retry, so we call it a
// PartialFailure.
has_err = true;
has_ok = true;
// Transactions are evaluated as final by network mempools at the next block. However, the modules
// constituting our Lightning node might not have perfect sync about their blockchain views. Thus, if
// the wallet module is in advance on the LDK view, allow one more block of headroom.
- // TODO: updated if/when https://github.com/rust-bitcoin/rust-bitcoin/pull/994 landed and rust-bitcoin bumped.
if !funding_transaction.input.iter().all(|input| input.sequence == Sequence::MAX) && LockTime::from(funding_transaction.lock_time).is_block_height() && funding_transaction.lock_time.0 > height + 2 {
return Err(APIError::APIMisuseError {
err: "Funding transaction absolute timelock is non-final".to_owned()
let mut phantom_receives: Vec<(u64, OutPoint, Vec<(PendingHTLCInfo, u64)>)> = Vec::new();
let mut handle_errors = Vec::new();
{
- let mut channel_state_lock = self.channel_state.lock().unwrap();
- let channel_state = &mut *channel_state_lock;
+ let mut forward_htlcs = HashMap::new();
+ mem::swap(&mut forward_htlcs, &mut self.forward_htlcs.lock().unwrap());
- for (short_chan_id, mut pending_forwards) in channel_state.forward_htlcs.drain() {
+ for (short_chan_id, mut pending_forwards) in forward_htlcs {
+ let mut channel_state_lock = self.channel_state.lock().unwrap();
+ let channel_state = &mut *channel_state_lock;
if short_chan_id != 0 {
let forward_chan_id = match channel_state.short_to_chan_info.get(&short_chan_id) {
Some((_cp_id, chan_id)) => chan_id.clone(),
continue;
}
};
- if let Err(e) = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
- handle_errors.push((chan.get().get_counterparty_node_id(), handle_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true)));
- continue;
+ match self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
+ ChannelMonitorUpdateStatus::Completed => {},
+ e => {
+ handle_errors.push((chan.get().get_counterparty_node_id(), handle_monitor_update_res!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true)));
+ continue;
+ }
}
log_debug!(self.logger, "Forwarding HTLCs resulted in a commitment update with {} HTLCs added and {} HTLCs failed for channel {}",
add_htlc_msgs.len(), fail_htlc_msgs.len(), log_bytes!(chan.get().channel_id()));
}
for (htlc_source, payment_hash, failure_reason, destination) in failed_forwards.drain(..) {
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), htlc_source, &payment_hash, failure_reason, destination);
+ self.fail_htlc_backwards_internal(htlc_source, &payment_hash, failure_reason, destination);
}
self.forward_htlcs(&mut phantom_receives);
};
let ret_err = match res {
Ok(Some((update_fee, commitment_signed, monitor_update))) => {
- if let Err(e) = self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) {
- let (res, drop) = handle_monitor_err!(self, e, short_to_chan_info, chan, RAACommitmentOrder::CommitmentFirst, chan_id, COMMITMENT_UPDATE_ONLY);
- if drop { retain_channel = false; }
- res
- } else {
- pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
- node_id: chan.get_counterparty_node_id(),
- updates: msgs::CommitmentUpdate {
- update_add_htlcs: Vec::new(),
- update_fulfill_htlcs: Vec::new(),
- update_fail_htlcs: Vec::new(),
- update_fail_malformed_htlcs: Vec::new(),
- update_fee: Some(update_fee),
- commitment_signed,
- },
- });
- Ok(())
+ match self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) {
+ ChannelMonitorUpdateStatus::Completed => {
+ pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
+ node_id: chan.get_counterparty_node_id(),
+ updates: msgs::CommitmentUpdate {
+ update_add_htlcs: Vec::new(),
+ update_fulfill_htlcs: Vec::new(),
+ update_fail_htlcs: Vec::new(),
+ update_fail_malformed_htlcs: Vec::new(),
+ update_fee: Some(update_fee),
+ commitment_signed,
+ },
+ });
+ Ok(())
+ },
+ e => {
+ let (res, drop) = handle_monitor_update_res!(self, e, short_to_chan_info, chan, RAACommitmentOrder::CommitmentFirst, chan_id, COMMITMENT_UPDATE_ONLY);
+ if drop { retain_channel = false; }
+ res
+ }
}
},
Ok(None) => Ok(()),
for htlc_source in timed_out_mpp_htlcs.drain(..) {
let receiver = HTLCDestination::FailedPayment { payment_hash: htlc_source.1 };
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), HTLCSource::PreviousHopData(htlc_source.0.clone()), &htlc_source.1, HTLCFailReason::Reason { failure_code: 23, data: Vec::new() }, receiver );
+ self.fail_htlc_backwards_internal(HTLCSource::PreviousHopData(htlc_source.0.clone()), &htlc_source.1, HTLCFailReason::Reason { failure_code: 23, data: Vec::new() }, receiver );
}
for (err, counterparty_node_id) in handle_errors.drain(..) {
pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
- let mut channel_state = Some(self.channel_state.lock().unwrap());
- let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(payment_hash);
+ let removed_source = {
+ let mut channel_state = self.channel_state.lock().unwrap();
+ channel_state.claimable_htlcs.remove(payment_hash)
+ };
if let Some((_, mut sources)) = removed_source {
for htlc in sources.drain(..) {
- if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(
self.best_block.read().unwrap().height()));
- self.fail_htlc_backwards_internal(channel_state.take().unwrap(),
+ self.fail_htlc_backwards_internal(
HTLCSource::PreviousHopData(htlc.prev_hop), payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: htlc_msat_height_data },
HTLCDestination::FailedPayment { payment_hash: *payment_hash });
counterparty_node_id: &PublicKey
) {
for (htlc_src, payment_hash) in htlcs_to_fail.drain(..) {
- let mut channel_state = self.channel_state.lock().unwrap();
let (failure_code, onion_failure_data) =
- match channel_state.by_id.entry(channel_id) {
+ match self.channel_state.lock().unwrap().by_id.entry(channel_id) {
hash_map::Entry::Occupied(chan_entry) => {
self.get_htlc_inbound_temp_fail_err_and_data(0x1000|7, &chan_entry.get())
},
};
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id.clone()), channel_id };
- self.fail_htlc_backwards_internal(channel_state, htlc_src, &payment_hash, HTLCFailReason::Reason { failure_code, data: onion_failure_data }, receiver);
+ self.fail_htlc_backwards_internal(htlc_src, &payment_hash, HTLCFailReason::Reason { failure_code, data: onion_failure_data }, receiver);
}
}
/// Fails an HTLC backwards to the sender of it to us.
- /// Note that while we take a channel_state lock as input, we do *not* assume consistency here.
- /// There are several callsites that do stupid things like loop over a list of payment_hashes
- /// to fail and take the channel_state lock for each iteration (as we take ownership and may
- /// drop it). In other words, no assumptions are made that entries in claimable_htlcs point to
- /// still-available channels.
- fn fail_htlc_backwards_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<Signer>>, source: HTLCSource, payment_hash: &PaymentHash, onion_error: HTLCFailReason, destination: HTLCDestination) {
+ /// Note that we do not assume that channels corresponding to failed HTLCs are still available.
+ fn fail_htlc_backwards_internal(&self, source: HTLCSource, payment_hash: &PaymentHash, onion_error: HTLCFailReason,destination: HTLCDestination) {
+ #[cfg(debug_assertions)]
+ {
+ // Ensure that the `channel_state` lock is not held when calling this function.
+ // This ensures that future code doesn't introduce a lock_order requirement for
+ // `forward_htlcs` to be locked after the `channel_state` lock, which calling this
+ // function with the `channel_state` locked would.
+ assert!(self.channel_state.try_lock().is_ok());
+ }
+
//TODO: There is a timing attack here where if a node fails an HTLC back to us they can
//identify whether we sent it or not based on the (I presume) very different runtime
//between the branches here. We should make this async and move it into the forward HTLCs
log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
return;
}
- mem::drop(channel_state_lock);
let mut retry = if let Some(payment_params_data) = payment_params {
let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
Some(RouteParameters {
}
} else {
events::Event::ProbeFailed {
- payment_id: payment_id,
+ payment_id,
payment_hash: payment_hash.clone(),
path: path.clone(),
short_channel_id,
if self.payment_is_probe(payment_hash, &payment_id) {
events::Event::ProbeFailed {
- payment_id: payment_id,
+ payment_id,
payment_hash: payment_hash.clone(),
path: path.clone(),
short_channel_id: Some(scid),
};
let mut forward_event = None;
- if channel_state_lock.forward_htlcs.is_empty() {
+ let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
+ if forward_htlcs.is_empty() {
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS));
}
- match channel_state_lock.forward_htlcs.entry(short_channel_id) {
+ match forward_htlcs.entry(short_channel_id) {
hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().push(HTLCForwardInfo::FailHTLC { htlc_id, err_packet });
},
entry.insert(vec!(HTLCForwardInfo::FailHTLC { htlc_id, err_packet }));
}
}
- mem::drop(channel_state_lock);
+ mem::drop(forward_htlcs);
let mut pending_events = self.pending_events.lock().unwrap();
if let Some(time) = forward_event {
pending_events.push(events::Event::PendingHTLCsForwardable {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
- let mut channel_state = Some(self.channel_state.lock().unwrap());
- let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&payment_hash);
+ let removed_source = self.channel_state.lock().unwrap().claimable_htlcs.remove(&payment_hash);
if let Some((payment_purpose, mut sources)) = removed_source {
assert!(!sources.is_empty());
let mut claimable_amt_msat = 0;
let mut expected_amt_msat = None;
let mut valid_mpp = true;
+ let mut errs = Vec::new();
+ let mut claimed_any_htlcs = false;
+ let mut channel_state_lock = self.channel_state.lock().unwrap();
+ let channel_state = &mut *channel_state_lock;
for htlc in sources.iter() {
- if let None = channel_state.as_ref().unwrap().short_to_chan_info.get(&htlc.prev_hop.short_channel_id) {
+ if let None = channel_state.short_to_chan_info.get(&htlc.prev_hop.short_channel_id) {
valid_mpp = false;
break;
}
expected_amt_msat.unwrap(), claimable_amt_msat);
return;
}
-
- let mut errs = Vec::new();
- let mut claimed_any_htlcs = false;
- for htlc in sources.drain(..) {
- if !valid_mpp {
- if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
- let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
- htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(
- self.best_block.read().unwrap().height()));
- self.fail_htlc_backwards_internal(channel_state.take().unwrap(),
- HTLCSource::PreviousHopData(htlc.prev_hop), &payment_hash,
- HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_height_data },
- HTLCDestination::FailedPayment { payment_hash } );
- } else {
- match self.claim_funds_from_hop(channel_state.as_mut().unwrap(), htlc.prev_hop, payment_preimage) {
+ if valid_mpp {
+ for htlc in sources.drain(..) {
+ match self.claim_funds_from_hop(&mut channel_state_lock, htlc.prev_hop, payment_preimage) {
ClaimFundsFromHop::MonitorUpdateFail(pk, err, _) => {
if let msgs::ErrorAction::IgnoreError = err.err.action {
// We got a temporary failure updating monitor, but will claim the
}
}
}
+ mem::drop(channel_state_lock);
+ if !valid_mpp {
+ for htlc in sources.drain(..) {
+ let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
+ htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(
+ self.best_block.read().unwrap().height()));
+ self.fail_htlc_backwards_internal(
+ HTLCSource::PreviousHopData(htlc.prev_hop), &payment_hash,
+ HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_height_data },
+ HTLCDestination::FailedPayment { payment_hash } );
+ }
+ }
if claimed_any_htlcs {
self.pending_events.lock().unwrap().push(events::Event::PaymentClaimed {
});
}
- // Now that we've done the entire above loop in one lock, we can handle any errors
- // which were generated.
- channel_state.take();
-
+ // Now we can handle any errors which were generated.
for (counterparty_node_id, err) in errs.drain(..) {
let res: Result<(), _> = Err(err);
let _ = handle_error!(self, res, counterparty_node_id);
match chan.get_mut().get_update_fulfill_htlc_and_commit(prev_hop.htlc_id, payment_preimage, &self.logger) {
Ok(msgs_monitor_option) => {
if let UpdateFulfillCommitFetch::NewClaim { msgs, htlc_value_msat, monitor_update } = msgs_monitor_option {
- if let Err(e) = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
- log_given_level!(self.logger, if e == ChannelMonitorUpdateErr::PermanentFailure { Level::Error } else { Level::Debug },
- "Failed to update channel monitor with preimage {:?}: {:?}",
- payment_preimage, e);
- return ClaimFundsFromHop::MonitorUpdateFail(
- chan.get().get_counterparty_node_id(),
- handle_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, msgs.is_some()).unwrap_err(),
- Some(htlc_value_msat)
- );
+ match self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
+ ChannelMonitorUpdateStatus::Completed => {},
+ e => {
+ log_given_level!(self.logger, if e == ChannelMonitorUpdateStatus::PermanentFailure { Level::Error } else { Level::Debug },
+ "Failed to update channel monitor with preimage {:?}: {:?}",
+ payment_preimage, e);
+ return ClaimFundsFromHop::MonitorUpdateFail(
+ chan.get().get_counterparty_node_id(),
+ handle_monitor_update_res!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, msgs.is_some()).unwrap_err(),
+ Some(htlc_value_msat)
+ );
+ }
}
if let Some((msg, commitment_signed)) = msgs {
log_debug!(self.logger, "Claiming funds for HTLC with preimage {} resulted in a commitment_signed for channel {}",
}
},
Err((e, monitor_update)) => {
- if let Err(e) = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
- log_given_level!(self.logger, if e == ChannelMonitorUpdateErr::PermanentFailure { Level::Error } else { Level::Info },
- "Failed to update channel monitor with preimage {:?} immediately prior to force-close: {:?}",
- payment_preimage, e);
+ match self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
+ ChannelMonitorUpdateStatus::Completed => {},
+ e => {
+ log_given_level!(self.logger, if e == ChannelMonitorUpdateStatus::PermanentFailure { Level::Error } else { Level::Info },
+ "Failed to update channel monitor with preimage {:?} immediately prior to force-close: {:?}",
+ payment_preimage, e);
+ },
}
let counterparty_node_id = chan.get().get_counterparty_node_id();
let (drop, res) = convert_chan_err!(self, e, channel_state.short_to_chan_info, chan.get_mut(), &chan_id);
// We update the ChannelMonitor on the backward link, after
// receiving an offchain preimage event from the forward link (the
// event being update_fulfill_htlc).
- if let Err(e) = self.chain_monitor.update_channel(prev_outpoint, preimage_update) {
+ let update_res = self.chain_monitor.update_channel(prev_outpoint, preimage_update);
+ if update_res != ChannelMonitorUpdateStatus::Completed {
+ // TODO: This needs to be handled somehow - if we receive a monitor update
+ // with a preimage we *must* somehow manage to propagate it to the upstream
+ // channel, or we must have an ability to receive the same event and try
+ // again on restart.
log_error!(self.logger, "Critical error: failed to update channel monitor with preimage {:?}: {:?}",
- payment_preimage, e);
+ payment_preimage, update_res);
}
// Note that we do *not* set `claimed_htlc` to false here. In fact, this
// totally could be a duplicate claim, but we have no way of knowing
self.finalize_claims(finalized_claims);
for failure in pending_failures.drain(..) {
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id: funding_txo.to_channel_id() };
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), failure.0, &failure.1, failure.2, receiver);
+ self.fail_htlc_backwards_internal(failure.0, &failure.1, failure.2, receiver);
}
}
};
// Because we have exclusive ownership of the channel here we can release the channel_state
// lock before watch_channel
- if let Err(e) = self.chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor) {
- match e {
- ChannelMonitorUpdateErr::PermanentFailure => {
- // Note that we reply with the new channel_id in error messages if we gave up on the
- // channel, not the temporary_channel_id. This is compatible with ourselves, but the
- // spec is somewhat ambiguous here. Not a huge deal since we'll send error messages for
- // any messages referencing a previously-closed channel anyway.
- // We do not do a force-close here as that would generate a monitor update for
- // a monitor that we didn't manage to store (and that we don't care about - we
- // don't respond with the funding_signed so the channel can never go on chain).
- let (_monitor_update, failed_htlcs) = chan.force_shutdown(true);
- assert!(failed_htlcs.is_empty());
- return Err(MsgHandleErrInternal::send_err_msg_no_close("ChannelMonitor storage failure".to_owned(), funding_msg.channel_id));
- },
- ChannelMonitorUpdateErr::TemporaryFailure => {
- // There's no problem signing a counterparty's funding transaction if our monitor
- // hasn't persisted to disk yet - we can't lose money on a transaction that we haven't
- // accepted payment from yet. We do, however, need to wait to send our channel_ready
- // until we have persisted our monitor.
- chan.monitor_update_failed(false, false, channel_ready.is_some(), Vec::new(), Vec::new(), Vec::new());
- channel_ready = None; // Don't send the channel_ready now
- },
- }
+ match self.chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor) {
+ ChannelMonitorUpdateStatus::Completed => {},
+ ChannelMonitorUpdateStatus::PermanentFailure => {
+ // Note that we reply with the new channel_id in error messages if we gave up on the
+ // channel, not the temporary_channel_id. This is compatible with ourselves, but the
+ // spec is somewhat ambiguous here. Not a huge deal since we'll send error messages for
+ // any messages referencing a previously-closed channel anyway.
+ // We do not propagate the monitor update to the user as it would be for a monitor
+ // that we didn't manage to store (and that we don't care about - we don't respond
+ // with the funding_signed so the channel can never go on chain).
+ let (_monitor_update, failed_htlcs) = chan.force_shutdown(false);
+ assert!(failed_htlcs.is_empty());
+ return Err(MsgHandleErrInternal::send_err_msg_no_close("ChannelMonitor storage failure".to_owned(), funding_msg.channel_id));
+ },
+ ChannelMonitorUpdateStatus::InProgress => {
+ // There's no problem signing a counterparty's funding transaction if our monitor
+ // hasn't persisted to disk yet - we can't lose money on a transaction that we haven't
+ // accepted payment from yet. We do, however, need to wait to send our channel_ready
+ // until we have persisted our monitor.
+ chan.monitor_updating_paused(false, false, channel_ready.is_some(), Vec::new(), Vec::new(), Vec::new());
+ channel_ready = None; // Don't send the channel_ready now
+ },
}
let mut channel_state_lock = self.channel_state.lock().unwrap();
let channel_state = &mut *channel_state_lock;
Ok(update) => update,
Err(e) => try_chan_entry!(self, Err(e), channel_state, chan),
};
- if let Err(e) = self.chain_monitor.watch_channel(chan.get().get_funding_txo().unwrap(), monitor) {
- let mut res = handle_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::RevokeAndACKFirst, channel_ready.is_some(), OPTIONALLY_RESEND_FUNDING_LOCKED);
- if let Err(MsgHandleErrInternal { ref mut shutdown_finish, .. }) = res {
- // We weren't able to watch the channel to begin with, so no updates should be made on
- // it. Previously, full_stack_target found an (unreachable) panic when the
- // monitor update contained within `shutdown_finish` was applied.
- if let Some((ref mut shutdown_finish, _)) = shutdown_finish {
- shutdown_finish.0.take();
+ match self.chain_monitor.watch_channel(chan.get().get_funding_txo().unwrap(), monitor) {
+ ChannelMonitorUpdateStatus::Completed => {},
+ e => {
+ let mut res = handle_monitor_update_res!(self, e, channel_state, chan, RAACommitmentOrder::RevokeAndACKFirst, channel_ready.is_some(), OPTIONALLY_RESEND_FUNDING_LOCKED);
+ if let Err(MsgHandleErrInternal { ref mut shutdown_finish, .. }) = res {
+ // We weren't able to watch the channel to begin with, so no updates should be made on
+ // it. Previously, full_stack_target found an (unreachable) panic when the
+ // monitor update contained within `shutdown_finish` was applied.
+ if let Some((ref mut shutdown_finish, _)) = shutdown_finish {
+ shutdown_finish.0.take();
+ }
}
- }
- return res
+ return res
+ },
}
if let Some(msg) = channel_ready {
send_channel_ready!(channel_state.short_to_chan_info, channel_state.pending_msg_events, chan.get(), msg);
// Update the monitor with the shutdown script if necessary.
if let Some(monitor_update) = monitor_update {
- if let Err(e) = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update) {
- let (result, is_permanent) =
- handle_monitor_err!(self, e, channel_state.short_to_chan_info, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
- if is_permanent {
- remove_channel!(self, channel_state, chan_entry);
- break result;
- }
+ let update_res = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update);
+ let (result, is_permanent) =
+ handle_monitor_update_res!(self, update_res, channel_state.short_to_chan_info, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
+ if is_permanent {
+ remove_channel!(self, channel_state, chan_entry);
+ break result;
}
}
};
for htlc_source in dropped_htlcs.drain(..) {
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id.clone()), channel_id: msg.channel_id };
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), htlc_source.0, &htlc_source.1, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
+ self.fail_htlc_backwards_internal(htlc_source.0, &htlc_source.1, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
}
let _ = handle_error!(self, result, *counterparty_node_id);
},
Ok(res) => res
};
- if let Err(e) = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
- return_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::RevokeAndACKFirst, true, commitment_signed.is_some());
+ let update_res = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update);
+ if let Err(e) = handle_monitor_update_res!(self, update_res, channel_state, chan, RAACommitmentOrder::RevokeAndACKFirst, true, commitment_signed.is_some()) {
+ return Err(e);
}
+
channel_state.pending_msg_events.push(events::MessageSendEvent::SendRevokeAndACK {
node_id: counterparty_node_id.clone(),
msg: revoke_and_ack,
for &mut (prev_short_channel_id, prev_funding_outpoint, ref mut pending_forwards) in per_source_pending_forwards {
let mut forward_event = None;
if !pending_forwards.is_empty() {
- let mut channel_state = self.channel_state.lock().unwrap();
- if channel_state.forward_htlcs.is_empty() {
+ let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
+ if forward_htlcs.is_empty() {
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS))
}
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
- match channel_state.forward_htlcs.entry(match forward_info.routing {
+ match forward_htlcs.entry(match forward_info.routing {
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
PendingHTLCRouting::Receive { .. } => 0,
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
break Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
- let was_frozen_for_monitor = chan.get().is_awaiting_monitor_update();
+ let was_paused_for_mon_update = chan.get().is_awaiting_monitor_update();
let raa_updates = break_chan_entry!(self,
chan.get_mut().revoke_and_ack(&msg, &self.logger), channel_state, chan);
htlcs_to_fail = raa_updates.holding_cell_failed_htlcs;
- if let Err(e) = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), raa_updates.monitor_update) {
- if was_frozen_for_monitor {
- assert!(raa_updates.commitment_update.is_none());
- assert!(raa_updates.accepted_htlcs.is_empty());
- assert!(raa_updates.failed_htlcs.is_empty());
- assert!(raa_updates.finalized_claimed_htlcs.is_empty());
- break Err(MsgHandleErrInternal::ignore_no_close("Previous monitor update failure prevented responses to RAA".to_owned()));
- } else {
- if let Err(e) = handle_monitor_err!(self, e, channel_state, chan,
- RAACommitmentOrder::CommitmentFirst, false,
- raa_updates.commitment_update.is_some(), false,
- raa_updates.accepted_htlcs, raa_updates.failed_htlcs,
- raa_updates.finalized_claimed_htlcs) {
- break Err(e);
- } else { unreachable!(); }
- }
+ let update_res = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), raa_updates.monitor_update);
+ if was_paused_for_mon_update {
+ assert!(update_res != ChannelMonitorUpdateStatus::Completed);
+ assert!(raa_updates.commitment_update.is_none());
+ assert!(raa_updates.accepted_htlcs.is_empty());
+ assert!(raa_updates.failed_htlcs.is_empty());
+ assert!(raa_updates.finalized_claimed_htlcs.is_empty());
+ break Err(MsgHandleErrInternal::ignore_no_close("Existing pending monitor update prevented responses to RAA".to_owned()));
+ }
+ if update_res != ChannelMonitorUpdateStatus::Completed {
+ if let Err(e) = handle_monitor_update_res!(self, update_res, channel_state, chan,
+ RAACommitmentOrder::CommitmentFirst, false,
+ raa_updates.commitment_update.is_some(), false,
+ raa_updates.accepted_htlcs, raa_updates.failed_htlcs,
+ raa_updates.finalized_claimed_htlcs) {
+ break Err(e);
+ } else { unreachable!(); }
}
if let Some(updates) = raa_updates.commitment_update {
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
{
for failure in pending_failures.drain(..) {
let receiver = HTLCDestination::NextHopChannel { node_id: Some(*counterparty_node_id), channel_id: channel_outpoint.to_channel_id() };
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), failure.0, &failure.1, failure.2, receiver);
+ self.fail_htlc_backwards_internal(failure.0, &failure.1, failure.2, receiver);
}
self.forward_htlcs(&mut [(short_channel_id, channel_outpoint, pending_forwards)]);
self.finalize_claims(finalized_claim_htlcs);
} else {
log_trace!(self.logger, "Failing HTLC with hash {} from our monitor", log_bytes!(htlc_update.payment_hash.0));
let receiver = HTLCDestination::NextHopChannel { node_id: counterparty_node_id, channel_id: funding_outpoint.to_channel_id() };
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), htlc_update.source, &htlc_update.payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
+ self.fail_htlc_backwards_internal(htlc_update.source, &htlc_update.payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
}
},
MonitorEvent::CommitmentTxConfirmed(funding_outpoint) |
});
}
},
- MonitorEvent::UpdateCompleted { funding_txo, monitor_update_id } => {
+ MonitorEvent::Completed { funding_txo, monitor_update_id } => {
self.channel_monitor_updated(&funding_txo, monitor_update_id);
},
}
));
}
if let Some((commitment_update, monitor_update)) = commitment_opt {
- if let Err(e) = self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) {
- has_monitor_update = true;
- let (res, close_channel) = handle_monitor_err!(self, e, short_to_chan_info, chan, RAACommitmentOrder::CommitmentFirst, channel_id, COMMITMENT_UPDATE_ONLY);
- handle_errors.push((chan.get_counterparty_node_id(), res));
- if close_channel { return false; }
- } else {
- pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
- node_id: chan.get_counterparty_node_id(),
- updates: commitment_update,
- });
+ match self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) {
+ ChannelMonitorUpdateStatus::Completed => {
+ pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
+ node_id: chan.get_counterparty_node_id(),
+ updates: commitment_update,
+ });
+ },
+ e => {
+ has_monitor_update = true;
+ let (res, close_channel) = handle_monitor_update_res!(self, e, short_to_chan_info, chan, RAACommitmentOrder::CommitmentFirst, channel_id, COMMITMENT_UPDATE_ONLY);
+ handle_errors.push((chan.get_counterparty_node_id(), res));
+ if close_channel { return false; }
+ },
}
}
true
self.handle_init_event_channel_failures(failed_channels);
for (source, payment_hash, reason, destination) in timed_out_htlcs.drain(..) {
- self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, reason, destination);
+ self.fail_htlc_backwards_internal(source, &payment_hash, reason, destination);
}
}
}
}
- fn peer_connected(&self, counterparty_node_id: &PublicKey, init_msg: &msgs::Init) {
+ fn peer_connected(&self, counterparty_node_id: &PublicKey, init_msg: &msgs::Init) -> Result<(), ()> {
+ if !init_msg.features.supports_static_remote_key() {
+ log_debug!(self.logger, "Peer {} does not support static remote key, disconnecting with no_connection_possible", log_pubkey!(counterparty_node_id));
+ return Err(());
+ }
+
log_debug!(self.logger, "Generating channel_reestablish events for {}", log_pubkey!(counterparty_node_id));
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
retain
});
//TODO: Also re-broadcast announcement_signatures
+ Ok(())
}
fn handle_error(&self, counterparty_node_id: &PublicKey, msg: &msgs::ErrorMessage) {
}
fn provided_node_features(&self) -> NodeFeatures {
- NodeFeatures::known_channel_features()
+ provided_node_features()
}
fn provided_init_features(&self, _their_init_features: &PublicKey) -> InitFeatures {
- InitFeatures::known_channel_features()
+ provided_init_features()
}
}
+/// Fetches the set of [`NodeFeatures`] flags which are provided by or required by
+/// [`ChannelManager`].
+pub fn provided_node_features() -> NodeFeatures {
+ provided_init_features().to_context()
+}
+
+/// Fetches the set of [`InvoiceFeatures`] flags which are provided by or required by
+/// [`ChannelManager`].
+///
+/// Note that the invoice feature flags can vary depending on if the invoice is a "phantom invoice"
+/// or not. Thus, this method is not public.
+#[cfg(any(feature = "_test_utils", test))]
+pub fn provided_invoice_features() -> InvoiceFeatures {
+ provided_init_features().to_context()
+}
+
+/// Fetches the set of [`ChannelFeatures`] flags which are provided by or required by
+/// [`ChannelManager`].
+pub fn provided_channel_features() -> ChannelFeatures {
+ provided_init_features().to_context()
+}
+
+/// Fetches the set of [`InitFeatures`] flags which are provided by or required by
+/// [`ChannelManager`].
+pub fn provided_init_features() -> InitFeatures {
+ // Note that if new features are added here which other peers may (eventually) require, we
+ // should also add the corresponding (optional) bit to the ChannelMessageHandler impl for
+ // ErroringMessageHandler.
+ let mut features = InitFeatures::empty();
+ features.set_data_loss_protect_optional();
+ features.set_upfront_shutdown_script_optional();
+ features.set_variable_length_onion_required();
+ features.set_static_remote_key_required();
+ features.set_payment_secret_required();
+ features.set_basic_mpp_optional();
+ features.set_wumbo_optional();
+ features.set_shutdown_any_segwit_optional();
+ features.set_channel_type_optional();
+ features.set_scid_privacy_optional();
+ features.set_zero_conf_optional();
+ features
+}
+
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
}
Ok(HTLCSource::OutboundRoute {
session_priv: session_priv.0.unwrap(),
- first_hop_htlc_msat: first_hop_htlc_msat,
+ first_hop_htlc_msat,
path: path.unwrap(),
payment_id: payment_id.unwrap(),
payment_secret,
best_block.block_hash().write(writer)?;
}
- let channel_state = self.channel_state.lock().unwrap();
- let mut unfunded_channels = 0;
- for (_, channel) in channel_state.by_id.iter() {
- if !channel.is_funding_initiated() {
- unfunded_channels += 1;
+ {
+ // Take `channel_state` lock temporarily to avoid creating a lock order that requires
+ // that the `forward_htlcs` lock is taken after `channel_state`
+ let channel_state = self.channel_state.lock().unwrap();
+ let mut unfunded_channels = 0;
+ for (_, channel) in channel_state.by_id.iter() {
+ if !channel.is_funding_initiated() {
+ unfunded_channels += 1;
+ }
}
- }
- ((channel_state.by_id.len() - unfunded_channels) as u64).write(writer)?;
- for (_, channel) in channel_state.by_id.iter() {
- if channel.is_funding_initiated() {
- channel.write(writer)?;
+ ((channel_state.by_id.len() - unfunded_channels) as u64).write(writer)?;
+ for (_, channel) in channel_state.by_id.iter() {
+ if channel.is_funding_initiated() {
+ channel.write(writer)?;
+ }
}
}
- (channel_state.forward_htlcs.len() as u64).write(writer)?;
- for (short_channel_id, pending_forwards) in channel_state.forward_htlcs.iter() {
- short_channel_id.write(writer)?;
- (pending_forwards.len() as u64).write(writer)?;
- for forward in pending_forwards {
- forward.write(writer)?;
+ {
+ let forward_htlcs = self.forward_htlcs.lock().unwrap();
+ (forward_htlcs.len() as u64).write(writer)?;
+ for (short_channel_id, pending_forwards) in forward_htlcs.iter() {
+ short_channel_id.write(writer)?;
+ (pending_forwards.len() as u64).write(writer)?;
+ for forward in pending_forwards {
+ forward.write(writer)?;
+ }
}
}
+ let channel_state = self.channel_state.lock().unwrap();
let mut htlc_purposes: Vec<&events::PaymentPurpose> = Vec::new();
(channel_state.claimable_htlcs.len() as u64).write(writer)?;
for (payment_hash, (purpose, previous_hops)) in channel_state.claimable_htlcs.iter() {
channel_state: Mutex::new(ChannelHolder {
by_id,
short_to_chan_info,
- forward_htlcs,
claimable_htlcs,
pending_msg_events: Vec::new(),
}),
pending_inbound_payments: Mutex::new(pending_inbound_payments),
pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
+ forward_htlcs: Mutex::new(forward_htlcs),
outbound_scid_aliases: Mutex::new(outbound_scid_aliases),
id_to_peer: Mutex::new(id_to_peer),
fake_scid_rand_bytes: fake_scid_rand_bytes.unwrap(),
for htlc_source in failed_htlcs.drain(..) {
let (source, payment_hash, counterparty_node_id, channel_id) = htlc_source;
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
- channel_manager.fail_htlc_backwards_internal(channel_manager.channel_state.lock().unwrap(), source, &payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
+ channel_manager.fail_htlc_backwards_internal(source, &payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 8, data: Vec::new() }, receiver);
}
//TODO: Broadcast channel update for closed channels, but only after we've made a
use core::time::Duration;
use core::sync::atomic::Ordering;
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
- use ln::channelmanager::{PaymentId, PaymentSendFailure};
- use ln::channelmanager::inbound_payment;
- use ln::features::InitFeatures;
+ use ln::channelmanager::{self, inbound_payment, PaymentId, PaymentSendFailure};
use ln::functional_test_utils::*;
use ln::msgs;
use ln::msgs::ChannelMessageHandler;
assert!(nodes[1].node.await_persistable_update_timeout(Duration::from_millis(1)));
assert!(nodes[2].node.await_persistable_update_timeout(Duration::from_millis(1)));
- let mut chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let mut chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// We check that the channel info nodes have doesn't change too early, even though we try
// to connect messages with new values
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// First, send a partial MPP payment.
let (route, our_payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[1], 100_000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
let payer_pubkey = nodes[0].node.get_our_node_id();
let payee_pubkey = nodes[1].node.get_our_node_id();
- nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
- let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known());
+ let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], channelmanager::provided_init_features(), channelmanager::provided_init_features());
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(payee_pubkey),
final_value_msat: 10000,
let payer_pubkey = nodes[0].node.get_our_node_id();
let payee_pubkey = nodes[1].node.get_our_node_id();
- nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
- let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known());
+ let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], channelmanager::provided_init_features(), channelmanager::provided_init_features());
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(payee_pubkey),
final_value_msat: 10000,
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
// Marshall an MPP route.
let (mut route, payment_hash, _, _) = get_route_and_payment_hash!(&nodes[0], nodes[3], 100000);
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let (temporary_channel_id, tx, _funding_output) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42);
let channel_id = &tx.txid().into_inner();
update_nodes_with_chan_announce(&nodes, 0, 1, &announcement, &nodes_0_update, &nodes_1_update);
nodes[0].node.close_channel(channel_id, &nodes[1].node.get_our_node_id()).unwrap();
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()));
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()));
let nodes_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &nodes_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &nodes_1_shutdown);
let closing_signed_node_0 = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &closing_signed_node_0);
use chain::Listen;
use chain::chainmonitor::{ChainMonitor, Persist};
use chain::keysinterface::{KeysManager, KeysInterface, InMemorySigner};
- use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage};
+ use ln::channelmanager::{self, BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage};
use ln::features::{InitFeatures, InvoiceFeatures};
use ln::functional_test_utils::*;
use ln::msgs::{ChannelMessageHandler, Init};
});
let node_b_holder = NodeHolder { node: &node_b };
- node_a.peer_connected(&node_b.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
- node_b.peer_connected(&node_a.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None });
+ node_a.peer_connected(&node_b.get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ node_b.peer_connected(&node_a.get_our_node_id(), &Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None).unwrap();
- node_b.handle_open_channel(&node_a.get_our_node_id(), InitFeatures::known(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id()));
- node_a.handle_accept_channel(&node_b.get_our_node_id(), InitFeatures::known(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id()));
+ node_b.handle_open_channel(&node_a.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id()));
+ node_a.handle_accept_channel(&node_b.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id()));
let tx;
if let Event::FundingGenerationReady { temporary_channel_id, output_script, .. } = get_event!(node_a_holder, Event::FundingGenerationReady) {
($node_a: expr, $node_b: expr) => {
let usable_channels = $node_a.list_usable_channels();
let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let seed = [3u8; 32];
let keys_manager = KeysManager::new(&seed, 42, 42);
use prelude::*;
use ln::features::Features;
- /// The context in which [`Features`] are applicable. Defines which features are required and
- /// which are optional for the context.
+ /// The context in which [`Features`] are applicable. Defines which features are known to the
+ /// implementation, though specification of them as required or optional is up to the code
+ /// constructing a features object.
pub trait Context {
- /// Features that are known to the implementation, where a required feature is indicated by
- /// its even bit and an optional feature is indicated by its odd bit.
- const KNOWN_FEATURE_FLAGS: &'static [u8];
-
- /// Bitmask for selecting features that are known to the implementation, regardless of
- /// whether each feature is required or optional.
+ /// Bitmask for selecting features that are known to the implementation.
const KNOWN_FEATURE_MASK: &'static [u8];
}
/// are specified as a comma-separated list of bytes where each byte is a pipe-delimited list of
/// feature identifiers.
macro_rules! define_context {
- ($context: ident {
- required_features: [$( $( $required_feature: ident )|*, )*],
- optional_features: [$( $( $optional_feature: ident )|*, )*],
- }) => {
+ ($context: ident, [$( $( $known_feature: ident )|*, )*]) => {
#[derive(Eq, PartialEq)]
pub struct $context {}
impl Context for $context {
- const KNOWN_FEATURE_FLAGS: &'static [u8] = &[
- // For each byte, use bitwise-OR to compute the applicable flags for known
- // required features `r_i` and optional features `o_j` for all `i` and `j` such
- // that the following slice is formed:
- //
- // [
- // `r_0` | `r_1` | ... | `o_0` | `o_1` | ...,
- // ...,
- // ]
- $(
- 0b00_00_00_00 $(|
- <Self as $required_feature>::REQUIRED_MASK)*
- $(|
- <Self as $optional_feature>::OPTIONAL_MASK)*,
- )*
- ];
-
const KNOWN_FEATURE_MASK: &'static [u8] = &[
- // Similar as above, but set both flags for each feature regardless of whether
- // the feature is required or optional.
$(
0b00_00_00_00 $(|
- <Self as $required_feature>::REQUIRED_MASK |
- <Self as $required_feature>::OPTIONAL_MASK)*
- $(|
- <Self as $optional_feature>::REQUIRED_MASK |
- <Self as $optional_feature>::OPTIONAL_MASK)*,
+ <Self as $known_feature>::REQUIRED_MASK |
+ <Self as $known_feature>::OPTIONAL_MASK)*,
)*
];
}
fn fmt(&self, fmt: &mut alloc::fmt::Formatter) -> Result<(), alloc::fmt::Error> {
$(
$(
- fmt.write_fmt(format_args!("{}: {}, ", stringify!($required_feature),
- if <$context as $required_feature>::requires_feature(&self.flags) { "required" }
- else if <$context as $required_feature>::supports_feature(&self.flags) { "supported" }
- else { "not supported" }))?;
- )*
- $(
- fmt.write_fmt(format_args!("{}: {}, ", stringify!($optional_feature),
- if <$context as $optional_feature>::requires_feature(&self.flags) { "required" }
- else if <$context as $optional_feature>::supports_feature(&self.flags) { "supported" }
+ fmt.write_fmt(format_args!("{}: {}, ", stringify!($known_feature),
+ if <$context as $known_feature>::requires_feature(&self.flags) { "required" }
+ else if <$context as $known_feature>::supports_feature(&self.flags) { "supported" }
else { "not supported" }))?;
)*
+ {} // Rust gets mad if we only have a $()* block here, so add a dummy {}
)*
fmt.write_fmt(format_args!("unknown flags: {}",
if self.requires_unknown_bits() { "required" }
};
}
- define_context!(InitContext {
- required_features: [
- // Byte 0
- ,
- // Byte 1
- VariableLengthOnion | StaticRemoteKey | PaymentSecret,
- // Byte 2
- ,
- // Byte 3
- ,
- // Byte 4
- ,
- // Byte 5
- ,
- // Byte 6
- ,
- ],
- optional_features: [
- // Note that if new "non-channel-related" flags are added here they should be
- // explicitly cleared in InitFeatures::known_channel_features and
- // NodeFeatures::known_channel_features.
- // Byte 0
- DataLossProtect | InitialRoutingSync | UpfrontShutdownScript | GossipQueries,
- // Byte 1
- ,
- // Byte 2
- BasicMPP | Wumbo,
- // Byte 3
- ShutdownAnySegwit,
- // Byte 4
- OnionMessages,
- // Byte 5
- ChannelType | SCIDPrivacy,
- // Byte 6
- ZeroConf,
- ],
- });
- define_context!(NodeContext {
- required_features: [
- // Byte 0
- ,
- // Byte 1
- VariableLengthOnion | StaticRemoteKey | PaymentSecret,
- // Byte 2
- ,
- // Byte 3
- ,
- // Byte 4
- ,
- // Byte 5
- ,
- // Byte 6
- ,
- ],
- optional_features: [
- // Byte 0
- DataLossProtect | UpfrontShutdownScript | GossipQueries,
- // Byte 1
- ,
- // Byte 2
- BasicMPP | Wumbo,
- // Byte 3
- ShutdownAnySegwit,
- // Byte 4
- OnionMessages,
- // Byte 5
- ChannelType | SCIDPrivacy,
- // Byte 6
- ZeroConf | Keysend,
- ],
- });
- define_context!(ChannelContext {
- required_features: [],
- optional_features: [],
- });
- define_context!(InvoiceContext {
- required_features: [
- // Byte 0
- ,
- // Byte 1
- VariableLengthOnion | PaymentSecret,
- // Byte 2
- ,
- ],
- optional_features: [
- // Byte 0
- ,
- // Byte 1
- ,
- // Byte 2
- BasicMPP,
- ],
- });
+ define_context!(InitContext, [
+ // Byte 0
+ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript | GossipQueries,
+ // Byte 1
+ VariableLengthOnion | StaticRemoteKey | PaymentSecret,
+ // Byte 2
+ BasicMPP | Wumbo,
+ // Byte 3
+ ShutdownAnySegwit,
+ // Byte 4
+ OnionMessages,
+ // Byte 5
+ ChannelType | SCIDPrivacy,
+ // Byte 6
+ ZeroConf,
+ ]);
+ define_context!(NodeContext, [
+ // Byte 0
+ DataLossProtect | UpfrontShutdownScript | GossipQueries,
+ // Byte 1
+ VariableLengthOnion | StaticRemoteKey | PaymentSecret,
+ // Byte 2
+ BasicMPP | Wumbo,
+ // Byte 3
+ ShutdownAnySegwit,
+ // Byte 4
+ OnionMessages,
+ // Byte 5
+ ChannelType | SCIDPrivacy,
+ // Byte 6
+ ZeroConf | Keysend,
+ ]);
+ define_context!(ChannelContext, []);
+ define_context!(InvoiceContext, [
+ // Byte 0
+ ,
+ // Byte 1
+ VariableLengthOnion | PaymentSecret,
+ // Byte 2
+ BasicMPP,
+ ]);
// This isn't a "real" feature context, and is only used in the channel_type field in an
// `OpenChannel` message.
- define_context!(ChannelTypeContext {
- required_features: [
- // Byte 0
- ,
- // Byte 1
- StaticRemoteKey,
- // Byte 2
- ,
- // Byte 3
- ,
- // Byte 4
- ,
- // Byte 5
- SCIDPrivacy,
- // Byte 6
- ZeroConf,
- ],
- optional_features: [
- // Byte 0
- ,
- // Byte 1
- ,
- // Byte 2
- ,
- // Byte 3
- ,
- // Byte 4
- ,
- // Byte 5
- ,
- // Byte 6
- ,
- ],
- });
+ define_context!(ChannelTypeContext, [
+ // Byte 0
+ ,
+ // Byte 1
+ StaticRemoteKey,
+ // Byte 2
+ ,
+ // Byte 3
+ ,
+ // Byte 4
+ ,
+ // Byte 5
+ SCIDPrivacy,
+ // Byte 6
+ ZeroConf,
+ ]);
/// Defines a feature with the given bits for the specified [`Context`]s. The generated trait is
/// useful for manipulating feature flags.
/// [`ODD_BIT`]: #associatedconstant.ODD_BIT
const ASSERT_ODD_BIT_PARITY: usize;
+ /// Assertion that the bits are set in the context's [`KNOWN_FEATURE_MASK`].
+ ///
+ /// [`KNOWN_FEATURE_MASK`]: Context::KNOWN_FEATURE_MASK
+ #[cfg(not(test))] // We violate this constraint with `UnknownFeature`
+ const ASSERT_BITS_IN_MASK: u8;
+
/// The byte where the feature is set.
const BYTE_OFFSET: usize = Self::EVEN_BIT / 8;
// ODD_BIT % 2 == 1
const ASSERT_ODD_BIT_PARITY: usize = (<Self as $feature>::ODD_BIT % 2) - 1;
+
+ // (byte & (REQUIRED_MASK | OPTIONAL_MASK)) >> (EVEN_BIT % 8) == 3
+ #[cfg(not(test))] // We violate this constraint with `UnknownFeature`
+ const ASSERT_BITS_IN_MASK: u8 =
+ ((<$context>::KNOWN_FEATURE_MASK[<Self as $feature>::BYTE_OFFSET] & (<Self as $feature>::REQUIRED_MASK | <Self as $feature>::OPTIONAL_MASK))
+ >> (<Self as $feature>::EVEN_BIT % 8)) - 3;
}
)*
};
pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
self.to_context_internal()
}
-
- /// Returns the set of known init features that are related to channels. At least some of
- /// these features are likely required for peers to talk to us.
- pub fn known_channel_features() -> InitFeatures {
- Self::known()
- .clear_initial_routing_sync()
- .clear_gossip_queries()
- .clear_onion_messages()
- }
-}
-
-impl NodeFeatures {
- /// Returns the set of known node features that are related to channels.
- pub fn known_channel_features() -> NodeFeatures {
- Self::known()
- .clear_gossip_queries()
- .clear_onion_messages()
- }
}
impl InvoiceFeatures {
}
}
- /// Creates a Features with the bits set which are known by the implementation
- pub fn known() -> Self {
- Self {
- flags: T::KNOWN_FEATURE_FLAGS.to_vec(),
- mark: PhantomData,
- }
- }
-
/// Converts `Features<T>` to `Features<C>`. Only known `T` features relevant to context `C` are
/// included in the result.
fn to_context_internal<C: sealed::Context>(&self) -> Features<C> {
}
}
-
-impl<T: sealed::GossipQueries> Features<T> {
- pub(crate) fn clear_gossip_queries(mut self) -> Self {
- <T as sealed::GossipQueries>::clear_bits(&mut self.flags);
- self
- }
-}
-
-impl<T: sealed::InitialRoutingSync> Features<T> {
- // Note that initial_routing_sync is ignored if gossip_queries is set.
- pub(crate) fn clear_initial_routing_sync(mut self) -> Self {
- <T as sealed::InitialRoutingSync>::clear_bits(&mut self.flags);
- self
- }
-}
-
-impl<T: sealed::OnionMessages> Features<T> {
- pub(crate) fn clear_onion_messages(mut self) -> Self {
- <T as sealed::OnionMessages>::clear_bits(&mut self.flags);
- self
- }
-}
-
impl<T: sealed::ShutdownAnySegwit> Features<T> {
#[cfg(test)]
pub(crate) fn clear_shutdown_anysegwit(mut self) -> Self {
#[cfg(test)]
mod tests {
- use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
+ use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures, sealed};
use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5};
- #[test]
- fn sanity_test_known_features() {
- assert!(!ChannelFeatures::known().requires_unknown_bits());
- assert!(!ChannelFeatures::known().supports_unknown_bits());
- assert!(!InitFeatures::known().requires_unknown_bits());
- assert!(!InitFeatures::known().supports_unknown_bits());
- assert!(!NodeFeatures::known().requires_unknown_bits());
- assert!(!NodeFeatures::known().supports_unknown_bits());
-
- assert!(InitFeatures::known().supports_upfront_shutdown_script());
- assert!(NodeFeatures::known().supports_upfront_shutdown_script());
- assert!(!InitFeatures::known().requires_upfront_shutdown_script());
- assert!(!NodeFeatures::known().requires_upfront_shutdown_script());
-
- assert!(InitFeatures::known().supports_gossip_queries());
- assert!(NodeFeatures::known().supports_gossip_queries());
- assert!(!InitFeatures::known().requires_gossip_queries());
- assert!(!NodeFeatures::known().requires_gossip_queries());
-
- assert!(InitFeatures::known().supports_data_loss_protect());
- assert!(NodeFeatures::known().supports_data_loss_protect());
- assert!(!InitFeatures::known().requires_data_loss_protect());
- assert!(!NodeFeatures::known().requires_data_loss_protect());
-
- assert!(InitFeatures::known().supports_variable_length_onion());
- assert!(NodeFeatures::known().supports_variable_length_onion());
- assert!(InvoiceFeatures::known().supports_variable_length_onion());
- assert!(InitFeatures::known().requires_variable_length_onion());
- assert!(NodeFeatures::known().requires_variable_length_onion());
- assert!(InvoiceFeatures::known().requires_variable_length_onion());
-
- assert!(InitFeatures::known().supports_static_remote_key());
- assert!(NodeFeatures::known().supports_static_remote_key());
- assert!(InitFeatures::known().requires_static_remote_key());
- assert!(NodeFeatures::known().requires_static_remote_key());
-
- assert!(InitFeatures::known().supports_payment_secret());
- assert!(NodeFeatures::known().supports_payment_secret());
- assert!(InvoiceFeatures::known().supports_payment_secret());
- assert!(InitFeatures::known().requires_payment_secret());
- assert!(NodeFeatures::known().requires_payment_secret());
- assert!(InvoiceFeatures::known().requires_payment_secret());
-
- assert!(InitFeatures::known().supports_basic_mpp());
- assert!(NodeFeatures::known().supports_basic_mpp());
- assert!(InvoiceFeatures::known().supports_basic_mpp());
- assert!(!InitFeatures::known().requires_basic_mpp());
- assert!(!NodeFeatures::known().requires_basic_mpp());
- assert!(!InvoiceFeatures::known().requires_basic_mpp());
-
- assert!(InitFeatures::known().supports_channel_type());
- assert!(NodeFeatures::known().supports_channel_type());
- assert!(!InitFeatures::known().requires_channel_type());
- assert!(!NodeFeatures::known().requires_channel_type());
-
- assert!(InitFeatures::known().supports_shutdown_anysegwit());
- assert!(NodeFeatures::known().supports_shutdown_anysegwit());
-
- assert!(InitFeatures::known().supports_scid_privacy());
- assert!(NodeFeatures::known().supports_scid_privacy());
- assert!(ChannelTypeFeatures::known().supports_scid_privacy());
- assert!(!InitFeatures::known().requires_scid_privacy());
- assert!(!NodeFeatures::known().requires_scid_privacy());
- assert!(ChannelTypeFeatures::known().requires_scid_privacy());
-
- assert!(InitFeatures::known().supports_wumbo());
- assert!(NodeFeatures::known().supports_wumbo());
- assert!(!InitFeatures::known().requires_wumbo());
- assert!(!NodeFeatures::known().requires_wumbo());
-
- assert!(InitFeatures::known().supports_onion_messages());
- assert!(NodeFeatures::known().supports_onion_messages());
- assert!(!InitFeatures::known().requires_onion_messages());
- assert!(!NodeFeatures::known().requires_onion_messages());
-
- assert!(InitFeatures::known().supports_zero_conf());
- assert!(!InitFeatures::known().requires_zero_conf());
- assert!(NodeFeatures::known().supports_zero_conf());
- assert!(!NodeFeatures::known().requires_zero_conf());
- assert!(ChannelTypeFeatures::known().supports_zero_conf());
- assert!(ChannelTypeFeatures::known().requires_zero_conf());
-
- let mut init_features = InitFeatures::known();
- assert!(init_features.initial_routing_sync());
- init_features = init_features.clear_initial_routing_sync();
- assert!(!init_features.initial_routing_sync());
- }
-
#[test]
fn sanity_test_unknown_bits() {
let features = ChannelFeatures::empty();
#[test]
fn convert_to_context_with_relevant_flags() {
- let init_features = InitFeatures::known().clear_upfront_shutdown_script().clear_gossip_queries();
+ let mut init_features = InitFeatures::empty();
+ // Set a bunch of features we use, plus initial_routing_sync_required (which shouldn't get
+ // converted as it's only relevant in an init context).
+ init_features.set_initial_routing_sync_required();
+ init_features.set_data_loss_protect_optional();
+ init_features.set_variable_length_onion_required();
+ init_features.set_static_remote_key_required();
+ init_features.set_payment_secret_required();
+ init_features.set_basic_mpp_optional();
+ init_features.set_wumbo_optional();
+ init_features.set_shutdown_any_segwit_optional();
+ init_features.set_onion_messages_optional();
+ init_features.set_channel_type_optional();
+ init_features.set_scid_privacy_optional();
+ init_features.set_zero_conf_optional();
+
assert!(init_features.initial_routing_sync());
assert!(!init_features.supports_upfront_shutdown_script());
assert!(!init_features.supports_gossip_queries());
#[test]
fn convert_to_context_with_unknown_flags() {
// Ensure the `from` context has fewer known feature bytes than the `to` context.
- assert!(InvoiceFeatures::known().flags.len() < NodeFeatures::known().flags.len());
- let mut invoice_features = InvoiceFeatures::known();
+ assert!(<sealed::InvoiceContext as sealed::Context>::KNOWN_FEATURE_MASK.len() <
+ <sealed::NodeContext as sealed::Context>::KNOWN_FEATURE_MASK.len());
+ let mut invoice_features = InvoiceFeatures::empty();
invoice_features.set_unknown_feature_optional();
assert!(invoice_features.supports_unknown_bits());
let node_features: NodeFeatures = invoice_features.to_context();
//! A bunch of useful utilities for building networks of nodes and exchanging messages between
//! nodes for functional tests.
-use chain::{BestBlock, Confirm, Listen, Watch, keysinterface::KeysInterface};
+use chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, keysinterface::KeysInterface};
use chain::channelmonitor::ChannelMonitor;
use chain::transaction::OutPoint;
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
-use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId, MIN_CLTV_EXPIRY_DELTA};
+use ln::channelmanager::{self, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId, MIN_CLTV_EXPIRY_DELTA};
use routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
use routing::router::{PaymentParameters, Route, get_route};
-use ln::features::{InitFeatures, InvoiceFeatures};
+use ln::features::InitFeatures;
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler};
use util::enforcing_trait_impls::EnforcingSigner;
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &broadcaster, &self.logger, &feeest, &persister, &self.keys_manager);
for deserialized_monitor in deserialized_monitors.drain(..) {
- if let Err(_) = chain_monitor.watch_channel(deserialized_monitor.get_funding_txo().0, deserialized_monitor) {
+ if chain_monitor.watch_channel(deserialized_monitor.get_funding_txo().0, deserialized_monitor) != ChannelMonitorUpdateStatus::Completed {
panic!();
}
}
initiator.node.create_channel(receiver.node.get_our_node_id(), 100_000, 10_001, 42, initiator_config).unwrap();
let open_channel = get_event_msg!(initiator, MessageSendEvent::SendOpenChannel, receiver.node.get_our_node_id());
- receiver.node.handle_open_channel(&initiator.node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ receiver.node.handle_open_channel(&initiator.node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let events = receiver.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
let accept_channel = get_event_msg!(receiver, MessageSendEvent::SendAcceptChannel, initiator.node.get_our_node_id());
assert_eq!(accept_channel.minimum_depth, 0);
- initiator.node.handle_accept_channel(&receiver.node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ initiator.node.handle_accept_channel(&receiver.node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let (temporary_channel_id, tx, _) = create_funding_transaction(&initiator, &receiver.node.get_our_node_id(), 100_000, 42);
initiator.node.funding_transaction_generated(&temporary_channel_id, &receiver.node.get_our_node_id(), tx.clone()).unwrap();
let (tx_a, tx_b);
node_a.close_channel(channel_id, &node_b.get_our_node_id()).unwrap();
- node_b.handle_shutdown(&node_a.get_our_node_id(), &InitFeatures::known(), &get_event_msg!(struct_a, MessageSendEvent::SendShutdown, node_b.get_our_node_id()));
+ node_b.handle_shutdown(&node_a.get_our_node_id(), &channelmanager::provided_init_features(), &get_event_msg!(struct_a, MessageSendEvent::SendShutdown, node_b.get_our_node_id()));
let events_1 = node_b.get_and_clear_pending_msg_events();
assert!(events_1.len() >= 1);
})
};
- node_a.handle_shutdown(&node_b.get_our_node_id(), &InitFeatures::known(), &shutdown_b);
+ node_a.handle_shutdown(&node_b.get_our_node_id(), &channelmanager::provided_init_features(), &shutdown_b);
let (as_update, bs_update) = if close_inbound_first {
assert!(node_a.get_and_clear_pending_msg_events().is_empty());
node_a.handle_closing_signed(&node_b.get_our_node_id(), &closing_signed_b.unwrap());
assert!(updates.update_fail_htlcs.is_empty());
assert!(updates.update_fail_malformed_htlcs.is_empty());
assert!(updates.update_fee.is_none());
- SendEvent { node_id: node_id, msgs: updates.update_add_htlcs, commitment_msg: updates.commitment_signed }
+ SendEvent { node_id, msgs: updates.update_add_htlcs, commitment_msg: updates.commitment_signed }
}
pub fn from_event(event: MessageSendEvent) -> SendEvent {
macro_rules! get_route_and_payment_hash {
($send_node: expr, $recv_node: expr, $recv_value: expr) => {{
let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id())
- .with_features($crate::ln::features::InvoiceFeatures::known());
+ .with_features($crate::ln::channelmanager::provided_invoice_features());
$crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value, TEST_FINAL_CLTV)
}};
($send_node: expr, $recv_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{
pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) -> (PaymentPreimage, PaymentHash, PaymentSecret) {
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let route = get_route!(origin_node, payment_params, recv_value, TEST_FINAL_CLTV).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].len(), expected_route.len());
pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) {
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let network_graph = origin_node.network_graph.read_only();
let scorer = test_utils::TestScorer::with_penalty(0);
let seed = [0u8; 32];
chain_monitor,
keys_manager: &chanmon_cfgs[i].keys_manager,
node_seed: seed,
- features: InitFeatures::known(),
+ features: channelmanager::provided_init_features(),
network_graph: NetworkGraph::new(chanmon_cfgs[i].chain_source.genesis_hash, &chanmon_cfgs[i].logger),
});
}
for i in 0..node_count {
for j in (i+1)..node_count {
- nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &msgs::Init { features: cfgs[j].features.clone(), remote_network_address: None });
- nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &msgs::Init { features: cfgs[i].features.clone(), remote_network_address: None });
+ nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &msgs::Init { features: cfgs[j].features.clone(), remote_network_address: None }).unwrap();
+ nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &msgs::Init { features: cfgs[i].features.clone(), remote_network_address: None }).unwrap();
}
}
// Note that the following only works for CLTV values up to 128
pub const ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 137; //Here we have a diff due to HTLC CLTV expiry being < 2^15 in test
-pub const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133;
#[derive(PartialEq)]
pub enum HTLCType { NONE, TIMEOUT, SUCCESS }
/// pending_htlc_adds includes both the holding cell and in-flight update_add_htlcs, whereas
/// for claims/fails they are separated out.
pub fn reconnect_nodes<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, send_channel_ready: (bool, bool), pending_htlc_adds: (i64, i64), pending_htlc_claims: (usize, usize), pending_htlc_fails: (usize, usize), pending_cell_htlc_claims: (usize, usize), pending_cell_htlc_fails: (usize, usize), pending_raa: (bool, bool)) {
- node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(node_a, node_b);
- node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(node_b, node_a);
if send_channel_ready.0 {
//! claim outputs on-chain.
use chain;
-use chain::{Confirm, Listen, Watch};
+use chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch};
use chain::chaininterface::LowerBoundedFeeEstimator;
use chain::channelmonitor;
use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
use chain::keysinterface::{BaseSign, KeysInterface};
use ln::{PaymentPreimage, PaymentSecret, PaymentHash};
use ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT};
-use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, PaymentId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, PAYMENT_EXPIRY_BLOCKS };
+use ln::channelmanager::{self, ChannelManager, ChannelManagerReadArgs, PaymentId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, PAYMENT_EXPIRY_BLOCKS};
use ln::channel::{Channel, ChannelError};
use ln::{chan_utils, onion_utils};
-use ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
-use routing::gossip::NetworkGraph;
+use ln::chan_utils::{OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
+use routing::gossip::{NetworkGraph, NetworkUpdate};
use routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, find_route, get_route};
-use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
+use ln::features::{ChannelFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, ErrorAction};
use util::enforcing_trait_impls::EnforcingSigner;
// Test helper that asserts we get the correct error string given a mutator
// that supposedly makes the channel open message insane
let insane_open_helper = |expected_error_str: &str, message_mutator: fn(msgs::OpenChannel) -> msgs::OpenChannel| {
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &message_mutator(open_channel_message.clone()));
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &message_mutator(open_channel_message.clone()));
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(msg_events.len(), 1);
let expected_regex = regex::Regex::new(expected_error_str).unwrap();
use ln::channel::MAX_FUNDING_SATOSHIS_NO_WUMBO;
let chanmon_cfgs = create_chanmon_cfgs(2);
let mut node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
- node_cfgs[1].features = InitFeatures::known().clear_wumbo();
+ node_cfgs[1].features = channelmanager::provided_init_features().clear_wumbo();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
open_channel_message.channel_reserve_satoshis = 0;
open_channel_message.max_htlc_value_in_flight_msat = 100_000_000;
}
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel_message);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel_message);
// Extract the channel accept message from node1 to node0
let mut accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
accept_channel_message.channel_reserve_satoshis = 0;
accept_channel_message.max_htlc_value_in_flight_msat = 100_000_000;
}
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel_message);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel_message);
{
let mut lock;
let mut chan = get_channel_ref!(if send_from_initiator { &nodes[1] } else { &nodes[0] }, lock, temp_channel_id);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// balancing
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// balancing
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// A B
// update_fee/commitment_signed ->
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
if steps & 0x0f == 1 { return; }
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
if steps & 0x0f == 2 { return; }
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let (temporary_channel_id, tx, funding_output) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
{
let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap();
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let channel_value = 5000;
let push_sats = 700;
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, push_sats * 1000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, push_sats * 1000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let channel_id = chan.2;
let secp_ctx = Secp256k1::new();
let default_config = UserConfig::default();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// balancing
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let channel_id = chan.2;
// A B
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
- let chan_3 = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_3 = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance the network a bit by relaying one payment through all the channels...
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..], 8000000);
fail_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..], payment_hash_1);
// Add a new channel that skips 3
- let chan_4 = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known());
+ let chan_4 = create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[3])[..], 1000000);
send_payment(&nodes[2], &vec!(&nodes[3])[..], 1000000);
});
hops.push(RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_4.0.contents.short_channel_id,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 1000000,
cltv_expiry_delta: TEST_FINAL_CLTV,
});
});
hops.push(RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: chan_2.0.contents.short_channel_id,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 1000000,
cltv_expiry_delta: TEST_FINAL_CLTV,
});
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut payments = Vec::new();
for _ in 0..::ln::channel::OUR_MAX_HTLCS {
let mut nodes = create_network(6, &node_cfgs, &node_chanmgrs);
// Create some initial channels to route via 3 to 4/5 from 0/1/2
- create_announced_chan_between_nodes(&nodes, 0, 3, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 3, 4, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 3, 5, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 3, 4, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 3, 5, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[3], &nodes[4])[..], 1000000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// balancing
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
let claim_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
- assert_eq!(claim_txn.len(), 8);
+ assert_eq!(claim_txn.len(), 5);
check_spends!(claim_txn[0], remote_txn[0]); // Immediate HTLC claim with preimage
-
check_spends!(claim_txn[1], chan_1.3); // Alternative commitment tx
check_spends!(claim_txn[2], claim_txn[1]); // HTLC spend in alternative commitment tx
- let bump_tx = if claim_txn[1] == claim_txn[4] {
- assert_eq!(claim_txn[1], claim_txn[4]);
- assert_eq!(claim_txn[2], claim_txn[5]);
-
- check_spends!(claim_txn[7], claim_txn[1]); // HTLC timeout on alternative commitment tx
-
- check_spends!(claim_txn[3], remote_txn[0]); // HTLC timeout on broadcasted commitment tx
- &claim_txn[3]
+ check_spends!(claim_txn[3], remote_txn[0]);
+ check_spends!(claim_txn[4], remote_txn[0]);
+ let preimage_tx = &claim_txn[0];
+ let (preimage_bump_tx, timeout_tx) = if claim_txn[3].input[0].previous_output == preimage_tx.input[0].previous_output {
+ (&claim_txn[3], &claim_txn[4])
} else {
- assert_eq!(claim_txn[1], claim_txn[3]);
- assert_eq!(claim_txn[2], claim_txn[4]);
-
- check_spends!(claim_txn[5], claim_txn[1]); // HTLC timeout on alternative commitment tx
-
- check_spends!(claim_txn[7], remote_txn[0]); // HTLC timeout on broadcasted commitment tx
-
- &claim_txn[7]
+ (&claim_txn[4], &claim_txn[3])
};
- assert_eq!(claim_txn[0].input.len(), 1);
- assert_eq!(bump_tx.input.len(), 1);
- assert_eq!(claim_txn[0].input[0].previous_output, bump_tx.input[0].previous_output);
+ assert_eq!(preimage_tx.input.len(), 1);
+ assert_eq!(preimage_bump_tx.input.len(), 1);
- assert_eq!(claim_txn[0].input.len(), 1);
- assert_eq!(claim_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC 1 <--> 0, preimage tx
- assert_eq!(remote_txn[0].output[claim_txn[0].input[0].previous_output.vout as usize].value, 800);
+ assert_eq!(preimage_tx.input.len(), 1);
+ assert_eq!(preimage_tx.input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC 1 <--> 0, preimage tx
+ assert_eq!(remote_txn[0].output[preimage_tx.input[0].previous_output.vout as usize].value, 800);
- assert_eq!(claim_txn[6].input.len(), 1);
- assert_eq!(claim_txn[6].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // HTLC 0 <--> 1, timeout tx
- check_spends!(claim_txn[6], remote_txn[0]);
- assert_eq!(remote_txn[0].output[claim_txn[6].input[0].previous_output.vout as usize].value, 900);
+ assert_eq!(timeout_tx.input.len(), 1);
+ assert_eq!(timeout_tx.input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // HTLC 0 <--> 1, timeout tx
+ check_spends!(timeout_tx, remote_txn[0]);
+ assert_eq!(remote_txn[0].output[timeout_tx.input[0].previous_output.vout as usize].value, 900);
let events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 3);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let chan_stat = get_channel_value_stat!(nodes[0], chan.2);
let channel_reserve = chan_stat.channel_reserve_msat;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 3460001);
// Need to manually create the update_add_htlc message to go around the channel reserve check in send_htlc()
push_amt -= Channel::<EnforcingSigner>::get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
- let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, push_amt, InitFeatures::known(), InitFeatures::known());
+ let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, push_amt, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Sending exactly enough to hit the reserve amount should be accepted
for _ in 0..MIN_AFFORDABLE_HTLC_COUNT {
let mut push_amt = 100_000_000;
push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors);
push_amt -= Channel::<EnforcingSigner>::get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, push_amt, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, push_amt, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Send four HTLCs to cover the initial push_msat buffer we're required to include
for _ in 0..MIN_AFFORDABLE_HTLC_COUNT {
let mut push_amt = 100_000_000;
push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors);
push_amt -= Channel::<EnforcingSigner>::get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, push_amt, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, push_amt, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let dust_amt = crate::ln::channel::MIN_CHAN_DUST_LIMIT_SATOSHIS * 1000
+ feerate_per_kw as u64 * htlc_success_tx_weight(opt_anchors) / 1000 * 1000 - 1;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, push_amt, 42, None).unwrap();
let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
open_channel_msg.push_msat += 1;
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel_msg);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel_msg);
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(msg_events.len(), 1);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 98000000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 98000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_amt = 46000; // Dust amount
// In the previous code, these first four payments would succeed.
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
- let _ = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let _ = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let feemsat = 239;
let total_routing_fee_msat = (nodes.len() - 2) as u64 * feemsat;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let channels0 = node_chanmgrs[0].list_channels();
let channels1 = node_chanmgrs[1].list_channels();
let default_config = UserConfig::default();
config.channel_config.forwarding_fee_base_msat = 239;
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 190000, 1001, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 190000, 1001, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 190000, 1001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 190000, 1001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut stat01 = get_channel_value_stat!(nodes[0], chan_1.2);
let mut stat11 = get_channel_value_stat!(nodes[1], chan_1.2);
// attempt to send amt_msat > their_max_htlc_value_in_flight_msat
{
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
- .with_features(InvoiceFeatures::known()).with_max_channel_saturation_power_of_half(0);
+ .with_features(channelmanager::provided_invoice_features()).with_max_channel_saturation_power_of_half(0);
let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, recv_value_0, TEST_FINAL_CLTV);
route.paths[0].last_mut().unwrap().fee_msat += 1;
assert!(route.paths[0].iter().rev().skip(1).all(|h| h.fee_msat == feemsat));
}
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
- .with_features(InvoiceFeatures::known()).with_max_channel_saturation_power_of_half(0);
+ .with_features(channelmanager::provided_invoice_features()).with_max_channel_saturation_power_of_half(0);
let route = get_route!(nodes[0], payment_params, recv_value_0, TEST_FINAL_CLTV).unwrap();
let (payment_preimage, ..) = send_along_route(&nodes[0], route, &[&nodes[1], &nodes[2]], recv_value_0);
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let b_chan_values = get_channel_value_stat!(nodes[1], chan_1.2);
// Route the first two HTLCs.
let nodes = create_network(5, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
- let chan_3 = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
- let chan_4 = create_announced_chan_between_nodes(&nodes, 3, 4, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_3 = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_4 = create_announced_chan_between_nodes(&nodes, 3, 4, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Make sure all nodes are at the same starting height
connect_blocks(&nodes[0], 4*CHAN_CONFIRM_DEPTH + 1 - nodes[0].best_block_info().1);
assert_eq!(nodes[3].node.list_channels().len(), 0);
assert_eq!(nodes[4].node.list_channels().len(), 0);
- nodes[3].chain_monitor.chain_monitor.watch_channel(OutPoint { txid: chan_3.3.txid(), index: 0 }, chan_3_mon).unwrap();
+ assert_eq!(nodes[3].chain_monitor.chain_monitor.watch_channel(OutPoint { txid: chan_3.3.txid(), index: 0 }, chan_3_mon),
+ ChannelMonitorUpdateStatus::Completed);
check_closed_event!(nodes[3], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_event!(nodes[4], 1, ClosureReason::CommitmentTxConfirmed);
}
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
*nodes[0].connect_style.borrow_mut() = ConnectStyle::FullBlockViaListen;
// Create some new channels:
- let chan_5 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_5 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// A pending HTLC which will be revoked:
let payment_preimage_3 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
// We test justice_tx build by A on B's revoked HTLC-Success tx
// Create some new channels:
- let chan_6 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_6 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
{
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
node_txn.clear();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// node[0] is gonna to revoke an old state thus node[1] should be able to claim the revoked output
let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan_1.2);
assert_eq!(revoked_local_txn.len(), 1);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some new channel:
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance the network to generate htlc in the two directions
send_payment(&nodes[0], &[&nodes[1]], 8_000_000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance the network to generate htlc in the two directions
send_payment(&nodes[0], &[&nodes[1]], 8_000_000);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Ensure all nodes are at the same height
let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
*nodes[2].connect_style.borrow_mut() = connect_style;
// Create some intial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance the network a bit by relaying one payment thorugh all the channels...
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, _payment_hash, _payment_secret) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 3000000);
// Get the will-be-revoked local txn from nodes[2]
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, _payment_hash, _payment_secret) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], if no_to_remote { 10_000 } else { 3_000_000 });
// Get the will-be-revoked local txn from nodes[2]
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Alice -> Bob: Route a payment but without Bob sending revoke_and_ack.
{
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
route_payment(&nodes[0], &[&nodes[1]], 10000000);
nodes[0].node.force_close_broadcasting_latest_txn(&nodes[0].node.list_channels()[0].channel_id, &nodes[1].node.get_our_node_id()).unwrap();
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 1000000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
// broadcasted, even though it's created by `nodes[0]`.
let expected_temporary_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let (temporary_channel_id, tx, _funding_output) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42);
assert_eq!(temporary_channel_id, expected_temporary_channel_id);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
let mut as_channel_ready = None;
if messages_delivered == 0 {
- let (channel_ready, _, _) = create_chan_between_nodes_with_value_a(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let (channel_ready, _, _) = create_chan_between_nodes_with_value_a(&nodes[0], &nodes[1], 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
as_channel_ready = Some(channel_ready);
// nodes[1] doesn't receive the channel_ready message (it'll be re-sent on reconnect)
// Note that we store it so that if we're running with `simulate_broken_lnd` we can deliver
// it before the channel_reestablish message.
} else {
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
}
let (route, payment_hash_1, payment_preimage_1, payment_secret_1) = get_route_and_payment_hash!(nodes[0], nodes[1], 1_000_000);
let new_chain_monitor: test_utils::TestChainMonitor;
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
let events_2 = nodes[1].node.get_and_clear_pending_msg_events();
assert!(events_2.is_empty());
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let as_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
// nodes[0] hasn't yet received a channel_ready, so it only sends that on reconnect.
nodes_0_deserialized = nodes_0_deserialized_tmp;
assert!(nodes_0_read.is_empty());
- assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
nodes[0].node = &nodes_0_deserialized;
check_added_monitors!(nodes[0], 1);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
*nodes[0].connect_style.borrow_mut() = ConnectStyle::BestBlockFirstSkippingBlocks;
- let funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ let funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let conf_height = nodes[0].best_block_info().1 + 1;
connect_blocks(&nodes[0], CHAN_CONFIRM_DEPTH);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let our_payment_hash = if send_partial_mpp {
let (route, our_payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[1], 100000);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Make sure all nodes are at the same starting height
connect_blocks(&nodes[0], 2*CHAN_CONFIRM_DEPTH + 1 - nodes[0].best_block_info().1);
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes_0_deserialized = nodes_0_deserialized_tmp;
assert!(nodes_0_read.is_empty());
- assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
nodes[0].node = &nodes_0_deserialized;
assert_eq!(nodes[0].node.list_channels().len(), 1);
check_added_monitors!(nodes[0], 1);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]);
// Start creating a channel, but stop right before broadcasting the funding transaction
let channel_value = 100000;
let push_msat = 10001;
- let a_flags = InitFeatures::known();
- let b_flags = InitFeatures::known();
+ let a_flags = channelmanager::provided_init_features();
+ let b_flags = channelmanager::provided_init_features();
let node_a = nodes.remove(0);
let node_b = nodes.remove(0);
node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap();
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
nodes[0].node = &nodes_0_deserialized;
// After deserializing, make sure the funding_transaction is still held by the channel manager
assert_eq!(nodes[0].node.list_channels().len(), 1);
check_added_monitors!(nodes[0], 1);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]);
let new_chain_monitor: test_utils::TestChainMonitor;
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (our_payment_preimage, _, _) = route_payment(&nodes[0], &[&nodes[1]], 1000000);
let (_, our_payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 1000000);
nodes_0_deserialized = nodes_0_deserialized_tmp;
assert!(nodes_0_read.is_empty());
- assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
nodes[0].node = &nodes_0_deserialized;
check_added_monitors!(nodes[0], 1);
let new_chain_monitor: test_utils::TestChainMonitor;
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_id_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
- let chan_id_2 = create_announced_chan_between_nodes(&nodes, 2, 0, InitFeatures::known(), InitFeatures::known()).2;
- let (_, _, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 3, InitFeatures::known(), InitFeatures::known());
+ let chan_id_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ let chan_id_2 = create_announced_chan_between_nodes(&nodes, 2, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ let (_, _, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut node_0_stale_monitors_serialized = Vec::new();
for chan_id_iter in &[chan_id_1, chan_id_2, channel_id] {
}
for monitor in node_0_monitors.drain(..) {
- assert!(nodes[0].chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor),
+ ChannelMonitorUpdateStatus::Completed);
check_added_monitors!(nodes[0], 1);
}
nodes[0].node = &nodes_0_deserialized;
//... and we can even still claim the payment!
claim_payment(&nodes[2], &[&nodes[0], &nodes[1]], our_payment_preimage);
- nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish = get_chan_reestablish_msgs!(nodes[3], nodes[0]).pop().unwrap();
- nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
nodes[0].node.handle_channel_reestablish(&nodes[3].node.get_our_node_id(), &reestablish);
let mut found_err = false;
for msg_event in nodes[0].node.get_and_clear_pending_msg_events() {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 98_000_000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 98_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[1].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[0].node.get_our_node_id()).unwrap();
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 98_000_000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 98_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[1].node.get_our_node_id()).unwrap();
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 59000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 59000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan.2);
assert_eq!(revoked_local_txn[0].input.len(), 1);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 3_000_000);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance the network a bit by relaying one payment through all the channels ...
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan_1.2);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan_1.2);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let revoked_local_txn = get_local_commitment_txn!(nodes[1], chan_1.2);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Ensure all nodes are at the same height
let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
&[Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let node_max_height = nodes.iter().map(|node| node.blocks.lock().unwrap().len()).max().unwrap() as u32;
connect_blocks(&nodes[0], node_max_height - nodes[0].best_block_info().1);
// script push size limit so that the below script length checks match
// ACCEPTED_HTLC_SCRIPT_WEIGHT.
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[3], payment_params, 900000, TEST_FINAL_CLTV - 40);
send_along_route_with_secret(&nodes[0], route, &[&[&nodes[1], &nodes[2], &nodes[3]]], 900000, duplicate_payment_hash, payment_secret);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 9_000_000);
let local_txn = get_local_commitment_txn!(nodes[1], chan_1.2);
&[Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
- let _chan_0_2 = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known());
- let _chan_1_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
- let chan_2_3 = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
- let chan_3_4 = create_announced_chan_between_nodes(&nodes, 3, 4, InitFeatures::known(), InitFeatures::known());
- let chan_3_5 = create_announced_chan_between_nodes(&nodes, 3, 5, InitFeatures::known(), InitFeatures::known());
+ let _chan_0_2 = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let _chan_1_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2_3 = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_3_4 = create_announced_chan_between_nodes(&nodes, 3, 4, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_3_5 = create_announced_chan_between_nodes(&nodes, 3, 5, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance and check output sanity...
send_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 500000);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (_, our_payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 9000000);
let local_txn = get_local_commitment_txn!(nodes[0], chan_1.2);
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &chanmon_cfgs[0].persister, &keys_manager);
let network_graph = NetworkGraph::new(chanmon_cfgs[0].chain_source.genesis_hash, &chanmon_cfgs[0].logger);
- let node = NodeCfg { chain_source: &chanmon_cfgs[0].chain_source, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, chain_monitor, keys_manager: &keys_manager, network_graph, node_seed: seed, features: InitFeatures::known() };
+ let node = NodeCfg { chain_source: &chanmon_cfgs[0].chain_source, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, chain_monitor, keys_manager: &keys_manager, network_graph, node_seed: seed, features: channelmanager::provided_init_features() };
let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
node_cfgs.remove(0);
node_cfgs.insert(0, node);
// Create some initial channels
// Create a dummy channel to advance index by one and thus test re-derivation correctness
// for node 0
- let chan_0 = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known());
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_0 = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
assert_ne!(chan_0.3.output[0].script_pubkey, chan_1.3.output[0].script_pubkey);
// Ensure all nodes are at the same height
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
let closing_tx = close_channel(&nodes[0], &nodes[1], &chan.2, chan.3, true).2;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], if use_dust { 50000 } else { 3_000_000 });
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], if use_dust { 50000 } else { 3000000 });
nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Fail the payment, but don't deliver A's final RAA, resulting in the HTLC only being present
// in B's previous (unrevoked) commitment transaction, but none of A's commitment transactions.
let push_msat=10001;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).unwrap();
let node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &node0_to_1_send_open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &node0_to_1_send_open_channel);
get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
// Create a second channel with the same random values. This used to panic due to a colliding
node0_to_1_send_open_channel.dust_limit_satoshis = 547;
node0_to_1_send_open_channel.channel_reserve_satoshis = 100001;
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &node0_to_1_send_open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &node0_to_1_send_open_channel);
let events = nodes[1].node.get_and_clear_pending_msg_events();
let err_msg = match events[0] {
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg }, node_id: _ } => {
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// First nodes[0] generates an update_fee, setting the channel's
// pending_update_fee.
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// First nodes[0] generates an update_fee, setting the channel's
// pending_update_fee.
config.channel_config.forwarding_fee_base_msat = 196;
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
- let chan_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// First nodes[1] generates an update_fee, setting the channel's
// pending_update_fee.
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 100000);
route.paths[0][0].fee_msat = 100;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 100000);
route.paths[0][0].fee_msat = 0;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 100000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 0, InitFeatures::known(), InitFeatures::known());
+ let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], payment_params, 100000000, 0);
route.paths[0].last_mut().unwrap().cltv_expiry_delta = 500000001;
unwrap_send_err!(nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)), true, APIError::RouteError { ref err },
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 0, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let max_accepted_htlcs = nodes[1].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().counterparty_max_accepted_htlcs as u64;
for i in 0..max_accepted_htlcs {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let channel_value = 100000;
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, 0, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let max_in_flight = get_channel_value_stat!(nodes[0], chan.2).counterparty_max_htlc_value_in_flight_msat;
send_payment(&nodes[0], &vec!(&nodes[1])[..], max_in_flight);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let htlc_minimum_msat: u64;
{
let chan_lock = nodes[0].node.channel_state.lock().unwrap();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let chan_stat = get_channel_value_stat!(nodes[0], chan.2);
let channel_reserve = chan_stat.channel_reserve_msat;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 3999999);
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
check_added_monitors!(nodes[0], 1);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
check_added_monitors!(nodes[0], 1);
//Disconnect and Reconnect
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &reestablish_2[0]);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (our_payment_preimage, our_payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 100_000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (our_payment_preimage, our_payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 100_000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1000000, 1000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 100000);
check_added_monitors!(nodes[1], 1);
}
+#[test]
+fn test_channel_failed_after_message_with_badonion_node_perm_bits_set() {
+ let chanmon_cfgs = create_chanmon_cfgs(3);
+ let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+ let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+
+ let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 100_000);
+
+ // First hop
+ let mut payment_event = {
+ nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
+ check_added_monitors!(nodes[0], 1);
+ SendEvent::from_node(&nodes[0])
+ };
+
+ nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
+ commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
+ expect_pending_htlcs_forwardable!(nodes[1]);
+ check_added_monitors!(nodes[1], 1);
+ payment_event = SendEvent::from_node(&nodes[1]);
+ assert_eq!(payment_event.msgs.len(), 1);
+
+ // Second Hop
+ payment_event.msgs[0].onion_routing_packet.version = 1; // Trigger an invalid_onion_version error
+ nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
+ check_added_monitors!(nodes[2], 0);
+ commitment_signed_dance!(nodes[2], nodes[1], payment_event.commitment_msg, false, true);
+
+ let events_3 = nodes[2].node.get_and_clear_pending_msg_events();
+ assert_eq!(events_3.len(), 1);
+ match events_3[0] {
+ MessageSendEvent::UpdateHTLCs { ref updates, .. } => {
+ let mut update_msg = updates.update_fail_malformed_htlcs[0].clone();
+ // Set the NODE bit (BADONION and PERM already set in invalid_onion_version error)
+ update_msg.failure_code |= 0x2000;
+
+ nodes[1].node.handle_update_fail_malformed_htlc(&nodes[2].node.get_our_node_id(), &update_msg);
+ commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false, true);
+ },
+ _ => panic!("Unexpected event"),
+ }
+
+ expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1],
+ vec![HTLCDestination::NextHopChannel {
+ node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_2.2 }]);
+ let events_4 = nodes[1].node.get_and_clear_pending_msg_events();
+ assert_eq!(events_4.len(), 1);
+ check_added_monitors!(nodes[1], 1);
+
+ match events_4[0] {
+ MessageSendEvent::UpdateHTLCs { ref updates, .. } => {
+ nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
+ commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false, true);
+ },
+ _ => panic!("Unexpected event"),
+ }
+
+ let events_5 = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events_5.len(), 1);
+
+ // Expect a PaymentPathFailed event with a ChannelFailure network update for the channel between
+ // the node originating the error to its next hop.
+ match events_5[0] {
+ Event::PaymentPathFailed { network_update:
+ Some(NetworkUpdate::ChannelFailure { short_channel_id, is_permanent }), error_code, ..
+ } => {
+ assert_eq!(short_channel_id, chan_2.0.contents.short_channel_id);
+ assert!(is_permanent);
+ assert_eq!(error_code, Some(0x8000|0x4000|0x2000|4));
+ },
+ _ => panic!("Unexpected event"),
+ }
+
+ // TODO: Test actual removal of channel from NetworkGraph when it's implemented.
+}
+
fn do_test_failure_delay_dust_htlc_local_commitment(announce_latest: bool) {
// Dust-HTLC failure updates must be delayed until failure-trigger tx (in this case local commitment) reach ANTI_REORG_DELAY
// We can have at most two valid local commitment tx, so both cases must be covered, and both txs must be checked to get them all as
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan =create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan =create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let bs_dust_limit = nodes[1].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().holder_dust_limit_satoshis;
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let bs_dust_limit = nodes[1].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().holder_dust_limit_satoshis;
// We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in Channel::new_outbound()
if let Err(error) = Channel::new_outbound(&LowerBoundedFeeEstimator::new(&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }),
- &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), 1000000, 1000000, 0,
+ &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), 1000000, 1000000, 0,
&low_our_to_self_config, 0, 42)
{
match error {
let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
open_channel.to_self_delay = 200;
if let Err(error) = Channel::new_from_req(&LowerBoundedFeeEstimator::new(&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }),
- &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0,
+ &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &open_channel, 0,
&low_our_to_self_config, 0, &nodes[0].logger, 42)
{
match error {
// We test msg.to_self_delay <= config.their_to_self_delay is enforced in Chanel::accept_channel()
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
accept_channel.to_self_delay = 200;
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let reason_msg;
if let MessageSendEvent::HandleError { ref action, .. } = nodes[0].node.get_and_clear_pending_msg_events()[0] {
match action {
let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
open_channel.to_self_delay = 200;
if let Err(error) = Channel::new_from_req(&LowerBoundedFeeEstimator::new(&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }),
- &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0,
+ &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &open_channel, 0,
&high_their_to_self_config, 0, &nodes[0].logger, 42)
{
match error {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Cache node A state before any channel update
let previous_node_state = nodes[0].node.encode();
}).unwrap().1
};
nodes[0].node = &node_state_0;
- assert!(monitor.watch_channel(OutPoint { txid: chan.3.txid(), index: 0 }, chain_monitor).is_ok());
+ assert_eq!(monitor.watch_channel(OutPoint { txid: chan.3.txid(), index: 0 }, chain_monitor),
+ ChannelMonitorUpdateStatus::Completed);
nodes[0].chain_monitor = &monitor;
nodes[0].chain_source = &chain_source;
check_added_monitors!(nodes[0], 1);
if reconnect_panicing {
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
// after the warning message sent by B, we should not able to
// use the channel, or reconnect with success to the channel.
assert!(nodes[0].node.list_usable_channels().is_empty());
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let retry_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &retry_reestablish[0]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(channelmanager::provided_invoice_features());
let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None, 10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
let (_, our_payment_hash, _) = get_payment_preimage_hash!(nodes[0]);
let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200).unwrap();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Disconnect peers
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
}
}
// Reconnect peers
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 3);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 3);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let (route,_, _, _) = get_route_and_payment_hash!(nodes[1], nodes[0], payment_params, 3000000, 30);
send_along_route(&nodes[1], route, &vec!(&nodes[0])[..], 3000000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Lock HTLC in both directions (using a slightly lower CLTV delay to provide timely RBF bumps)
- let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(channelmanager::provided_invoice_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None,
3_000_000, 50, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
let payment_preimage = send_along_route(&nodes[0], route, &[&nodes[1]], 3_000_000).0;
- let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(channelmanager::provided_invoice_features());
let route = get_route(&nodes[1].node.get_our_node_id(), &payment_params, &nodes[1].network_graph.read_only(), None,
3_000_000, 50, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
send_along_route(&nodes[1], route, &[&nodes[0]], 3_000_000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 3_000_000);
route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000).0;
let feerate_preimage;
{
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
- // 9 transactions including:
- // 1*2 ChannelManager local broadcasts of commitment + HTLC-Success
- // 1*3 ChannelManager local broadcasts of commitment + HTLC-Success + HTLC-Timeout
- // 2 * HTLC-Success (one RBF bump we'll check later)
- // 1 * HTLC-Timeout
- assert_eq!(node_txn.len(), 8);
+ // 5 transactions including:
+ // local commitment + HTLC-Success
+ // preimage and timeout sweeps from remote commitment + preimage sweep bump
+ assert_eq!(node_txn.len(), 5);
assert_eq!(node_txn[0].input.len(), 1);
- assert_eq!(node_txn[6].input.len(), 1);
+ assert_eq!(node_txn[3].input.len(), 1);
+ assert_eq!(node_txn[4].input.len(), 1);
check_spends!(node_txn[0], remote_txn[0]);
- check_spends!(node_txn[6], remote_txn[0]);
-
- check_spends!(node_txn[1], chan.3);
- check_spends!(node_txn[2], node_txn[1]);
-
- if node_txn[0].input[0].previous_output == node_txn[3].input[0].previous_output {
- preimage_bump = node_txn[3].clone();
- check_spends!(node_txn[3], remote_txn[0]);
-
- assert_eq!(node_txn[1], node_txn[4]);
- assert_eq!(node_txn[2], node_txn[5]);
- } else {
- preimage_bump = node_txn[7].clone();
- check_spends!(node_txn[7], remote_txn[0]);
- assert_eq!(node_txn[0].input[0].previous_output, node_txn[7].input[0].previous_output);
-
- assert_eq!(node_txn[1], node_txn[3]);
- assert_eq!(node_txn[2], node_txn[4]);
- }
+ check_spends!(node_txn[3], remote_txn[0]);
+ check_spends!(node_txn[4], remote_txn[0]);
- timeout = node_txn[6].txid();
- let index = node_txn[6].input[0].previous_output.vout;
- let fee = remote_txn[0].output[index as usize].value - node_txn[6].output[0].value;
- feerate_timeout = fee * 1000 / node_txn[6].weight() as u64;
+ check_spends!(node_txn[1], chan.3); // local commitment
+ check_spends!(node_txn[2], node_txn[1]); // local HTLC-Success
preimage = node_txn[0].txid();
let index = node_txn[0].input[0].previous_output.vout;
let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
feerate_preimage = fee * 1000 / node_txn[0].weight() as u64;
+ let (preimage_bump_tx, timeout_tx) = if node_txn[3].input[0].previous_output == node_txn[0].input[0].previous_output {
+ (node_txn[3].clone(), node_txn[4].clone())
+ } else {
+ (node_txn[4].clone(), node_txn[3].clone())
+ };
+
+ preimage_bump = preimage_bump_tx;
+ check_spends!(preimage_bump, remote_txn[0]);
+ assert_eq!(node_txn[0].input[0].previous_output, preimage_bump.input[0].previous_output);
+
+ timeout = timeout_tx.txid();
+ let index = timeout_tx.input[0].previous_output.vout;
+ let fee = remote_txn[0].output[index as usize].value - timeout_tx.output[0].value;
+ feerate_timeout = fee * 1000 / timeout_tx.weight() as u64;
+
node_txn.clear();
};
assert_ne!(feerate_timeout, 0);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let per_commitment_secret;
let next_per_commitment_point;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Lock HTLC in both directions
let (payment_preimage_1, _, _) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 9_000_000);
let (_, payment_hash_2, _) = route_payment(&nodes[1], &vec!(&nodes[0])[..], 9_000_000);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 1_010_000);
nodes[1].node.claim_funds(payment_preimage);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 100_000, InitFeatures::known(), InitFeatures::known());
+ let _funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 100_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// The outbound node should wait forever for confirmation:
// This matches `channel::FUNDING_CONF_DEADLINE_BLOCKS` and BOLT 2's suggested timeout, thus is
let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
assert_eq!(res.htlc_minimum_msat, 1);
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &res);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &res);
let res = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
assert_eq!(res.htlc_minimum_msat, 1);
}
let channel_value_50_percent_msat = (channel_value_msat as f64 * 0.5) as u64;
let channel_value_90_percent_msat = (channel_value_msat as f64 * 0.9) as u64;
- let (node_0_chan_update, node_1_chan_update, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value_satoshis, 10001, InitFeatures::known(), InitFeatures::known());
- let (node_2_chan_update, node_3_chan_update, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, channel_value_satoshis, 10001, InitFeatures::known(), InitFeatures::known());
+ let (node_0_chan_update, node_1_chan_update, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value_satoshis, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (node_2_chan_update, node_3_chan_update, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, channel_value_satoshis, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Assert that `node[0]`'s `ChannelUpdate` is capped at 50 percent of the `channel_value`, as
// that's the value of `node[1]`'s `holder_max_htlc_value_in_flight_msat`.
let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap();
let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &res);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &res);
// Assert that `nodes[1]` has no `MessageSendEvent::SendAcceptChannel` in `msg_events` before
// accepting the inbound channel request.
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap();
let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &res);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &res);
// Assert that `nodes[1]` has no `MessageSendEvent::SendAcceptChannel` in `msg_events` before
// rejecting the inbound channel request.
let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
let temp_channel_id = res.temporary_channel_id;
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &res);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &res);
// Assert that `nodes[1]` has no `MessageSendEvent::SendAcceptChannel` in the `msg_events`.
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
let channel = get_channel_ref!(&nodes[1], lock, temp_channel_id);
channel.get_accept_channel_message()
};
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_chan_msg);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_chan_msg);
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42);
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap();
let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &res);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &res);
// Assert that `nodes[1]` has no `MessageSendEvent::SendAcceptChannel` in `msg_events` before
// accepting the inbound channel request.
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[3], 100000);
let path = route.paths[0].clone();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
{
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(100_000), 7200).unwrap();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
let (payment_hash, payment_secret_1) = nodes[1].node.create_inbound_payment_legacy(Some(100_000), 2).unwrap();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
let random_payment_hash = PaymentHash([42; 32]);
let random_payment_secret = PaymentSecret([43; 32]);
fn test_update_err_monitor_lockdown() {
// Our monitor will lock update of local commitment transaction if a broadcastion condition
// has been fulfilled (either force-close from Channel or block height requiring a HTLC-
- // timeout). Trying to update monitor after lockdown should return a ChannelMonitorUpdateErr.
+ // timeout). Trying to update monitor after lockdown should return a ChannelMonitorUpdateStatus
+ // error.
//
// This scenario may happen in a watchtower setup, where watchtower process a block height
// triggering a timeout while a slow-block-processing ChannelManager receives a local signed
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channel
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let outpoint = OutPoint { txid: chan_1.3.txid(), index: 0 };
// Rebalance the network to generate htlc in the two directions
&mut io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
assert!(new_monitor == *monitor);
let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
- assert!(watchtower.watch_channel(outpoint, new_monitor).is_ok());
+ assert_eq!(watchtower.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]);
if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan_1.2) {
if let Ok((_, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) {
- if let Err(_) = watchtower.chain_monitor.update_channel(outpoint, update.clone()) {} else { assert!(false); }
- if let Ok(_) = nodes[0].chain_monitor.update_channel(outpoint, update) {} else { assert!(false); }
+ assert_eq!(watchtower.chain_monitor.update_channel(outpoint, update.clone()), ChannelMonitorUpdateStatus::PermanentFailure);
+ assert_eq!(nodes[0].chain_monitor.update_channel(outpoint, update), ChannelMonitorUpdateStatus::Completed);
} else { assert!(false); }
} else { assert!(false); };
// Our local monitor is in-sync and hasn't processed yet timeout
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channel
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let outpoint = OutPoint { txid: chan_1.3.txid(), index: 0 };
// Rebalance the network to generate htlc in the two directions
&mut io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
assert!(new_monitor == *monitor);
let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
- assert!(watchtower.watch_channel(outpoint, new_monitor).is_ok());
+ assert_eq!(watchtower.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
&mut io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
assert!(new_monitor == *monitor);
let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
- assert!(watchtower.watch_channel(outpoint, new_monitor).is_ok());
+ assert_eq!(watchtower.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan_1.2) {
if let Ok((_, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) {
// Watchtower Alice should already have seen the block and reject the update
- if let Err(_) = watchtower_alice.chain_monitor.update_channel(outpoint, update.clone()) {} else { assert!(false); }
- if let Ok(_) = watchtower_bob.chain_monitor.update_channel(outpoint, update.clone()) {} else { assert!(false); }
- if let Ok(_) = nodes[0].chain_monitor.update_channel(outpoint, update) {} else { assert!(false); }
+ assert_eq!(watchtower_alice.chain_monitor.update_channel(outpoint, update.clone()), ChannelMonitorUpdateStatus::PermanentFailure);
+ assert_eq!(watchtower_bob.chain_monitor.update_channel(outpoint, update.clone()), ChannelMonitorUpdateStatus::Completed);
+ assert_eq!(nodes[0].chain_monitor.update_channel(outpoint, update), ChannelMonitorUpdateStatus::Completed);
} else { assert!(false); }
} else { assert!(false); };
// Our local monitor is in-sync and hasn't processed yet timeout
watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![bob_state_y.clone()] }, CHAN_CONFIRM_DEPTH + 2 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
{
let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- // We broadcast twice the transaction, once due to the HTLC-timeout, once due
- // the onchain detection of the HTLC output
- assert_eq!(htlc_txn.len(), 2);
+ assert_eq!(htlc_txn.len(), 1);
check_spends!(htlc_txn[0], bob_state_y);
- check_spends!(htlc_txn[1], bob_state_y);
}
}
// Create an initial channel
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_chan_msg);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_chan_msg);
let accept_chan_msg = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_chan_msg);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_chan_msg);
// Move the first channel through the funding flow...
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
send_payment(&nodes[0], &vec!(&nodes[1])[..], 1_000_000);
let (_, our_payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 2_000_000);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_ab = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_ab = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Steps (1) and (2):
// Send an HTLC Alice --> Bob --> Carol, but Carol doesn't settle the HTLC back.
// Create an initial channel
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_chan_msg);
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_chan_msg);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
// Try to create a second channel with the same temporary_channel_id as the first and check
// that it is rejected.
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_chan_msg);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_chan_msg);
{
let events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
// Technically this is allowed by the spec, but we don't support it and there's little reason
// to. Still, it shouldn't cause any other issues.
open_chan_msg.temporary_channel_id = channel_id;
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_chan_msg);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_chan_msg);
{
let events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
// Now try to create a second channel which has a duplicate funding output.
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
let open_chan_2_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_chan_2_msg);
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_chan_2_msg);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42); // Get and check the FundingGenerationReady event
let funding_created = {
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
// Create some initial channels
- let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
- let chan_3 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_3 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
assert_eq!(nodes[0].node.list_usable_channels().len(), 3);
assert_eq!(nodes[1].node.list_usable_channels().len(), 2);
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_3.2 || nodes[0].node.list_usable_channels()[1].channel_id == chan_3.2);
// A null channel ID should close all channels
- let _chan_4 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let _chan_4 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id: [0; 32], data: "ERR".to_owned() });
check_added_monitors!(nodes[0], 2);
check_closed_event!(nodes[0], 2, ClosureReason::CounterpartyForceClosed { peer_msg: "ERR".to_string() });
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_000, 42, None).unwrap();
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
let (temporary_channel_id, mut tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100_000, 42);
// a panic as we'd try to extract a 32 byte preimage from a witness element without checking
// its length.
let mut wit_program: Vec<u8> = channelmonitor::deliberately_bogus_accepted_htlc_witness_program();
- assert!(chan_utils::HTLCType::scriptlen_to_htlctype(wit_program.len()).unwrap() ==
- chan_utils::HTLCType::AcceptedHTLC);
-
- let wit_program_script: Script = wit_program.clone().into();
+ let wit_program_script: Script = wit_program.into();
for output in tx.output.iter_mut() {
// Make the confirmed funding transaction have a bogus script_pubkey
output.script_pubkey = Script::new_v0_p2wsh(&wit_program_script.wscript_hash());
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
*nodes[0].connect_style.borrow_mut() = ConnectStyle::BestBlockFirstSkippingBlocks;
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let (chan_announce, _, channel_id, _) = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (chan_announce, _, channel_id, _) = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (_, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), false);
nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
let new_chain_monitor: test_utils::TestChainMonitor;
let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_id_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
- let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known()).2;
+ let chan_id_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
// First send a payment to nodes[1]
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
nodes_1_deserialized = nodes_1_deserialized_tmp;
assert!(nodes_1_read.is_empty());
- assert!(nodes[1].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
- assert!(nodes[1].chain_monitor.watch_channel(chan_1_monitor.get_funding_txo().0, chan_1_monitor).is_ok());
+ assert_eq!(nodes[1].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
+ assert_eq!(nodes[1].chain_monitor.watch_channel(chan_1_monitor.get_funding_txo().0, chan_1_monitor),
+ ChannelMonitorUpdateStatus::Completed);
nodes[1].node = &nodes_1_deserialized;
check_added_monitors!(nodes[1], 2);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let route = get_route!(nodes[0], payment_params, 10_000, TEST_FINAL_CLTV).unwrap();
let (our_payment_preimage, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(&nodes[1]);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_2_3 =create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2_3 =create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let mut route = get_route!(nodes[0], payment_params, 15_000_000, TEST_FINAL_CLTV).unwrap();
assert_eq!(route.paths.len(), 2);
route.paths.sort_by(|path_a, _| {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let network_graph = nodes[0].network_graph;
let payer_pubkey = nodes[0].node.get_our_node_id();
let payee_pubkey = nodes[1].node.get_our_node_id();
let payer_pubkey = nodes[0].node.get_our_node_id();
let payee_pubkey = nodes[1].node.get_our_node_id();
- nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
- let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known());
+ let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], channelmanager::provided_init_features(), channelmanager::provided_init_features());
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(payee_pubkey),
final_value_msat: 10000,
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[3], 15_000_000);
assert_eq!(route.paths.len(), 2);
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan_id_persisted = create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 100_000, 0, InitFeatures::known(), InitFeatures::known()).2;
- let chan_id_not_persisted = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0, InitFeatures::known(), InitFeatures::known()).2;
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_id_persisted = create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ let chan_id_not_persisted = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
// Create an MPP route for 15k sats, more than the default htlc-max of 10%
let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[3], 15_000_000);
for monitor in monitors {
// On startup the preimage should have been copied into the non-persisted monitor:
assert!(monitor.get_stored_preimages().contains_key(&payment_hash));
- nodes[3].chain_monitor.watch_channel(monitor.get_funding_txo().0.clone(), monitor).unwrap();
+ assert_eq!(nodes[3].chain_monitor.watch_channel(monitor.get_funding_txo().0.clone(), monitor),
+ ChannelMonitorUpdateStatus::Completed);
}
check_added_monitors!(nodes[3], 2);
if !persist_both_monitors {
// If one of the two channels is still live, reveal the payment preimage over it.
- nodes[3].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[3].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_1 = get_chan_reestablish_msgs!(nodes[3], nodes[2]);
- nodes[2].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[2].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let reestablish_2 = get_chan_reestablish_msgs!(nodes[2], nodes[3]);
nodes[2].node.handle_channel_reestablish(&nodes[3].node.get_our_node_id(), &reestablish_1[0]);
if on_holder_tx {
open_channel.dust_limit_satoshis = 546;
}
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let opt_anchors = false;
let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel_message);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel_message);
let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel_message);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel_message);
let best_height = nodes[0].node.best_block.read().unwrap().height();
use chain::transaction::OutPoint;
use chain::chaininterface::LowerBoundedFeeEstimator;
use ln::channel;
-use ln::channelmanager::BREAKDOWN_TIMEOUT;
-use ln::features::InitFeatures;
+use ln::channelmanager::{self, BREAKDOWN_TIMEOUT};
use ln::msgs::ChannelMessageHandler;
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination};
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let (update_a, _, chan_id_2, _) = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (update_a, _, chan_id_2, _) = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 1_000_000);
nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_hash_1 = route_payment(&nodes[1], &[&nodes[0]], 1_000_000).1;
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let (_, _, chan_id, funding_tx) =
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 1_000_000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 1_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
nodes[0].node.close_channel(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
let node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_closing_signed);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let (_, _, chan_id, funding_tx) =
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 1_000_000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 1_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
// Create a single channel with two pending HTLCs from nodes[0] to nodes[1], one which nodes[1]
// knows the preimage for, one which it does not.
- let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 10_000_000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
+ let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
// Send two HTLCs, one from A to B, and one from B to A.
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let (_, _, chan_id, funding_tx) =
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 100_000_000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 100_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
// Create some initial channels
let (_, _, chan_id, funding_tx) =
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 11_000_000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 11_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let (_, _, chan_id, funding_tx) =
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 100_000_000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 100_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
/// An error in decoding a message or struct.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DecodeError {
/// A version byte specified something we don't know how to handle.
/// Includes unknown realm byte in an OnionHopData packet
}
/// An init message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Init {
/// The relevant features which the sender supports
pub features: InitFeatures,
}
/// An error message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ErrorMessage {
/// The channel ID involved in the error.
///
}
/// A warning message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct WarningMessage {
/// The channel ID involved in the warning.
///
}
/// A ping message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Ping {
/// The desired response length
pub ponglen: u16,
}
/// A pong message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Pong {
/// The pong packet size.
/// This field is not sent on the wire. byteslen zeros are sent.
}
/// An open_channel message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OpenChannel {
/// The genesis hash of the blockchain where the channel is to be opened
pub chain_hash: BlockHash,
}
/// An accept_channel message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AcceptChannel {
/// A temporary channel ID, until the funding outpoint is announced
pub temporary_channel_id: [u8; 32],
}
/// A funding_created message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FundingCreated {
/// A temporary channel ID, until the funding is established
pub temporary_channel_id: [u8; 32],
}
/// A funding_signed message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FundingSigned {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A channel_ready message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelReady {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A shutdown message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Shutdown {
/// The channel ID
pub channel_id: [u8; 32],
/// The minimum and maximum fees which the sender is willing to place on the closing transaction.
/// This is provided in [`ClosingSigned`] by both sides to indicate the fee range they are willing
/// to use.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClosingSignedFeeRange {
/// The minimum absolute fee, in satoshis, which the sender is willing to place on the closing
/// transaction.
}
/// A closing_signed message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClosingSigned {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_add_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateAddHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An onion message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OnionMessage {
/// Used in decrypting the onion packet's payload.
pub blinding_point: PublicKey,
}
/// An update_fulfill_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFulfillHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_fail_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFailHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_fail_malformed_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFailMalformedHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A commitment_signed message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CommitmentSigned {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A revoke_and_ack message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RevokeAndACK {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_fee message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFee {
/// The channel ID
pub channel_id: [u8; 32],
pub feerate_per_kw: u32,
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// Proof that the sender knows the per-commitment secret of the previous commitment transaction.
/// This is used to convince the recipient that the channel is at a certain commitment
/// number even if they lost that data due to a local failure. Of course, the peer may lie
}
/// A channel_reestablish message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelReestablish {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An announcement_signatures message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AnnouncementSignatures {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An address which can be used to connect to a remote peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NetAddress {
/// An IPv4 address/port on which the peer is listening.
IPv4 {
/// The unsigned part of a node_announcement
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnsignedNodeAnnouncement {
/// The advertised features
pub features: NodeFeatures,
pub(crate) excess_address_data: Vec<u8>,
pub(crate) excess_data: Vec<u8>,
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// A node_announcement message to be sent or received from a peer
pub struct NodeAnnouncement {
/// The signature by the node key
}
/// The unsigned part of a channel_announcement
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnsignedChannelAnnouncement {
/// The advertised channel features
pub features: ChannelFeatures,
pub(crate) excess_data: Vec<u8>,
}
/// A channel_announcement message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelAnnouncement {
/// Authentication of the announcement by the first public node
pub node_signature_1: Signature,
}
/// The unsigned part of a channel_update
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnsignedChannelUpdate {
/// The genesis hash of the blockchain where the channel is to be opened
pub chain_hash: BlockHash,
pub excess_data: Vec<u8>,
}
/// A channel_update message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelUpdate {
/// A signature of the channel update
pub signature: Signature,
/// UTXOs in a range of blocks. The recipient of a query makes a best
/// effort to reply to the query using one or more reply_channel_range
/// messages.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryChannelRange {
/// The genesis hash of the blockchain being queried
pub chain_hash: BlockHash,
/// not be a perfect view of the network. The short_channel_ids in the
/// reply are encoded. We only support encoding_type=0 uncompressed
/// serialization and do not support encoding_type=1 zlib serialization.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReplyChannelRange {
/// The genesis hash of the blockchain being queried
pub chain_hash: BlockHash,
/// reply_short_channel_ids_end message. The short_channel_ids sent in
/// this query are encoded. We only support encoding_type=0 uncompressed
/// serialization and do not support encoding_type=1 zlib serialization.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryShortChannelIds {
/// The genesis hash of the blockchain being queried
pub chain_hash: BlockHash,
/// query_short_channel_ids message. The query recipient makes a best
/// effort to respond based on their local network view which may not be
/// a perfect view of the network.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReplyShortChannelIdsEnd {
/// The genesis hash of the blockchain that was queried
pub chain_hash: BlockHash,
/// A gossip_timestamp_filter message is used by a node to request
/// gossip relay for messages in the requested time range when the
/// gossip_queries feature has been negotiated.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GossipTimestampFilter {
/// The genesis hash of the blockchain for channel and node information
pub chain_hash: BlockHash,
/// Struct used to return values from revoke_and_ack messages, containing a bunch of commitment
/// transaction updates if they were pending.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CommitmentUpdate {
/// update_add_htlc messages which should be sent
pub update_add_htlcs: Vec<UpdateAddHTLC>,
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
/// (C-not exported) due to a free generic in T
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
/// is believed to be possible in the future (eg they're sending us messages we don't
/// understand or indicate they require unknown feature bits), no_connection_possible is set
/// and any outstanding channels should be failed.
+ ///
+ /// Note that in some rare cases this may be called without a corresponding
+ /// [`Self::peer_connected`].
fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
/// Handle a peer reconnecting, possibly generating channel_reestablish message(s).
- fn peer_connected(&self, their_node_id: &PublicKey, msg: &Init);
+ ///
+ /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
+ /// with us. Implementors should be somewhat conservative about doing so, however, as other
+ /// message handlers may still wish to communicate with this peer.
+ fn peer_connected(&self, their_node_id: &PublicKey, msg: &Init) -> Result<(), ()>;
/// Handle an incoming channel_reestablish message from the given peer.
fn handle_channel_reestablish(&self, their_node_id: &PublicKey, msg: &ChannelReestablish);
/// Called when a connection is established with a peer. This can be used to
/// perform routing table synchronization using a strategy defined by the
/// implementor.
- fn peer_connected(&self, their_node_id: &PublicKey, init: &Init);
+ ///
+ /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
+ /// with us. Implementors should be somewhat conservative about doing so, however, as other
+ /// message handlers may still wish to communicate with this peer.
+ fn peer_connected(&self, their_node_id: &PublicKey, init: &Init) -> Result<(), ()>;
/// Handles the reply of a query we initiated to learn about channels
/// for a given range of blocks. We can expect to receive one or more
/// replies to a single query.
fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage);
/// Called when a connection is established with a peer. Can be used to track which peers
/// advertise onion message support and are online.
- fn peer_connected(&self, their_node_id: &PublicKey, init: &Init);
+ ///
+ /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
+ /// with us. Implementors should be somewhat conservative about doing so, however, as other
+ /// message handlers may still wish to communicate with this peer.
+ fn peer_connected(&self, their_node_id: &PublicKey, init: &Init) -> Result<(), ()>;
/// Indicates a connection to the peer failed/an existing connection was lost. Allows handlers to
/// drop and refuse to forward onion messages to this peer.
+ ///
+ /// Note that in some rare cases this may be called without a corresponding
+ /// [`Self::peer_connected`].
fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
// Handler information:
}
}
+impl Eq for OnionPacket { }
impl PartialEq for OnionPacket {
fn eq(&self, other: &OnionPacket) -> bool {
for (i, j) in self.hop_data.iter().zip(other.hop_data.iter()) {
}
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct OnionErrorPacket {
// This really should be a constant size slice, but the spec lets these things be up to 128KB?
// (TODO) We limit it in decode to much lower...
let sig_2 = get_sig_on!(privkey_2, secp_ctx, String::from("01010101010101010101010101010101"));
let sig_3 = get_sig_on!(privkey_3, secp_ctx, String::from("01010101010101010101010101010101"));
let sig_4 = get_sig_on!(privkey_4, secp_ctx, String::from("01010101010101010101010101010101"));
- let mut features = ChannelFeatures::known();
+ let mut features = ChannelFeatures::empty();
if unknown_features_bits {
features = ChannelFeatures::from_le_bytes(vec![0xFF, 0xFF]);
}
use chain::keysinterface::{KeysInterface, Recipient};
use ln::{PaymentHash, PaymentSecret};
use ln::channel::EXPIRE_PREV_CONFIG_TICKS;
-use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
+use ln::channelmanager::{self, ChannelManager, ChannelManagerReadArgs, HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
use ln::onion_utils;
use routing::gossip::{NetworkUpdate, RoutingFees, NodeId};
use routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop};
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config), Some(config), Some(config)]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()), create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known())];
+ let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()), create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features())];
// positive case
let (route, payment_hash_success, payment_preimage_success, payment_secret_success) = get_route_and_payment_hash!(nodes[0], nodes[2], 40_000);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config), Some(config), Some(node_2_cfg)]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()), create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known())];
+ let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()), create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features())];
for node in nodes.iter() {
*node.keys_manager.override_random_bytes.lock().unwrap() = Some([3; 32]);
}
}, || {}, true, Some(17), None, None);
run_onion_failure_test("final_incorrect_cltv_expiry", 1, &nodes, &route, &payment_hash, &payment_secret, |_| {}, || {
- for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() {
+ for (_, pending_forwards) in nodes[1].node.forward_htlcs.lock().unwrap().iter_mut() {
for f in pending_forwards.iter_mut() {
match f {
&mut HTLCForwardInfo::AddHTLC { ref mut forward_info, .. } =>
run_onion_failure_test("final_incorrect_htlc_amount", 1, &nodes, &route, &payment_hash, &payment_secret, |_| {}, || {
// violate amt_to_forward > msg.amount_msat
- for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() {
+ for (_, pending_forwards) in nodes[1].node.forward_htlcs.lock().unwrap().iter_mut() {
for f in pending_forwards.iter_mut() {
match f {
&mut HTLCForwardInfo::AddHTLC { ref mut forward_info, .. } =>
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
let other_channel = create_chan_between_nodes(
- &nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known(),
+ &nodes[0], &nodes[1], channelmanager::provided_init_features(), channelmanager::provided_init_features(),
);
let channel_to_update = if announced_channel {
let channel = create_announced_chan_between_nodes(
- &nodes, 1, 2, InitFeatures::known(), InitFeatures::known(),
+ &nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features(),
);
(channel.2, channel.0.contents.short_channel_id)
} else {
let channel = create_unannounced_chan_between_nodes_with_value(
- &nodes, 1, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known(),
+ &nodes, 1, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features(),
);
(channel.0.channel_id, channel.0.short_channel_id_alias.unwrap())
};
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(*channel_to_update_counterparty)
- .with_features(InvoiceFeatures::known())
+ .with_features(channelmanager::provided_invoice_features())
.with_route_hints(hop_hints);
get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, PAYMENT_AMT, TEST_FINAL_CLTV)
};
let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, Some(priv_channels_conf)]);
let mut nodes = create_network(5, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
- create_unannounced_chan_between_nodes_with_value(&nodes, 3, 4, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_unannounced_chan_between_nodes_with_value(&nodes, 3, 4, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id());
let origin_node = &nodes[0];
// supports variable length onions, as the `InitFeatures` exchanged in the init message
// between the nodes will be used when creating the route. We therefore do not default to
// supporting variable length onions for that hop, as the `InitFeatures` in this case are
- // `InitFeatures::known()`.
+ // `channelmanager::provided_init_features()`.
let unannounced_chan = &nodes[4].node.list_usable_channels()[0];
let chanmon_cfgs = create_chanmon_cfgs(4);
let mut node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
- // Set `node[1]` config to `InitFeatures::empty()` which return `false` for
- // `supports_variable_length_onion()`
+ // Set `node[1]` config to `InitFeatures::empty()` + `static_remote_key` which implies
+ // `!supports_variable_length_onion()` but still supports the required static-remote-key
+ // feature.
let mut node_1_cfg = &mut node_cfgs[1];
node_1_cfg.features = InitFeatures::empty();
+ node_1_cfg.features.set_static_remote_key_required();
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id())
.with_features(InvoiceFeatures::empty());
let phantom_pubkey = PublicKey::from_secret_key(&secp_ctx, &phantom_secret);
let phantom_route_hint = $nodes[1].node.get_phantom_route_hints();
let payment_params = PaymentParameters::from_node_id(phantom_pubkey)
- .with_features(InvoiceFeatures::known())
+ .with_features(channelmanager::provided_invoice_features())
.with_route_hints(vec![RouteHint(vec![
RouteHintHop {
src_node_id: $nodes[0].node.get_our_node_id(),
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the route.
let recv_value_msat = 10_000;
// Modify the payload so the phantom hop's HMAC is bogus.
let sha256_of_onion = {
- let mut channel_state = nodes[1].node.channel_state.lock().unwrap();
- let mut pending_forward = channel_state.forward_htlcs.get_mut(&phantom_scid).unwrap();
+ let mut forward_htlcs = nodes[1].node.forward_htlcs.lock().unwrap();
+ let mut pending_forward = forward_htlcs.get_mut(&phantom_scid).unwrap();
match pending_forward[0] {
HTLCForwardInfo::AddHTLC {
forward_info: PendingHTLCInfo {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the route.
let recv_value_msat = 10_000;
commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
// Modify the onion packet to have an invalid payment amount.
- for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() {
+ for (_, pending_forwards) in nodes[1].node.forward_htlcs.lock().unwrap().iter_mut() {
for f in pending_forwards.iter_mut() {
match f {
&mut HTLCForwardInfo::AddHTLC {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the route.
let recv_value_msat = 10_000;
commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
// Modify the payload so the phantom hop's HMAC is bogus.
- for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() {
+ for (_, pending_forwards) in nodes[1].node.forward_htlcs.lock().unwrap().iter_mut() {
for f in pending_forwards.iter_mut() {
match f {
&mut HTLCForwardInfo::AddHTLC {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the route.
let recv_value_msat = 10_000;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the route with a too-low amount.
let recv_amt_msat = 10_000;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(receiver_config)]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the route with an amount exceeding the dust exposure threshold of nodes[1].
let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(max_dust_exposure + 1));
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the route with a too-low amount.
let recv_amt_msat = 10_000;
if fixed_time_eq(&Hmac::from_engine(hmac).into_inner(), &err_packet.hmac) {
if let Some(error_code_slice) = err_packet.failuremsg.get(0..2) {
+ const BADONION: u16 = 0x8000;
const PERM: u16 = 0x4000;
const NODE: u16 = 0x2000;
const UPDATE: u16 = 0x1000;
let mut network_update = None;
let mut short_channel_id = None;
- if error_code & NODE == NODE {
+ if error_code & BADONION == BADONION {
+ // If the error code has the BADONION bit set, always blame the channel
+ // from the node "originating" the error to its next hop. The
+ // "originator" is ultimately actually claiming that its counterparty
+ // is the one who is failing the HTLC.
+ // If the "originator" here isn't lying we should really mark the
+ // next-hop node as failed entirely, but we can't be confident in that,
+ // as it would allow any node to get us to completely ban one of its
+ // counterparties. Instead, we simply remove the channel in question.
+ network_update = Some(NetworkUpdate::ChannelFailure {
+ short_channel_id: failing_route_hop.short_channel_id,
+ is_permanent: true,
+ });
+ } else if error_code & NODE == NODE {
let is_permanent = error_code & PERM == PERM;
network_update = Some(NetworkUpdate::NodeFailure { node_id: route_hop.pubkey, is_permanent });
short_channel_id = Some(route_hop.short_channel_id);
- }
- else if error_code & PERM == PERM {
+ } else if error_code & PERM == PERM {
if !payment_failed {
network_update = Some(NetworkUpdate::ChannelFailure {
short_channel_id: failing_route_hop.short_channel_id,
});
short_channel_id = Some(failing_route_hop.short_channel_id);
}
- }
- else if error_code & UPDATE == UPDATE {
+ } else if error_code & UPDATE == UPDATE {
if let Some(update_len_slice) = err_packet.failuremsg.get(debug_field_size+2..debug_field_size+4) {
let update_len = u16::from_be_bytes(update_len_slice.try_into().expect("len is 2")) as usize;
if let Some(mut update_slice) = err_packet.failuremsg.get(debug_field_size + 4..debug_field_size + 4 + update_len) {
short_channel_id = Some(route_hop.short_channel_id);
}
- // TODO: Here (and a few other places) we assume that BADONION errors
- // are always "sourced" from the node previous to the one which failed
- // to decode the onion.
res = Some((network_update, short_channel_id, !(error_code & PERM == PERM && is_from_final_node)));
let (description, title) = errors::get_onion_error_description(error_code);
//! serialization ordering between ChannelManager/ChannelMonitors and ensuring we can still retry
//! payments thereafter.
-use chain::{ChannelMonitorUpdateErr, Confirm, Listen, Watch};
+use chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch};
use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS};
use chain::transaction::OutPoint;
use chain::keysinterface::KeysInterface;
use ln::channel::EXPIRE_PREV_CONFIG_TICKS;
-use ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure};
-use ln::features::{InitFeatures, InvoiceFeatures};
+use ln::channelmanager::{self, BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure};
use ln::msgs;
use ln::msgs::ChannelMessageHandler;
use routing::router::{PaymentParameters, get_route};
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let _chan_0 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_1 = create_announced_chan_between_nodes(&nodes, 2, 1, InitFeatures::known(), InitFeatures::known());
+ let _chan_0 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 2, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance to find a route
send_payment(&nodes[2], &vec!(&nodes[1])[..], 3_000_000);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
- let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+ let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
+ let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
let (mut route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[3], 100000);
let path = route.paths[0].clone();
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let (chan_1_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let (chan_2_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known());
- let (chan_3_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known());
- let (chan_4_update, _, chan_4_id, _) = create_announced_chan_between_nodes(&nodes, 3, 2, InitFeatures::known(), InitFeatures::known());
+ let (chan_1_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (chan_2_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (chan_3_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (chan_4_update, _, chan_4_id, _) = create_announced_chan_between_nodes(&nodes, 3, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance
send_payment(&nodes[3], &vec!(&nodes[2])[..], 1_500_000);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
- let (chan_1_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let (chan_2_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known());
- let (chan_3_update, _, chan_3_id, _) = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::known(), InitFeatures::known());
- let (chan_4_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
+ let (chan_1_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (chan_2_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 0, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (chan_3_update, _, chan_3_id, _) = create_announced_chan_between_nodes(&nodes, 1, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let (chan_4_update, _, _, _) = create_announced_chan_between_nodes(&nodes, 2, 3, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[3], 100_000);
let path = route.paths[0].clone();
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let _chan_0 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_1 = create_announced_chan_between_nodes(&nodes, 2, 1, InitFeatures::known(), InitFeatures::known());
+ let _chan_0 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 2, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance to find a route
send_payment(&nodes[2], &vec!(&nodes[1])[..], 3_000_000);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
- let (_, _, chan_id_2, _) = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ let (_, _, chan_id_2, _) = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Serialize the ChannelManager prior to sending payments
let nodes_0_serialized = nodes[0].node.encode();
nodes_0_deserialized = nodes_0_deserialized_tmp;
assert!(nodes_0_read.is_empty());
- assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
nodes[0].node = &nodes_0_deserialized;
check_added_monitors!(nodes[0], 1);
assert_eq!(as_broadcasted_txn[0], as_commitment_tx);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
// Now nodes[1] should send a channel reestablish, which nodes[0] will respond to with an
// error, as the channel has hit the chain.
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
let as_err = nodes[0].node.get_and_clear_pending_msg_events();
// Create a new channel on which to retry the payment before we fail the payment via the
// HTLC-Timeout transaction. This avoids ChannelManager timing out the payment due to us
// connecting several blocks while creating the channel (implying time has passed).
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
assert_eq!(nodes[0].node.list_usable_channels().len(), 1);
mine_transaction(&nodes[1], &as_commitment_tx);
expect_payment_sent!(nodes[0], payment_preimage_1);
connect_blocks(&nodes[0], TEST_FINAL_CLTV*4 + 20);
let as_htlc_timeout_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
- assert_eq!(as_htlc_timeout_txn.len(), 3);
- let (first_htlc_timeout_tx, second_htlc_timeout_tx) = if as_htlc_timeout_txn[0] == as_commitment_tx {
- (&as_htlc_timeout_txn[1], &as_htlc_timeout_txn[2])
- } else {
- assert_eq!(as_htlc_timeout_txn[2], as_commitment_tx);
- (&as_htlc_timeout_txn[0], &as_htlc_timeout_txn[1])
- };
+ assert_eq!(as_htlc_timeout_txn.len(), 2);
+ let (first_htlc_timeout_tx, second_htlc_timeout_tx) = (&as_htlc_timeout_txn[0], &as_htlc_timeout_txn[1]);
check_spends!(first_htlc_timeout_tx, as_commitment_tx);
check_spends!(second_htlc_timeout_tx, as_commitment_tx);
if first_htlc_timeout_tx.input[0].previous_output == bs_htlc_claim_txn[0].input[0].previous_output {
// Ignore the announcement_signatures messages
nodes[0].node.get_and_clear_pending_msg_events();
nodes[1].node.get_and_clear_pending_msg_events();
- let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known()).2;
+ let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
// Serialize the ChannelManager prior to sending payments
let mut nodes_0_serialized = nodes[0].node.encode();
$chan_manager = nodes_0_deserialized_tmp;
assert!(nodes_0_read.is_empty());
- assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
if !chan_1_monitor_serialized.0.is_empty() {
let funding_txo = chan_1_monitor.as_ref().unwrap().get_funding_txo().0;
- assert!(nodes[0].chain_monitor.watch_channel(funding_txo, chan_1_monitor.unwrap()).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(funding_txo, chan_1_monitor.unwrap()),
+ ChannelMonitorUpdateStatus::Completed);
}
nodes[0].node = &$chan_manager;
check_added_monitors!(nodes[0], if !chan_1_monitor_serialized.0.is_empty() { 2 } else { 1 });
assert!(nodes[0].node.has_pending_payments());
assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0).len(), 1);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
// Now nodes[1] should send a channel reestablish, which nodes[0] will respond to with an
// error, as the channel has hit the chain.
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
let as_err = nodes[0].node.get_and_clear_pending_msg_events();
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Route a payment, but force-close the channel before the HTLC fulfill message arrives at
// nodes[0].
}
// Now connect the HTLC claim transaction with the ChainMonitor-generated ChannelMonitor update
- // returning TemporaryFailure. This should cause the claim event to never make its way to the
+ // returning InProgress. This should cause the claim event to never make its way to the
// ChannelManager.
chanmon_cfgs[0].persister.chain_sync_monitor_persistences.lock().unwrap().clear();
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
if payment_timeout {
connect_blocks(&nodes[0], 1);
// Now persist the ChannelMonitor and inform the ChainMonitor that we're done, generating the
// payment sent event.
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new());
get_monitor!(nodes[0], chan_id).write(&mut chan_0_monitor_serialized).unwrap();
for update in mon_updates {
};
nodes_0_deserialized = nodes_0_deserialized_tmp;
- assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
check_added_monitors!(nodes[0], 1);
nodes[0].node = &nodes_0_deserialized;
let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 100_000);
// The simplest way to get a failure after a fulfill is to reload nodes[1] from a state
};
nodes_1_deserialized = nodes_1_deserialized_tmp;
- assert!(nodes[1].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
+ assert_eq!(nodes[1].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
check_added_monitors!(nodes[1], 1);
nodes[1].node = &nodes_1_deserialized;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let amt_msat = 60_000;
let expiry_secs = 60 * 60;
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(amt_msat), expiry_secs).unwrap();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// First check we refuse to build a single-hop probe
let (route, _, _, _) = get_route_and_payment_hash!(&nodes[0], nodes[1], 100_000);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, _, _, _) = get_route_and_payment_hash!(&nodes[0], nodes[2], 100_000);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 90000000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 90000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id());
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
- create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id());
use io;
use alloc::collections::LinkedList;
use sync::{Arc, Mutex, MutexGuard, FairRwLock};
-use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
+use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use core::{cmp, hash, fmt, mem};
use core::ops::Deref;
use core::convert::Infallible;
fn get_next_channel_announcement(&self, _starting_point: u64) ->
Option<(msgs::ChannelAnnouncement, Option<msgs::ChannelUpdate>, Option<msgs::ChannelUpdate>)> { None }
fn get_next_node_announcement(&self, _starting_point: Option<&PublicKey>) -> Option<msgs::NodeAnnouncement> { None }
- fn peer_connected(&self, _their_node_id: &PublicKey, _init: &msgs::Init) {}
+ fn peer_connected(&self, _their_node_id: &PublicKey, _init: &msgs::Init) -> Result<(), ()> { Ok(()) }
fn handle_reply_channel_range(&self, _their_node_id: &PublicKey, _msg: msgs::ReplyChannelRange) -> Result<(), LightningError> { Ok(()) }
fn handle_reply_short_channel_ids_end(&self, _their_node_id: &PublicKey, _msg: msgs::ReplyShortChannelIdsEnd) -> Result<(), LightningError> { Ok(()) }
fn handle_query_channel_range(&self, _their_node_id: &PublicKey, _msg: msgs::QueryChannelRange) -> Result<(), LightningError> { Ok(()) }
}
impl OnionMessageHandler for IgnoringMessageHandler {
fn handle_onion_message(&self, _their_node_id: &PublicKey, _msg: &msgs::OnionMessage) {}
- fn peer_connected(&self, _their_node_id: &PublicKey, _init: &msgs::Init) {}
+ fn peer_connected(&self, _their_node_id: &PublicKey, _init: &msgs::Init) -> Result<(), ()> { Ok(()) }
fn peer_disconnected(&self, _their_node_id: &PublicKey, _no_connection_possible: bool) {}
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
// msgs::ChannelUpdate does not contain the channel_id field, so we just drop them.
fn handle_channel_update(&self, _their_node_id: &PublicKey, _msg: &msgs::ChannelUpdate) {}
fn peer_disconnected(&self, _their_node_id: &PublicKey, _no_connection_possible: bool) {}
- fn peer_connected(&self, _their_node_id: &PublicKey, _msg: &msgs::Init) {}
+ fn peer_connected(&self, _their_node_id: &PublicKey, _init: &msgs::Init) -> Result<(), ()> { Ok(()) }
fn handle_error(&self, _their_node_id: &PublicKey, _msg: &msgs::ErrorMessage) {}
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
- // Use our known channel feature set as peers may otherwise not be willing to talk to us at
- // all.
- InitFeatures::known_channel_features()
+ // Set a number of features which various nodes may require to talk to us. It's totally
+ // reasonable to indicate we "support" all kinds of channel features...we just reject all
+ // channels.
+ let mut features = InitFeatures::empty();
+ features.set_data_loss_protect_optional();
+ features.set_upfront_shutdown_script_optional();
+ features.set_variable_length_onion_optional();
+ features.set_static_remote_key_optional();
+ features.set_payment_secret_optional();
+ features.set_basic_mpp_optional();
+ features.set_wumbo_optional();
+ features.set_shutdown_any_segwit_optional();
+ features.set_channel_type_optional();
+ features.set_scid_privacy_optional();
+ features.set_zero_conf_optional();
+ features
}
}
impl Deref for ErroringMessageHandler {
/// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
/// value increases strictly since we don't assume access to a time source.
- last_node_announcement_serial: AtomicU64,
+ last_node_announcement_serial: AtomicU32,
our_node_secret: SecretKey,
ephemeral_key_midstate: Sha256Engine,
/// minute should suffice.
///
/// (C-not exported) as we can't export a PeerManager with a dummy route handler
- pub fn new_channel_only(channel_message_handler: CM, onion_message_handler: OM, our_node_secret: SecretKey, current_time: u64, ephemeral_random_data: &[u8; 32], logger: L) -> Self {
+ pub fn new_channel_only(channel_message_handler: CM, onion_message_handler: OM, our_node_secret: SecretKey, current_time: u32, ephemeral_random_data: &[u8; 32], logger: L) -> Self {
Self::new(MessageHandler {
chan_handler: channel_message_handler,
route_handler: IgnoringMessageHandler{},
/// cryptographically secure random bytes.
///
/// (C-not exported) as we can't export a PeerManager with a dummy channel handler
- pub fn new_routing_only(routing_message_handler: RM, our_node_secret: SecretKey, current_time: u64, ephemeral_random_data: &[u8; 32], logger: L) -> Self {
+ pub fn new_routing_only(routing_message_handler: RM, our_node_secret: SecretKey, current_time: u32, ephemeral_random_data: &[u8; 32], logger: L) -> Self {
Self::new(MessageHandler {
chan_handler: ErroringMessageHandler::new(),
route_handler: routing_message_handler,
/// incremented irregularly internally. In general it is best to simply use the current UNIX
/// timestamp, however if it is not available a persistent counter that increases once per
/// minute should suffice.
- pub fn new(message_handler: MessageHandler<CM, RM, OM>, our_node_secret: SecretKey, current_time: u64, ephemeral_random_data: &[u8; 32], logger: L, custom_message_handler: CMH) -> Self {
+ pub fn new(message_handler: MessageHandler<CM, RM, OM>, our_node_secret: SecretKey, current_time: u32, ephemeral_random_data: &[u8; 32], logger: L, custom_message_handler: CMH) -> Self {
let mut ephemeral_key_midstate = Sha256::engine();
ephemeral_key_midstate.input(ephemeral_random_data);
our_node_secret,
ephemeral_key_midstate,
peer_counter: AtomicCounter::new(),
- last_node_announcement_serial: AtomicU64::new(current_time),
+ last_node_announcement_serial: AtomicU32::new(current_time),
logger,
custom_message_handler,
secp_ctx,
peer_lock.sync_status = InitSyncTracker::ChannelsSyncing(0);
}
- if !msg.features.supports_static_remote_key() {
- log_debug!(self.logger, "Peer {} does not support static remote key, disconnecting with no_connection_possible", log_pubkey!(their_node_id));
+ if let Err(()) = self.message_handler.route_handler.peer_connected(&their_node_id, &msg) {
+ log_debug!(self.logger, "Route Handler decided we couldn't communicate with peer {}", log_pubkey!(their_node_id));
+ return Err(PeerHandleError{ no_connection_possible: true }.into());
+ }
+ if let Err(()) = self.message_handler.chan_handler.peer_connected(&their_node_id, &msg) {
+ log_debug!(self.logger, "Channel Handler decided we couldn't communicate with peer {}", log_pubkey!(their_node_id));
+ return Err(PeerHandleError{ no_connection_possible: true }.into());
+ }
+ if let Err(()) = self.message_handler.onion_message_handler.peer_connected(&their_node_id, &msg) {
+ log_debug!(self.logger, "Onion Message Handler decided we couldn't communicate with peer {}", log_pubkey!(their_node_id));
return Err(PeerHandleError{ no_connection_possible: true }.into());
}
-
- self.message_handler.route_handler.peer_connected(&their_node_id, &msg);
- self.message_handler.chan_handler.peer_connected(&their_node_id, &msg);
- self.message_handler.onion_message_handler.peer_connected(&their_node_id, &msg);
peer_lock.their_features = Some(msg.features);
return Ok(None);
.or(self.message_handler.onion_message_handler.provided_node_features());
let announcement = msgs::UnsignedNodeAnnouncement {
features,
- timestamp: self.last_node_announcement_serial.fetch_add(1, Ordering::AcqRel) as u32,
+ timestamp: self.last_node_announcement_serial.fetch_add(1, Ordering::AcqRel),
node_id: PublicKey::from_secret_key(&self.secp_ctx, &self.our_node_secret),
rgb, alias, addresses,
excess_address_data: Vec::new(),
//! other behavior that exists only on private channels or with a semi-trusted counterparty (eg
//! LSP).
-use chain::{ChannelMonitorUpdateErr, Watch};
+use chain::{ChannelMonitorUpdateStatus, Watch};
use chain::channelmonitor::ChannelMonitor;
use chain::keysinterface::{Recipient, KeysInterface};
-use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, MIN_CLTV_EXPIRY_DELTA};
+use ln::channelmanager::{self, ChannelManager, ChannelManagerReadArgs, MIN_CLTV_EXPIRY_DELTA};
use routing::gossip::RoutingFees;
use routing::router::{PaymentParameters, RouteHint, RouteHintHop};
-use ln::features::{InitFeatures, InvoiceFeatures, ChannelTypeFeatures};
+use ln::features::ChannelTypeFeatures;
use ln::msgs;
use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, ChannelUpdate, ErrorAction};
use ln::wire::Encode;
let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_id_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).2;
- let chan_id_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).0.channel_id;
+ let chan_id_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ let chan_id_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.channel_id;
// We should always be able to forward through nodes[1] as long as its out through a public
// channel:
}]);
let last_hops = vec![route_hint];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
- .with_features(InvoiceFeatures::known())
+ .with_features(channelmanager::provided_invoice_features())
.with_route_hints(last_hops);
let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 10_000, TEST_FINAL_CLTV);
assert!(nodes_1_read.is_empty());
nodes_1_deserialized = nodes_1_deserialized_tmp;
- assert!(nodes[1].chain_monitor.watch_channel(monitor_a.get_funding_txo().0, monitor_a).is_ok());
- assert!(nodes[1].chain_monitor.watch_channel(monitor_b.get_funding_txo().0, monitor_b).is_ok());
+ assert_eq!(nodes[1].chain_monitor.watch_channel(monitor_a.get_funding_txo().0, monitor_a),
+ ChannelMonitorUpdateStatus::Completed);
+ assert_eq!(nodes[1].chain_monitor.watch_channel(monitor_b.get_funding_txo().0, monitor_b),
+ ChannelMonitorUpdateStatus::Completed);
check_added_monitors!(nodes[1], 2);
nodes[1].node = &nodes_1_deserialized;
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let as_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_reestablish);
get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
- nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), remote_network_address: None });
- nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
+ nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[2]).pop().unwrap();
let cs_reestablish = get_chan_reestablish_msgs!(nodes[2], nodes[1]).pop().unwrap();
nodes[2].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
*nodes[0].connect_style.borrow_mut() = connect_style;
- let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
mine_transaction(&nodes[1], &tx);
nodes[0].node.handle_channel_ready(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendChannelReady, nodes[0].node.get_our_node_id()));
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(no_announce_cfg), None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).2;
- let mut as_channel_ready = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).0;
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
+ let mut as_channel_ready = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0;
let last_hop = nodes[2].node.list_usable_channels();
let hop_hints = vec![RouteHint(vec![RouteHintHop {
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
- .with_features(InvoiceFeatures::known())
+ .with_features(channelmanager::provided_invoice_features())
.with_route_hints(hop_hints);
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 100_000, 42);
assert_eq!(route.paths[0][1].short_channel_id, last_hop[0].inbound_scid_alias.unwrap());
open_channel.channel_type.as_mut().unwrap().set_scid_privacy_required();
assert_eq!(open_channel.channel_flags & 1, 1); // The `announce_channel` bit is set.
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let err = get_err_msg!(nodes[1], nodes[0].node.get_our_node_id());
assert_eq!(err.data, "SCID Alias/Privacy Channel Type cannot be set on a public channel");
}
let second_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
assert!(!second_open_channel.channel_type.as_ref().unwrap().supports_scid_privacy());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &second_open_channel);
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &second_open_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(accept_forward_cfg), None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let mut no_announce_cfg = test_default_channel_config();
no_announce_cfg.channel_handshake_config.announced_channel = false;
assert!(open_channel.channel_type.as_ref().unwrap().requires_scid_privacy());
- nodes[2].node.handle_open_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[2].node.handle_open_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let accept_channel = get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_accept_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[1].node.handle_accept_channel(&nodes[2].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[1], &nodes[2].node.get_our_node_id(), 100_000, 42);
nodes[1].node.funding_transaction_generated(&temporary_channel_id, &nodes[2].node.get_our_node_id(), tx.clone()).unwrap();
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
- .with_features(InvoiceFeatures::known())
+ .with_features(channelmanager::provided_invoice_features())
.with_route_hints(hop_hints.clone());
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 100_000, 42);
assert_eq!(route.paths[0][1].short_channel_id, last_hop[0].inbound_scid_alias.unwrap());
hop_hints[0].0[0].short_channel_id = last_hop[0].short_channel_id.unwrap();
let payment_params_2 = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
- .with_features(InvoiceFeatures::known())
+ .with_features(channelmanager::provided_invoice_features())
.with_route_hints(hop_hints);
let (route_2, payment_hash_2, _, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params_2, 100_000, 42);
assert_eq!(route_2.paths[0][1].short_channel_id, last_hop[0].short_channel_id.unwrap());
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(accept_forward_cfg), None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, InitFeatures::known(), InitFeatures::known());
- let chan = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let last_hop = nodes[2].node.list_usable_channels();
let mut hop_hints = vec![RouteHint(vec![RouteHintHop {
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
- .with_features(InvoiceFeatures::known())
+ .with_features(channelmanager::provided_invoice_features())
.with_route_hints(hop_hints);
let (mut route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 10_000, 42);
assert_eq!(route.paths[0][1].short_channel_id, nodes[2].node.list_usable_channels()[0].inbound_scid_alias.unwrap());
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(chan_config), None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
chan_config.channel_handshake_config.announced_channel = false;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(chan_config)).unwrap();
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let events = nodes[1].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
assert_eq!(accept_channel.minimum_depth, 0);
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let (temporary_channel_id, tx, funding_output) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42);
nodes[0].node.funding_transaction_generated(&temporary_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).unwrap();
let funding_created = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created);
check_added_monitors!(nodes[1], 1);
assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
let bs_signed_locked = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(bs_signed_locked.len(), 2);
- chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
match &bs_signed_locked[0] {
MessageSendEvent::SendFundingSigned { node_id, msg } => {
_ => panic!("Unexpected event"),
};
- chanmon_cfgs[0].persister.set_update_ret(Ok(()));
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &bs_channel_update);
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &as_channel_update);
nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bs_commitment_signed);
check_added_monitors!(nodes[0], 1);
- chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendRevokeAndACK, nodes[1].node.get_our_node_id()));
check_added_monitors!(nodes[1], 1);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
- chanmon_cfgs[1].persister.set_update_ret(Ok(()));
+ chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
let (outpoint, _, latest_update) = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&bs_raa.channel_id).unwrap().clone();
nodes[1].chain_monitor.chain_monitor.channel_monitor_updated(outpoint, latest_update).unwrap();
check_added_monitors!(nodes[1], 0);
open_channel_msg.channel_type = Some(channel_type_features.clone());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel_msg);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel_msg);
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
match msg_events[0] {
open_channel_msg.channel_type = Some(channel_type_features.clone());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(),
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(),
&open_channel_msg);
// Assert that `nodes[1]` has no `MessageSendEvent::SendAcceptChannel` in the `msg_events`.
open_channel_msg.channel_type = Some(channel_type_features);
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(),
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(),
&open_channel_msg);
let events = nodes[1].node.get_and_clear_pending_events();
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_001, 42, None).unwrap();
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let events = nodes[1].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
assert_eq!(accept_channel.minimum_depth, 0);
- nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), channelmanager::provided_init_features(), &accept_channel);
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor};
use chain::transaction::OutPoint;
-use chain::{Confirm, Watch};
-use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs};
-use ln::features::InitFeatures;
+use chain::{ChannelMonitorUpdateStatus, Confirm, Watch};
+use ln::channelmanager::{self, ChannelManager, ChannelManagerReadArgs};
use ln::msgs::ChannelMessageHandler;
use util::enforcing_trait_impls::EnforcingSigner;
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination};
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Make sure all nodes are at the same starting height
connect_blocks(&nodes[0], 2*CHAN_CONFIRM_DEPTH + 1 - nodes[0].best_block_info().1);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Get the initial commitment transaction for broadcast, before any HTLCs are added at all.
let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan.2);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
*nodes[0].connect_style.borrow_mut() = connect_style;
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let channel_state = nodes[0].node.channel_state.lock().unwrap();
assert_eq!(channel_state.by_id.len(), 1);
nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
}
- nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0.clone(), chan_0_monitor).unwrap();
+ assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0.clone(), chan_0_monitor),
+ ChannelMonitorUpdateStatus::Completed);
check_added_monitors!(nodes[0], 1);
}
nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
// Now check that we can create a new channel
- create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
send_payment(&nodes[0], &[&nodes[1]], 8000000);
}
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage_1, payment_hash_1, _) = route_payment(&nodes[1], &[&nodes[0]], 3_000_000);
let (payment_preimage_2, payment_hash_2, _) = route_payment(&nodes[1], &[&nodes[0]], 3_000_000);
*nodes[1].connect_style.borrow_mut() = style;
let (_, _, chan_id, funding_tx) =
- create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 100_000_000, InitFeatures::known(), InitFeatures::known());
+ create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 100_000_000, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
use bitcoin::secp256k1::PublicKey;
use bitcoin::util::address::WitnessVersion;
+use ln::channelmanager;
use ln::features::InitFeatures;
use ln::msgs::DecodeError;
use util::ser::{Readable, Writeable, Writer};
/// A script pubkey for shutting down a channel as defined by [BOLT #2].
///
/// [BOLT #2]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub struct ShutdownScript(ShutdownScriptImpl);
/// An error occurring when converting from [`Script`] to [`ShutdownScript`].
pub script: Script
}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
enum ShutdownScriptImpl {
/// [`PublicKey`] used to form a P2WPKH script pubkey. Used to support backward-compatible
/// serialization.
type Error = InvalidShutdownScript;
fn try_from(script: Script) -> Result<Self, Self::Error> {
- Self::try_from((script, &InitFeatures::known()))
+ Self::try_from((script, &channelmanager::provided_init_features()))
}
}
.into_script()
}
+ fn any_segwit_features() -> InitFeatures {
+ let mut features = InitFeatures::empty();
+ features.set_shutdown_any_segwit_optional();
+ features
+ }
+
#[test]
fn generates_p2wpkh_from_pubkey() {
let pubkey = pubkey();
let p2wpkh_script = Script::new_v0_p2wpkh(&pubkey_hash);
let shutdown_script = ShutdownScript::new_p2wpkh_from_pubkey(pubkey.inner);
- assert!(shutdown_script.is_compatible(&InitFeatures::known()));
- assert!(shutdown_script.is_compatible(&InitFeatures::known().clear_shutdown_anysegwit()));
+ assert!(shutdown_script.is_compatible(&any_segwit_features()));
+ assert!(shutdown_script.is_compatible(&InitFeatures::empty()));
assert_eq!(shutdown_script.into_inner(), p2wpkh_script);
}
let p2wpkh_script = Script::new_v0_p2wpkh(&pubkey_hash);
let shutdown_script = ShutdownScript::new_p2wpkh(&pubkey_hash);
- assert!(shutdown_script.is_compatible(&InitFeatures::known()));
- assert!(shutdown_script.is_compatible(&InitFeatures::known().clear_shutdown_anysegwit()));
+ assert!(shutdown_script.is_compatible(&any_segwit_features()));
+ assert!(shutdown_script.is_compatible(&InitFeatures::empty()));
assert_eq!(shutdown_script.into_inner(), p2wpkh_script);
assert!(ShutdownScript::try_from(p2wpkh_script).is_ok());
}
let p2wsh_script = Script::new_v0_p2wsh(&script_hash);
let shutdown_script = ShutdownScript::new_p2wsh(&script_hash);
- assert!(shutdown_script.is_compatible(&InitFeatures::known()));
- assert!(shutdown_script.is_compatible(&InitFeatures::known().clear_shutdown_anysegwit()));
+ assert!(shutdown_script.is_compatible(&any_segwit_features()));
+ assert!(shutdown_script.is_compatible(&InitFeatures::empty()));
assert_eq!(shutdown_script.into_inner(), p2wsh_script);
assert!(ShutdownScript::try_from(p2wsh_script).is_ok());
}
fn generates_segwit_from_non_v0_witness_program() {
let witness_program = Script::new_witness_program(WitnessVersion::V16, &[0; 40]);
let shutdown_script = ShutdownScript::new_witness_program(WitnessVersion::V16, &[0; 40]).unwrap();
- assert!(shutdown_script.is_compatible(&InitFeatures::known()));
- assert!(!shutdown_script.is_compatible(&InitFeatures::known().clear_shutdown_anysegwit()));
+ assert!(shutdown_script.is_compatible(&any_segwit_features()));
+ assert!(!shutdown_script.is_compatible(&InitFeatures::empty()));
assert_eq!(shutdown_script.into_inner(), witness_program);
}
use chain::keysinterface::KeysInterface;
use chain::transaction::OutPoint;
-use ln::channelmanager::PaymentSendFailure;
+use ln::channelmanager::{self, PaymentSendFailure};
use routing::router::{PaymentParameters, get_route};
-use ln::features::{InitFeatures, InvoiceFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler, ErrorAction};
use ln::script::ShutdownScript;
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 8000000, 0, InitFeatures::known(), InitFeatures::known());
+ let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 8000000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
mine_transaction(&nodes[0], &tx);
mine_transaction(&nodes[1], &tx);
nodes[0].node.close_channel(&OutPoint { txid: tx.txid(), index: 0 }.to_channel_id(), &nodes[1].node.get_our_node_id()).unwrap();
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
let node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_closing_signed);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let logger = test_utils::TestLogger::new();
let scorer = test_utils::TestScorer::with_penalty(0);
let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
nodes[0].node.close_channel(&chan_1.2, &nodes[1].node.get_our_node_id()).unwrap();
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[0]);
- let payment_params_1 = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(InvoiceFeatures::known());
+ let payment_params_1 = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(channelmanager::provided_invoice_features());
let route_1 = get_route(&nodes[0].node.get_our_node_id(), &payment_params_1, &nodes[0].network_graph.read_only(), None, 100000, TEST_FINAL_CLTV, &logger, &scorer, &random_seed_bytes).unwrap();
- let payment_params_2 = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(InvoiceFeatures::known());
+ let payment_params_2 = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(channelmanager::provided_invoice_features());
let route_2 = get_route(&nodes[1].node.get_our_node_id(), &payment_params_2, &nodes[1].network_graph.read_only(), None, 100000, TEST_FINAL_CLTV, &logger, &scorer, &random_seed_bytes).unwrap();
unwrap_send_err!(nodes[0].node.send_payment(&route_1, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable {..}, {});
unwrap_send_err!(nodes[1].node.send_payment(&route_2, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable {..}, {});
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 100000);
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
nodes[1].node.close_channel(&chan_1.2, &nodes[0].node.get_our_node_id()).unwrap();
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &updates.commitment_signed);
check_added_monitors!(nodes[1], 1);
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
commitment_signed_dance!(nodes[1], nodes[0], (), false, true, false);
let updates_2 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 100_000);
nodes[1].node.close_channel(&chan_1.2, &nodes[0].node.get_our_node_id()).unwrap();
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
if recv_count > 0 {
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
if recv_count > 1 {
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
}
}
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let node_0_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let node_1_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &node_0_reestablish);
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &node_1_reestablish);
let node_0_2nd_shutdown = if recv_count > 0 {
let node_0_2nd_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_2nd_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_2nd_shutdown);
node_0_2nd_shutdown
} else {
let node_0_chan_update = get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
assert_eq!(node_0_chan_update.contents.flags & 2, 0); // "disabled" flag must not be set as we just reconnected.
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_2nd_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_2nd_shutdown);
get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id())
};
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_2nd_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_2nd_shutdown);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
let node_1_2nd_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
- nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None });
+ nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: channelmanager::provided_init_features(), remote_network_address: None }).unwrap();
if recv_count == 0 {
// If all closing_signeds weren't delivered we can just resume where we left off...
let node_0_2nd_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
let node_1_3rd_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
assert!(node_1_3rd_shutdown == node_1_2nd_shutdown);
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_3rd_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_3rd_shutdown);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_3rd_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_3rd_shutdown);
nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_2nd_closing_signed);
let node_1_closing_signed = get_event_msg!(nodes[1], MessageSendEvent::SendClosingSigned, nodes[0].node.get_our_node_id());
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
// We test that in case of peer committing upfront to a script, if it changes at closing, we refuse to sign
- let flags = InitFeatures::known();
+ let flags = channelmanager::provided_init_features();
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1000000, 1000000, flags.clone(), flags.clone());
nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[2].node.get_our_node_id()).unwrap();
let node_0_orig_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id());
node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh();
// Test we enforce upfront_scriptpbukey if by providing a different one at closing that we warn
// the peer and ignore the message.
- nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
assert!(regex::Regex::new(r"Got shutdown request with a scriptpubkey \([A-Fa-f0-9]+\) which did not match their previous scriptpubkey.")
.unwrap().is_match(&check_warn_msg!(nodes[2], nodes[0].node.get_our_node_id(), chan.2)));
// This allows nodes[2] to retry the shutdown message, which should get a response:
- nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_orig_shutdown);
+ nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_orig_shutdown);
get_event_msg!(nodes[2], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
// We test that in case of peer committing upfront to a script, if it doesn't change at closing, we sign
nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[2].node.get_our_node_id()).unwrap();
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id());
// We test that in case of peer committing upfront to a script, if it oesn't change at closing, we sign
- nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let events = nodes[2].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
match events[0] {
}
// We test that if case of peer non-signaling we don't enforce committed script at channel opening
- let flags_no = InitFeatures::known().clear_upfront_shutdown_script();
+ let flags_no = channelmanager::provided_init_features().clear_upfront_shutdown_script();
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, flags_no, flags.clone());
nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[1].node.get_our_node_id()).unwrap();
let node_1_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
check_added_monitors!(nodes[1], 1);
let events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap();
check_added_monitors!(nodes[1], 1);
let node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
match events[0] {
nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap();
check_added_monitors!(nodes[1], 1);
let node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 2);
match events[0] {
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// Use a non-v0 segwit script supported by option_shutdown_anysegwit
- let node_features = InitFeatures::known().clear_shutdown_anysegwit();
+ let node_features = channelmanager::provided_init_features().clear_shutdown_anysegwit();
let anysegwit_shutdown_script = Builder::new()
.push_int(16)
.push_slice(&[0, 40])
// Check script when handling an accept_channel message
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
accept_channel.shutdown_scriptpubkey = Present(anysegwit_shutdown_script.clone());
nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), node_features, &accept_channel);
open_channel.shutdown_scriptpubkey = Present(Builder::new().push_int(0)
.push_slice(&[0, 0])
.into_script());
- nodes[0].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ nodes[0].node.handle_open_channel(&nodes[0].node.get_our_node_id(), channelmanager::provided_init_features(), &open_channel);
let events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &user_cfgs);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap();
check_added_monitors!(nodes[1], 1);
node_0_shutdown.scriptpubkey = Builder::new().push_int(0)
.push_slice(&[0; 20])
.into_script();
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 2);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &user_cfgs);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap();
check_added_monitors!(nodes[1], 1);
node_0_shutdown.scriptpubkey = Builder::new().push_int(16)
.push_slice(&[0, 0])
.into_script();
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 2);
let user_cfgs = [None, Some(config), None];
let chanmon_cfgs = create_chanmon_cfgs(3);
let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
- node_cfgs[0].features = InitFeatures::known().clear_shutdown_anysegwit();
- node_cfgs[1].features = InitFeatures::known().clear_shutdown_anysegwit();
+ node_cfgs[0].features = channelmanager::provided_init_features().clear_shutdown_anysegwit();
+ node_cfgs[1].features = channelmanager::provided_init_features().clear_shutdown_anysegwit();
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &user_cfgs);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &user_cfgs);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap();
check_added_monitors!(nodes[1], 1);
node_0_shutdown.scriptpubkey = Builder::new().push_int(0)
.push_slice(&[0, 0])
.into_script();
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
assert_eq!(&check_warn_msg!(nodes[0], nodes[1].node.get_our_node_id(), chan.2),
"Got a nonstandard scriptpubkey (00020000) from remote peer");
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
+ let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
send_payment(&nodes[0], &[&nodes[1]], 8_000_000);
nodes[0].node.close_channel(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
{
// Now we set nodes[1] to require a relatively high feerate for closing. This should result
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
if high_initiator_fee {
// If high_initiator_fee is set, set nodes[0]'s feerate significantly higher. This
nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[1].node.get_our_node_id()).unwrap();
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
let mut node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
node_0_closing_signed.fee_range = None;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- let chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
let chan_id = OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id();
nodes[0].node.close_channel_with_target_feerate(&chan_id, &nodes[1].node.get_our_node_id(), 253 * 10).unwrap();
nodes[1].node.close_channel_with_target_feerate(&chan_id, &nodes[0].node.get_our_node_id(), 253 * 5).unwrap();
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
- nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
- nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
+ nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_0_shutdown);
+ nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &channelmanager::provided_init_features(), &node_1_shutdown);
let node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_closing_signed);
}
for idx in 0..num_messengers - 1 {
let i = idx as usize;
- let mut features = InitFeatures::known();
+ let mut features = InitFeatures::empty();
features.set_onion_messages_optional();
let init_msg = msgs::Init { features, remote_network_address: None };
- nodes[i].messenger.peer_connected(&nodes[i + 1].get_node_pk(), &init_msg.clone());
- nodes[i + 1].messenger.peer_connected(&nodes[i].get_node_pk(), &init_msg.clone());
+ nodes[i].messenger.peer_connected(&nodes[i + 1].get_node_pk(), &init_msg.clone()).unwrap();
+ nodes[i + 1].messenger.peer_connected(&nodes[i].get_node_pk(), &init_msg.clone()).unwrap();
}
nodes
}
/// Errors that may occur when [sending an onion message].
///
/// [sending an onion message]: OnionMessenger::send_onion_message
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Eq)]
pub enum SendError {
/// Errored computing onion message packet keys.
Secp256k1(secp256k1::Error),
};
}
- fn peer_connected(&self, their_node_id: &PublicKey, init: &msgs::Init) {
+ fn peer_connected(&self, their_node_id: &PublicKey, init: &msgs::Init) -> Result<(), ()> {
if init.features.supports_onion_messages() {
let mut peers = self.pending_messages.lock().unwrap();
peers.insert(their_node_id.clone(), VecDeque::new());
}
+ Ok(())
}
fn peer_disconnected(&self, their_node_id: &PublicKey, _no_connection_possible: bool) {
pub(super) const SMALL_PACKET_HOP_DATA_LEN: usize = 1300;
pub(super) const BIG_PACKET_HOP_DATA_LEN: usize = 32768;
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Packet {
pub(super) version: u8,
pub(super) public_key: PublicKey,
/// suggestion.
const STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS: u64 = 60 * 60 * 24 * 14;
+/// We stop tracking the removal of permanently failed nodes and channels one week after removal
+const REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS: u64 = 60 * 60 * 24 * 7;
+
/// The maximum number of extra bytes which we do not understand in a gossip message before we will
/// refuse to relay the message.
const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
// Lock order: channels -> nodes
channels: RwLock<BTreeMap<u64, ChannelInfo>>,
nodes: RwLock<BTreeMap<NodeId, NodeInfo>>,
+ // Lock order: removed_channels -> removed_nodes
+ //
+ // NOTE: In the following `removed_*` maps, we use seconds since UNIX epoch to track time instead
+ // of `std::time::Instant`s for a few reasons:
+ // * We want it to be possible to do tracking in no-std environments where we can compare
+ // a provided current UNIX timestamp with the time at which we started tracking.
+ // * In the future, if we decide to persist these maps, they will already be serializable.
+ // * Although we lose out on the platform's monotonic clock, the system clock in a std
+ // environment should be practical over the time period we are considering (on the order of a
+ // week).
+ //
+ /// Keeps track of short channel IDs for channels we have explicitly removed due to permanent
+ /// failure so that we don't resync them from gossip. Each SCID is mapped to the time (in seconds)
+ /// it was removed so that once some time passes, we can potentially resync it from gossip again.
+ removed_channels: Mutex<HashMap<u64, Option<u64>>>,
+ /// Keeps track of `NodeId`s we have explicitly removed due to permanent failure so that we don't
+ /// resync them from gossip. Each `NodeId` is mapped to the time (in seconds) it was removed so
+ /// that once some time passes, we can potentially resync it from gossip again.
+ removed_nodes: Mutex<HashMap<NodeId, Option<u64>>>,
}
/// A read-only view of [`NetworkGraph`].
/// return packet by a node along the route. See [BOLT #4] for details.
///
/// [BOLT #4]: https://github.com/lightning/bolts/blob/master/04-onion-routing.md
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NetworkUpdate {
/// An error indicating a `channel_update` messages should be applied via
/// [`NetworkGraph::update_channel`].
is_permanent: bool,
},
/// An error indicating that a node failed to route a payment, which should be applied via
- /// [`NetworkGraph::node_failed`].
+ /// [`NetworkGraph::node_failed_permanent`] if permanent.
NodeFailure {
/// The node id of the failed node.
node_id: PublicKey,
self.channel_failed(short_channel_id, is_permanent);
},
NetworkUpdate::NodeFailure { ref node_id, is_permanent } => {
- let action = if is_permanent { "Removing" } else { "Disabling" };
- log_debug!(self.logger, "{} node graph entry for {} due to a payment failure.", action, node_id);
- self.node_failed(node_id, is_permanent);
+ if is_permanent {
+ log_debug!(self.logger,
+ "Removed node graph entry for {} due to a payment failure.", log_pubkey!(node_id));
+ self.node_failed_permanent(node_id);
+ };
},
}
}
/// to request gossip messages for each channel. The sync is considered complete
/// when the final reply_scids_end message is received, though we are not
/// tracking this directly.
- fn peer_connected(&self, their_node_id: &PublicKey, init_msg: &Init) {
+ fn peer_connected(&self, their_node_id: &PublicKey, init_msg: &Init) -> Result<(), ()> {
// We will only perform a sync with peers that support gossip_queries.
if !init_msg.features.supports_gossip_queries() {
- return ();
+ // Don't disconnect peers for not supporting gossip queries. We may wish to have
+ // channels with peers even without being able to exchange gossip.
+ return Ok(());
}
// The lightning network's gossip sync system is completely broken in numerous ways.
timestamp_range: u32::max_value(),
},
});
+ Ok(())
}
fn handle_reply_channel_range(&self, _their_node_id: &PublicKey, _msg: ReplyChannelRange) -> Result<(), LightningError> {
}
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// Details about one direction of a channel as received within a [`ChannelUpdate`].
pub struct ChannelUpdateInfo {
/// When the last update to the channel direction was issued.
}
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// Details about a channel (both directions).
/// Received within a channel announcement.
pub struct ChannelInfo {
(2, proportional_millionths, required)
});
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// Information received in the latest node_announcement from this node.
pub struct NodeAnnouncementInfo {
/// Protocol features the node announced support for
///
/// Since node aliases are provided by third parties, they are a potential avenue for injection
/// attacks. Care must be taken when processing.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NodeAlias(pub [u8; 32]);
impl fmt::Display for NodeAlias {
}
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// Details about a node in the network, known from the network announcement.
pub struct NodeInfo {
/// All valid channels a node has announced
channels: RwLock::new(channels),
nodes: RwLock::new(nodes),
last_rapid_gossip_sync_timestamp: Mutex::new(last_rapid_gossip_sync_timestamp),
+ removed_nodes: Mutex::new(HashMap::new()),
+ removed_channels: Mutex::new(HashMap::new()),
})
}
}
}
}
+impl<L: Deref> Eq for NetworkGraph<L> where L::Target: Logger {}
impl<L: Deref> PartialEq for NetworkGraph<L> where L::Target: Logger {
fn eq(&self, other: &Self) -> bool {
self.genesis_hash == other.genesis_hash &&
channels: RwLock::new(BTreeMap::new()),
nodes: RwLock::new(BTreeMap::new()),
last_rapid_gossip_sync_timestamp: Mutex::new(None),
+ removed_channels: Mutex::new(HashMap::new()),
+ removed_nodes: Mutex::new(HashMap::new()),
}
}
return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError});
}
+ let node_one = NodeId::from_pubkey(&msg.node_id_1);
+ let node_two = NodeId::from_pubkey(&msg.node_id_2);
+
{
let channels = self.channels.read().unwrap();
// We use the Node IDs rather than the bitcoin_keys to check for "equivalence"
// as we didn't (necessarily) store the bitcoin keys, and we only really care
// if the peers on the channel changed anyway.
- if NodeId::from_pubkey(&msg.node_id_1) == chan.node_one && NodeId::from_pubkey(&msg.node_id_2) == chan.node_two {
+ if node_one == chan.node_one && node_two == chan.node_two {
return Err(LightningError {
err: "Already have chain-validated channel".to_owned(),
action: ErrorAction::IgnoreDuplicateGossip
}
}
+ {
+ let removed_channels = self.removed_channels.lock().unwrap();
+ let removed_nodes = self.removed_nodes.lock().unwrap();
+ if removed_channels.contains_key(&msg.short_channel_id) ||
+ removed_nodes.contains_key(&node_one) ||
+ removed_nodes.contains_key(&node_two) {
+ return Err(LightningError{
+ err: format!("Channel with SCID {} or one of its nodes was removed from our network graph recently", &msg.short_channel_id),
+ action: ErrorAction::IgnoreAndLog(Level::Gossip)});
+ }
+ }
+
let utxo_value = match &chain_access {
&None => {
// Tentatively accept, potentially exposing us to DoS attacks
let chan_info = ChannelInfo {
features: msg.features.clone(),
- node_one: NodeId::from_pubkey(&msg.node_id_1),
+ node_one,
one_to_two: None,
- node_two: NodeId::from_pubkey(&msg.node_id_2),
+ node_two,
two_to_one: None,
capacity_sats: utxo_value,
announcement_message: if msg.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY
/// May cause the removal of nodes too, if this was their last channel.
/// If not permanent, makes channels unavailable for routing.
pub fn channel_failed(&self, short_channel_id: u64, is_permanent: bool) {
+ #[cfg(feature = "std")]
+ let current_time_unix = Some(SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs());
+ #[cfg(not(feature = "std"))]
+ let current_time_unix = None;
+
let mut channels = self.channels.write().unwrap();
if is_permanent {
if let Some(chan) = channels.remove(&short_channel_id) {
let mut nodes = self.nodes.write().unwrap();
+ self.removed_channels.lock().unwrap().insert(short_channel_id, current_time_unix);
Self::remove_channel_in_nodes(&mut nodes, &chan, short_channel_id);
}
} else {
}
}
- /// Marks a node in the graph as failed.
- pub fn node_failed(&self, _node_id: &PublicKey, is_permanent: bool) {
- if is_permanent {
- // TODO: Wholly remove the node
- } else {
- // TODO: downgrade the node
+ /// Marks a node in the graph as permanently failed, effectively removing it and its channels
+ /// from local storage.
+ pub fn node_failed_permanent(&self, node_id: &PublicKey) {
+ #[cfg(feature = "std")]
+ let current_time_unix = Some(SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs());
+ #[cfg(not(feature = "std"))]
+ let current_time_unix = None;
+
+ let node_id = NodeId::from_pubkey(node_id);
+ let mut channels = self.channels.write().unwrap();
+ let mut nodes = self.nodes.write().unwrap();
+ let mut removed_channels = self.removed_channels.lock().unwrap();
+ let mut removed_nodes = self.removed_nodes.lock().unwrap();
+
+ if let Some(node) = nodes.remove(&node_id) {
+ for scid in node.channels.iter() {
+ if let Some(chan_info) = channels.remove(scid) {
+ let other_node_id = if node_id == chan_info.node_one { chan_info.node_two } else { chan_info.node_one };
+ if let BtreeEntry::Occupied(mut other_node_entry) = nodes.entry(other_node_id) {
+ other_node_entry.get_mut().channels.retain(|chan_id| {
+ *scid != *chan_id
+ });
+ if other_node_entry.get().channels.is_empty() {
+ other_node_entry.remove_entry();
+ }
+ }
+ removed_channels.insert(*scid, current_time_unix);
+ }
+ }
+ removed_nodes.insert(node_id, current_time_unix);
}
}
/// Note that for users of the `lightning-background-processor` crate this method may be
/// automatically called regularly for you.
///
+ /// This method will also cause us to stop tracking removed nodes and channels if they have been
+ /// in the map for a while so that these can be resynced from gossip in the future.
+ ///
/// This method is only available with the `std` feature. See
- /// [`NetworkGraph::remove_stale_channels_with_time`] for `no-std` use.
- pub fn remove_stale_channels(&self) {
+ /// [`NetworkGraph::remove_stale_channels_and_tracking_with_time`] for `no-std` use.
+ pub fn remove_stale_channels_and_tracking(&self) {
let time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
- self.remove_stale_channels_with_time(time);
+ self.remove_stale_channels_and_tracking_with_time(time);
}
/// Removes information about channels that we haven't heard any updates about in some time.
/// updates every two weeks, the non-normative section of BOLT 7 currently suggests that
/// pruning occur for updates which are at least two weeks old, which we implement here.
///
+ /// This method will also cause us to stop tracking removed nodes and channels if they have been
+ /// in the map for a while so that these can be resynced from gossip in the future.
+ ///
/// This function takes the current unix time as an argument. For users with the `std` feature
- /// enabled, [`NetworkGraph::remove_stale_channels`] may be preferable.
- pub fn remove_stale_channels_with_time(&self, current_time_unix: u64) {
+ /// enabled, [`NetworkGraph::remove_stale_channels_and_tracking`] may be preferable.
+ pub fn remove_stale_channels_and_tracking_with_time(&self, current_time_unix: u64) {
let mut channels = self.channels.write().unwrap();
// Time out if we haven't received an update in at least 14 days.
if current_time_unix > u32::max_value() as u64 { return; } // Remove by 2106
Self::remove_channel_in_nodes(&mut nodes, &info, scid);
}
}
+
+ let should_keep_tracking = |time: &mut Option<u64>| {
+ if let Some(time) = time {
+ current_time_unix.saturating_sub(*time) < REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS
+ } else {
+ // NOTE: In the case of no-std, we won't have access to the current UNIX time at the time of removal,
+ // so we'll just set the removal time here to the current UNIX time on the very next invocation
+ // of this function.
+ #[cfg(feature = "no-std")]
+ {
+ let mut tracked_time = Some(current_time_unix);
+ core::mem::swap(time, &mut tracked_time);
+ return true;
+ }
+ #[allow(unreachable_code)]
+ false
+ }};
+
+ self.removed_channels.lock().unwrap().retain(|_, time| should_keep_tracking(time));
+ self.removed_nodes.lock().unwrap().retain(|_, time| should_keep_tracking(time));
}
/// For an already known (from announcement) channel, update info about one of the directions
#[cfg(test)]
mod tests {
use chain;
+ use ln::channelmanager;
use ln::chan_utils::make_funding_redeemscript;
use ln::PaymentHash;
- use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
+ use ln::features::InitFeatures;
use routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, NodeAlias, MAX_EXCESS_BYTES_FOR_RELAY, NodeId, RoutingFees, ChannelUpdateInfo, ChannelInfo, NodeAnnouncementInfo, NodeInfo};
use ln::msgs::{RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate,
use util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider};
use util::scid_utils::scid_from_parts;
+ use crate::routing::gossip::REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS;
use super::STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS;
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
fn get_signed_node_announcement<F: Fn(&mut UnsignedNodeAnnouncement)>(f: F, node_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> NodeAnnouncement {
let node_id = PublicKey::from_secret_key(&secp_ctx, node_key);
let mut unsigned_announcement = UnsignedNodeAnnouncement {
- features: NodeFeatures::known(),
+ features: channelmanager::provided_node_features(),
timestamp: 100,
node_id: node_id,
rgb: [0; 3],
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let mut unsigned_announcement = UnsignedChannelAnnouncement {
- features: ChannelFeatures::known(),
+ features: channelmanager::provided_channel_features(),
chain_hash: genesis_block(Network::Testnet).header.block_hash(),
short_channel_id: 0,
node_id_1,
Err(e) => assert_eq!(e.err, "Already have chain-validated channel")
};
+ #[cfg(feature = "std")]
+ {
+ use std::time::{SystemTime, UNIX_EPOCH};
+
+ let tracking_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
+ // Mark a node as permanently failed so it's tracked as removed.
+ gossip_sync.network_graph().node_failed_permanent(&PublicKey::from_secret_key(&secp_ctx, node_1_privkey));
+
+ // Return error and ignore valid channel announcement if one of the nodes has been tracked as removed.
+ let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| {
+ unsigned_announcement.short_channel_id += 3;
+ }, node_1_privkey, node_2_privkey, &secp_ctx);
+ match gossip_sync.handle_channel_announcement(&valid_announcement) {
+ Ok(_) => panic!(),
+ Err(e) => assert_eq!(e.err, "Channel with SCID 3 or one of its nodes was removed from our network graph recently")
+ }
+
+ gossip_sync.network_graph().remove_stale_channels_and_tracking_with_time(tracking_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS);
+
+ // The above channel announcement should be handled as per normal now.
+ match gossip_sync.handle_channel_announcement(&valid_announcement) {
+ Ok(res) => assert!(res),
+ _ => panic!()
+ }
+ }
+
// Don't relay valid channels with excess data
let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| {
- unsigned_announcement.short_channel_id += 3;
+ unsigned_announcement.short_channel_id += 4;
unsigned_announcement.excess_data.resize(MAX_EXCESS_BYTES_FOR_RELAY + 1, 0);
}, node_1_privkey, node_2_privkey, &secp_ctx);
match gossip_sync.handle_channel_announcement(&valid_announcement) {
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
+ let node_2_id = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
{
// There is no nodes in the table at the beginning.
assert_eq!(network_graph.read_only().channels().len(), 0);
// Nodes are also deleted because there are no associated channels anymore
assert_eq!(network_graph.read_only().nodes().len(), 0);
- // TODO: Test NetworkUpdate::NodeFailure, which is not implemented yet.
+
+ {
+ // Get a new network graph since we don't want to track removed nodes in this test with "std"
+ let network_graph = NetworkGraph::new(genesis_hash, &logger);
+
+ // Announce a channel to test permanent node failure
+ let valid_channel_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
+ let short_channel_id = valid_channel_announcement.contents.short_channel_id;
+ let chain_source: Option<&test_utils::TestChainSource> = None;
+ assert!(network_graph.update_channel_from_announcement(&valid_channel_announcement, &chain_source).is_ok());
+ assert!(network_graph.read_only().channels().get(&short_channel_id).is_some());
+
+ // Non-permanent node failure does not delete any nodes or channels
+ network_graph.handle_event(&Event::PaymentPathFailed {
+ payment_id: None,
+ payment_hash: PaymentHash([0; 32]),
+ payment_failed_permanently: false,
+ all_paths_failed: true,
+ path: vec![],
+ network_update: Some(NetworkUpdate::NodeFailure {
+ node_id: node_2_id,
+ is_permanent: false,
+ }),
+ short_channel_id: None,
+ retry: None,
+ error_code: None,
+ error_data: None,
+ });
+
+ assert!(network_graph.read_only().channels().get(&short_channel_id).is_some());
+ assert!(network_graph.read_only().nodes().get(&NodeId::from_pubkey(&node_2_id)).is_some());
+
+ // Permanent node failure deletes node and its channels
+ network_graph.handle_event(&Event::PaymentPathFailed {
+ payment_id: None,
+ payment_hash: PaymentHash([0; 32]),
+ payment_failed_permanently: false,
+ all_paths_failed: true,
+ path: vec![],
+ network_update: Some(NetworkUpdate::NodeFailure {
+ node_id: node_2_id,
+ is_permanent: true,
+ }),
+ short_channel_id: None,
+ retry: None,
+ error_code: None,
+ error_data: None,
+ });
+
+ assert_eq!(network_graph.read_only().nodes().len(), 0);
+ // Channels are also deleted because the associated node has been deleted
+ assert_eq!(network_graph.read_only().channels().len(), 0);
+ }
}
#[test]
fn test_channel_timeouts() {
- // Test the removal of channels with `remove_stale_channels`.
+ // Test the removal of channels with `remove_stale_channels_and_tracking`.
let logger = test_utils::TestLogger::new();
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
assert!(gossip_sync.handle_channel_update(&valid_channel_update).is_ok());
assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_some());
- network_graph.remove_stale_channels_with_time(100 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
+ network_graph.remove_stale_channels_and_tracking_with_time(100 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
assert_eq!(network_graph.read_only().channels().len(), 1);
assert_eq!(network_graph.read_only().nodes().len(), 2);
- network_graph.remove_stale_channels_with_time(101 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
+ network_graph.remove_stale_channels_and_tracking_with_time(101 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
#[cfg(feature = "std")]
{
// In std mode, a further check is performed before fully removing the channel -
use std::time::{SystemTime, UNIX_EPOCH};
let announcement_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
- network_graph.remove_stale_channels_with_time(announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
+ network_graph.remove_stale_channels_and_tracking_with_time(announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
}
assert_eq!(network_graph.read_only().channels().len(), 0);
assert_eq!(network_graph.read_only().nodes().len(), 0);
+
+ #[cfg(feature = "std")]
+ {
+ use std::time::{SystemTime, UNIX_EPOCH};
+
+ let tracking_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
+
+ // Clear tracked nodes and channels for clean slate
+ network_graph.removed_channels.lock().unwrap().clear();
+ network_graph.removed_nodes.lock().unwrap().clear();
+
+ // Add a channel and nodes from channel announcement. So our network graph will
+ // now only consist of two nodes and one channel between them.
+ assert!(network_graph.update_channel_from_announcement(
+ &valid_channel_announcement, &chain_source).is_ok());
+
+ // Mark the channel as permanently failed. This will also remove the two nodes
+ // and all of the entries will be tracked as removed.
+ network_graph.channel_failed(short_channel_id, true);
+
+ // Should not remove from tracking if insufficient time has passed
+ network_graph.remove_stale_channels_and_tracking_with_time(
+ tracking_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS - 1);
+ assert_eq!(network_graph.removed_channels.lock().unwrap().len(), 1);
+
+ // Provide a later time so that sufficient time has passed
+ network_graph.remove_stale_channels_and_tracking_with_time(
+ tracking_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS);
+ assert!(network_graph.removed_channels.lock().unwrap().is_empty());
+ assert!(network_graph.removed_nodes.lock().unwrap().is_empty());
+ }
+
+ #[cfg(not(feature = "std"))]
+ {
+ // When we don't have access to the system clock, the time we started tracking removal will only
+ // be that provided by the first call to `remove_stale_channels_and_tracking_with_time`. Hence,
+ // only if sufficient time has passed after that first call, will the next call remove it from
+ // tracking.
+ let removal_time = 1664619654;
+
+ // Clear removed nodes and channels for clean slate
+ network_graph.removed_channels.lock().unwrap().clear();
+ network_graph.removed_nodes.lock().unwrap().clear();
+
+ // Add a channel and nodes from channel announcement. So our network graph will
+ // now only consist of two nodes and one channel between them.
+ assert!(network_graph.update_channel_from_announcement(
+ &valid_channel_announcement, &chain_source).is_ok());
+
+ // Mark the channel as permanently failed. This will also remove the two nodes
+ // and all of the entries will be tracked as removed.
+ network_graph.channel_failed(short_channel_id, true);
+
+ // The first time we call the following, the channel will have a removal time assigned.
+ network_graph.remove_stale_channels_and_tracking_with_time(removal_time);
+ assert_eq!(network_graph.removed_channels.lock().unwrap().len(), 1);
+
+ // Provide a later time so that sufficient time has passed
+ network_graph.remove_stale_channels_and_tracking_with_time(
+ removal_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS);
+ assert!(network_graph.removed_channels.lock().unwrap().is_empty());
+ assert!(network_graph.removed_nodes.lock().unwrap().is_empty());
+ }
}
#[test]
// It should ignore if gossip_queries feature is not enabled
{
- let init_msg = Init { features: InitFeatures::known().clear_gossip_queries(), remote_network_address: None };
- gossip_sync.peer_connected(&node_id_1, &init_msg);
+ let init_msg = Init { features: InitFeatures::empty(), remote_network_address: None };
+ gossip_sync.peer_connected(&node_id_1, &init_msg).unwrap();
let events = gossip_sync.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 0);
}
// It should send a gossip_timestamp_filter with the correct information
{
- let init_msg = Init { features: InitFeatures::known(), remote_network_address: None };
- gossip_sync.peer_connected(&node_id_1, &init_msg);
+ let mut features = InitFeatures::empty();
+ features.set_gossip_queries_optional();
+ let init_msg = Init { features, remote_network_address: None };
+ gossip_sync.peer_connected(&node_id_1, &init_msg).unwrap();
let events = gossip_sync.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
match &events[0] {
// 2. Test encoding/decoding of ChannelInfo
// Check we can encode/decode ChannelInfo without ChannelUpdateInfo fields present.
let chan_info_none_updates = ChannelInfo {
- features: ChannelFeatures::known(),
+ features: channelmanager::provided_channel_features(),
node_one: NodeId::from_pubkey(&nodes[0].node.get_our_node_id()),
one_to_two: None,
node_two: NodeId::from_pubkey(&nodes[1].node.get_our_node_id()),
// Check we can encode/decode ChannelInfo with ChannelUpdateInfo fields present.
let chan_info_some_updates = ChannelInfo {
- features: ChannelFeatures::known(),
+ features: channelmanager::provided_channel_features(),
node_one: NodeId::from_pubkey(&nodes[0].node.get_our_node_id()),
one_to_two: Some(chan_update_info.clone()),
node_two: NodeId::from_pubkey(&nodes[1].node.get_our_node_id()),
// 1. Check we can read a valid NodeAnnouncementInfo and fail on an invalid one
let valid_netaddr = ::ln::msgs::NetAddress::Hostname { hostname: ::util::ser::Hostname::try_from("A".to_string()).unwrap(), port: 1234 };
let valid_node_ann_info = NodeAnnouncementInfo {
- features: NodeFeatures::known(),
+ features: channelmanager::provided_node_features(),
last_update: 0,
rgb: [0u8; 3],
alias: NodeAlias([0u8; 32]),
#[bench]
fn read_network_graph(bench: &mut Bencher) {
let logger = ::util::test_utils::TestLogger::new();
- let mut d = ::routing::router::test_utils::get_route_file().unwrap();
+ let mut d = ::routing::router::bench_utils::get_route_file().unwrap();
let mut v = Vec::new();
d.read_to_end(&mut v).unwrap();
bench.iter(|| {
#[bench]
fn write_network_graph(bench: &mut Bencher) {
let logger = ::util::test_utils::TestLogger::new();
- let mut d = ::routing::router::test_utils::get_route_file().unwrap();
+ let mut d = ::routing::router::bench_utils::get_route_file().unwrap();
let net_graph = NetworkGraph::read(&mut d, &logger).unwrap();
bench.iter(|| {
let _ = net_graph.encode();
pub mod gossip;
pub mod router;
pub mod scoring;
+#[cfg(test)]
+mod test_utils;
lowest_fee_to_peer_through_node: total_fee_msat,
lowest_fee_to_node: $next_hops_fee_msat as u64 + hop_use_fee_msat,
total_cltv_delta: hop_total_cltv_delta,
- value_contribution_msat: value_contribution_msat,
+ value_contribution_msat,
path_htlc_minimum_msat,
path_penalty_msat,
path_length_to_node,
PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE};
use routing::scoring::{ChannelUsage, Score, ProbabilisticScorer, ProbabilisticScoringParameters};
+ use routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel};
use chain::transaction::OutPoint;
use chain::keysinterface::KeysInterface;
- use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
- use ln::msgs::{ErrorAction, LightningError, UnsignedChannelAnnouncement, ChannelAnnouncement, RoutingMessageHandler,
- NodeAnnouncement, UnsignedNodeAnnouncement, ChannelUpdate, UnsignedChannelUpdate, MAX_VALUE_MSAT};
+ use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
+ use ln::msgs::{ErrorAction, LightningError, UnsignedChannelUpdate, MAX_VALUE_MSAT};
use ln::channelmanager;
- use util::test_utils;
+ use util::test_utils as ln_test_utils;
use util::chacha20::ChaCha20;
- use util::ser::Writeable;
#[cfg(c_bindings)]
- use util::ser::Writer;
+ use util::ser::{Writeable, Writer};
- use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin::hashes::Hash;
use bitcoin::network::constants::Network;
use bitcoin::blockdata::constants::genesis_block;
use hex;
use bitcoin::secp256k1::{PublicKey,SecretKey};
- use bitcoin::secp256k1::{Secp256k1, All};
+ use bitcoin::secp256k1::Secp256k1;
use prelude::*;
- use sync::{self, Arc};
+ use sync::Arc;
use core::convert::TryInto;
}
}
- // Using the same keys for LN and BTC ids
- fn add_channel(
- gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
- secp_ctx: &Secp256k1<All>, node_1_privkey: &SecretKey, node_2_privkey: &SecretKey, features: ChannelFeatures, short_channel_id: u64
- ) {
- let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
- let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
-
- let unsigned_announcement = UnsignedChannelAnnouncement {
- features,
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id,
- node_id_1,
- node_id_2,
- bitcoin_key_1: node_id_1,
- bitcoin_key_2: node_id_2,
- excess_data: Vec::new(),
- };
-
- let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
- let valid_announcement = ChannelAnnouncement {
- node_signature_1: secp_ctx.sign_ecdsa(&msghash, node_1_privkey),
- node_signature_2: secp_ctx.sign_ecdsa(&msghash, node_2_privkey),
- bitcoin_signature_1: secp_ctx.sign_ecdsa(&msghash, node_1_privkey),
- bitcoin_signature_2: secp_ctx.sign_ecdsa(&msghash, node_2_privkey),
- contents: unsigned_announcement.clone(),
- };
- match gossip_sync.handle_channel_announcement(&valid_announcement) {
- Ok(res) => assert!(res),
- _ => panic!()
- };
- }
-
- fn update_channel(
- gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
- secp_ctx: &Secp256k1<All>, node_privkey: &SecretKey, update: UnsignedChannelUpdate
- ) {
- let msghash = hash_to_message!(&Sha256dHash::hash(&update.encode()[..])[..]);
- let valid_channel_update = ChannelUpdate {
- signature: secp_ctx.sign_ecdsa(&msghash, node_privkey),
- contents: update.clone()
- };
-
- match gossip_sync.handle_channel_update(&valid_channel_update) {
- Ok(res) => assert!(res),
- Err(_) => panic!()
- };
- }
-
- fn add_or_update_node(
- gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
- secp_ctx: &Secp256k1<All>, node_privkey: &SecretKey, features: NodeFeatures, timestamp: u32
- ) {
- let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey);
- let unsigned_announcement = UnsignedNodeAnnouncement {
- features,
- timestamp,
- node_id,
- rgb: [0; 3],
- alias: [0; 32],
- addresses: Vec::new(),
- excess_address_data: Vec::new(),
- excess_data: Vec::new(),
- };
- let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
- let valid_announcement = NodeAnnouncement {
- signature: secp_ctx.sign_ecdsa(&msghash, node_privkey),
- contents: unsigned_announcement.clone()
- };
-
- match gossip_sync.handle_node_announcement(&valid_announcement) {
- Ok(_) => (),
- Err(_) => panic!()
- };
- }
-
- fn get_nodes(secp_ctx: &Secp256k1<All>) -> (SecretKey, PublicKey, Vec<SecretKey>, Vec<PublicKey>) {
- let privkeys: Vec<SecretKey> = (2..22).map(|i| {
- SecretKey::from_slice(&hex::decode(format!("{:02x}", i).repeat(32)).unwrap()[..]).unwrap()
- }).collect();
-
- let pubkeys = privkeys.iter().map(|secret| PublicKey::from_secret_key(&secp_ctx, secret)).collect();
-
- let our_privkey = SecretKey::from_slice(&hex::decode("01".repeat(32)).unwrap()[..]).unwrap();
- let our_id = PublicKey::from_secret_key(&secp_ctx, &our_privkey);
-
- (our_privkey, our_id, privkeys, pubkeys)
- }
-
- fn id_to_feature_flags(id: u8) -> Vec<u8> {
- // Set the feature flags to the id'th odd (ie non-required) feature bit so that we can
- // test for it later.
- let idx = (id - 1) * 2 + 1;
- if idx > 8*3 {
- vec![1 << (idx - 8*3), 0, 0, 0]
- } else if idx > 8*2 {
- vec![1 << (idx - 8*2), 0, 0]
- } else if idx > 8*1 {
- vec![1 << (idx - 8*1), 0]
- } else {
- vec![1 << idx]
- }
- }
-
- fn build_line_graph() -> (
- Secp256k1<All>, sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
- P2PGossipSync<sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>>,
- sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>,
- ) {
- let secp_ctx = Secp256k1::new();
- let logger = Arc::new(test_utils::TestLogger::new());
- let chain_monitor = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
- let gossip_sync = P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
-
- // Build network from our_id to node 19:
- // our_id -1(1)2- node0 -1(2)2- node1 - ... - node19
- let (our_privkey, _, privkeys, _) = get_nodes(&secp_ctx);
-
- for (idx, (cur_privkey, next_privkey)) in core::iter::once(&our_privkey)
- .chain(privkeys.iter()).zip(privkeys.iter()).enumerate() {
- let cur_short_channel_id = (idx as u64) + 1;
- add_channel(&gossip_sync, &secp_ctx, &cur_privkey, &next_privkey,
- ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), cur_short_channel_id);
- update_channel(&gossip_sync, &secp_ctx, &cur_privkey, UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: cur_short_channel_id,
- timestamp: idx as u32,
- flags: 0,
- cltv_expiry_delta: 0,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &next_privkey, UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: cur_short_channel_id,
- timestamp: (idx as u32)+1,
- flags: 1,
- cltv_expiry_delta: 0,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
- add_or_update_node(&gossip_sync, &secp_ctx, next_privkey,
- NodeFeatures::from_le_bytes(id_to_feature_flags(1)), 0);
- }
-
- (secp_ctx, network_graph, gossip_sync, chain_monitor, logger)
- }
-
- fn build_graph() -> (
- Secp256k1<All>,
- sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
- P2PGossipSync<sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>>,
- sync::Arc<test_utils::TestChainSource>,
- sync::Arc<test_utils::TestLogger>,
- ) {
- let secp_ctx = Secp256k1::new();
- let logger = Arc::new(test_utils::TestLogger::new());
- let chain_monitor = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
- let gossip_sync = P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
- // Build network from our_id to node6:
- //
- // -1(1)2- node0 -1(3)2-
- // / \
- // our_id -1(12)2- node7 -1(13)2--- node2
- // \ /
- // -1(2)2- node1 -1(4)2-
- //
- //
- // chan1 1-to-2: disabled
- // chan1 2-to-1: enabled, 0 fee
- //
- // chan2 1-to-2: enabled, ignored fee
- // chan2 2-to-1: enabled, 0 fee
- //
- // chan3 1-to-2: enabled, 0 fee
- // chan3 2-to-1: enabled, 100 msat fee
- //
- // chan4 1-to-2: enabled, 100% fee
- // chan4 2-to-1: enabled, 0 fee
- //
- // chan12 1-to-2: enabled, ignored fee
- // chan12 2-to-1: enabled, 0 fee
- //
- // chan13 1-to-2: enabled, 200% fee
- // chan13 2-to-1: enabled, 0 fee
- //
- //
- // -1(5)2- node3 -1(8)2--
- // | 2 |
- // | (11) |
- // / 1 \
- // node2--1(6)2- node4 -1(9)2--- node6 (not in global route map)
- // \ /
- // -1(7)2- node5 -1(10)2-
- //
- // Channels 5, 8, 9 and 10 are private channels.
- //
- // chan5 1-to-2: enabled, 100 msat fee
- // chan5 2-to-1: enabled, 0 fee
- //
- // chan6 1-to-2: enabled, 0 fee
- // chan6 2-to-1: enabled, 0 fee
- //
- // chan7 1-to-2: enabled, 100% fee
- // chan7 2-to-1: enabled, 0 fee
- //
- // chan8 1-to-2: enabled, variable fee (0 then 1000 msat)
- // chan8 2-to-1: enabled, 0 fee
- //
- // chan9 1-to-2: enabled, 1001 msat fee
- // chan9 2-to-1: enabled, 0 fee
- //
- // chan10 1-to-2: enabled, 0 fee
- // chan10 2-to-1: enabled, 0 fee
- //
- // chan11 1-to-2: enabled, 0 fee
- // chan11 2-to-1: enabled, 0 fee
-
- let (our_privkey, _, privkeys, _) = get_nodes(&secp_ctx);
-
- add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[0], ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), 1);
- update_channel(&gossip_sync, &secp_ctx, &privkeys[0], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 1,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: 0,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[0], NodeFeatures::from_le_bytes(id_to_feature_flags(1)), 0);
-
- add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(2)), 2);
- update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 2,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (5 << 4) | 3,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: u32::max_value(),
- fee_proportional_millionths: u32::max_value(),
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 2,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: 0,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[1], NodeFeatures::from_le_bytes(id_to_feature_flags(2)), 0);
-
- add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[7], ChannelFeatures::from_le_bytes(id_to_feature_flags(12)), 12);
- update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 12,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (5 << 4) | 3,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: u32::max_value(),
- fee_proportional_millionths: u32::max_value(),
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[7], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 12,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: 0,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[7], NodeFeatures::from_le_bytes(id_to_feature_flags(8)), 0);
-
- add_channel(&gossip_sync, &secp_ctx, &privkeys[0], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(3)), 3);
- update_channel(&gossip_sync, &secp_ctx, &privkeys[0], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 3,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (3 << 4) | 1,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 3,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: (3 << 4) | 2,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 100,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_channel(&gossip_sync, &secp_ctx, &privkeys[1], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(4)), 4);
- update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 4,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (4 << 4) | 1,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 1000000,
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 4,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: (4 << 4) | 2,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_channel(&gossip_sync, &secp_ctx, &privkeys[7], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(13)), 13);
- update_channel(&gossip_sync, &secp_ctx, &privkeys[7], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 13,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (13 << 4) | 1,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 2000000,
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 13,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: (13 << 4) | 2,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[2], NodeFeatures::from_le_bytes(id_to_feature_flags(3)), 0);
-
- add_channel(&gossip_sync, &secp_ctx, &privkeys[2], &privkeys[4], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6);
- update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 6,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (6 << 4) | 1,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 6,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: (6 << 4) | 2,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new(),
- });
-
- add_channel(&gossip_sync, &secp_ctx, &privkeys[4], &privkeys[3], ChannelFeatures::from_le_bytes(id_to_feature_flags(11)), 11);
- update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 11,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (11 << 4) | 1,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 11,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: (11 << 4) | 2,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[4], NodeFeatures::from_le_bytes(id_to_feature_flags(5)), 0);
-
- add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[3], NodeFeatures::from_le_bytes(id_to_feature_flags(4)), 0);
-
- add_channel(&gossip_sync, &secp_ctx, &privkeys[2], &privkeys[5], ChannelFeatures::from_le_bytes(id_to_feature_flags(7)), 7);
- update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 7,
- timestamp: 1,
- flags: 0,
- cltv_expiry_delta: (7 << 4) | 1,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 1000000,
- excess_data: Vec::new()
- });
- update_channel(&gossip_sync, &secp_ctx, &privkeys[5], UnsignedChannelUpdate {
- chain_hash: genesis_block(Network::Testnet).header.block_hash(),
- short_channel_id: 7,
- timestamp: 1,
- flags: 1,
- cltv_expiry_delta: (7 << 4) | 2,
- htlc_minimum_msat: 0,
- htlc_maximum_msat: MAX_VALUE_MSAT,
- fee_base_msat: 0,
- fee_proportional_millionths: 0,
- excess_data: Vec::new()
- });
-
- add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[5], NodeFeatures::from_le_bytes(id_to_feature_flags(6)), 0);
-
- (secp_ctx, network_graph, gossip_sync, chain_monitor, logger)
- }
-
#[test]
fn simple_route_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Simple route to 2 via 1
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Simple route to 2 via 1
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Simple route to 2 via 1
fn htlc_minimum_overpay_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features());
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// A route to node#2 via two paths.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// // Disable channels 4 and 12 by flags=2
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Disable nodes 1, 2, and 8 by requiring unknown feature bits
- let mut unknown_features = NodeFeatures::known();
+ let mut unknown_features = NodeFeatures::empty();
unknown_features.set_unknown_feature_required();
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[0], unknown_features.clone(), 1);
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[1], unknown_features.clone(), 1);
fn our_chans_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Route to 1 via 2 and 3 because our channel to 1 is disabled
fn partial_route_hint_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Simple test across 2, 3, 5, and 4 via a last_hop channel
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(empty_last_hop(&nodes));
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Test handling of an empty RouteHint passed in Invoice.
let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
let last_hops = multi_hop_last_hops_hint([nodes[2], nodes[3]]);
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Test through channels 2, 3, 0xff00, 0xff01.
// Test shows that multiple hop hints are considered.
let last_hops = multi_hop_last_hops_hint([nodes[2], non_announced_pubkey]);
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
- let scorer = test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
// Test through channels 2, 3, 0xff00, 0xff01.
// Test shows that multiple hop hints are considered.
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops_with_public_channel(&nodes));
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// This test shows that public routes can be present in the invoice
// which would be handled in the same manner.
fn our_chans_last_hop_connect_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// Simple test with outbound channel to 4 to test that last_hops and first_hops connect
}]);
let payment_params = PaymentParameters::from_node_id(target_node_id).with_route_hints(vec![last_hops]);
let our_chans = vec![get_channel_details(Some(42), middle_node_id, InitFeatures::from_le_bytes(vec![0b11]), outbound_capacity_msat)];
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let logger = test_utils::TestLogger::new();
+ let logger = ln_test_utils::TestLogger::new();
let network_graph = NetworkGraph::new(genesis_hash, &logger);
let route = get_route(&source_node_id, &payment_params, &network_graph.read_only(),
Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &logger, &scorer, &random_seed_bytes);
let (secp_ctx, network_graph, mut gossip_sync, chain_monitor, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features());
// We will use a simple single-path route from
// our node to node2 via node0: channels {1, 3}.
// one of the latter hops is limited.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features());
// Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
// {12, 13, 11} have the capacities of 100, {6} has a capacity of 50.
fn ignore_fee_first_hop_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let payment_params = PaymentParameters::from_node_id(nodes[2]);
fn simple_mpp_route_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let payment_params = PaymentParameters::from_node_id(nodes[2])
- .with_features(InvoiceFeatures::known());
+ .with_features(channelmanager::provided_invoice_features());
// We need a route consisting of 3 paths:
// From our node to node2 via node0, node7, node1 (three paths one hop each).
fn long_mpp_route_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features());
// We need a route consisting of 3 paths:
// From our node to node3 via {node0, node2}, {node7, node2, node4} and {node7, node2}.
fn mpp_cheaper_route_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features());
// This test checks that if we have two cheaper paths and one more expensive path,
// so that liquidity-wise any 2 of 3 combination is sufficient,
// if the fee is not properly accounted for, the behavior is different.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features());
// We need a route consisting of 2 paths:
// From our node to node3 via {node0, node2} and {node7, node2, node4}.
// This bug appeared in production in some specific channel configurations.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(PublicKey::from_slice(&[02; 33]).unwrap()).with_features(InvoiceFeatures::known())
+ let payment_params = PaymentParameters::from_node_id(PublicKey::from_slice(&[02; 33]).unwrap()).with_features(channelmanager::provided_invoice_features())
.with_route_hints(vec![RouteHint(vec![RouteHintHop {
src_node_id: nodes[2],
short_channel_id: 42,
// path finding we realize that we found more capacity than we need.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known())
+ let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features())
.with_max_channel_saturation_power_of_half(0);
// We need a route consisting of 3 paths:
// "previous hop" being set to node 3, creating a loop in the path.
let secp_ctx = Secp256k1::new();
let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let logger = Arc::new(test_utils::TestLogger::new());
+ let logger = Arc::new(ln_test_utils::TestLogger::new());
let network = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
let gossip_sync = P2PGossipSync::new(Arc::clone(&network), None, Arc::clone(&logger));
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let payment_params = PaymentParameters::from_node_id(nodes[6]);
// we calculated fees on a higher value, resulting in us ignoring such paths.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let payment_params = PaymentParameters::from_node_id(nodes[2]);
// resulting in us thinking there is no possible path, even if other paths exist.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features());
// We modify the graph to set the htlc_minimum of channel 2 and 4 as needed - channel 2
// gets an htlc_maximum_msat of 80_000 and channel 4 an htlc_minimum_msat of 90_000. We
assert_eq!(route.paths[0][1].short_channel_id, 13);
assert_eq!(route.paths[0][1].fee_msat, 90_000);
assert_eq!(route.paths[0][1].cltv_expiry_delta, 42);
- assert_eq!(route.paths[0][1].node_features.le_flags(), InvoiceFeatures::known().le_flags());
+ assert_eq!(route.paths[0][1].node_features.le_flags(), channelmanager::provided_invoice_features().le_flags());
assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(13));
}
}
let secp_ctx = Secp256k1::new();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let logger = Arc::new(test_utils::TestLogger::new());
+ let logger = Arc::new(ln_test_utils::TestLogger::new());
let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger));
- let scorer = test_utils::TestScorer::with_penalty(0);
- let payment_params = PaymentParameters::from_node_id(nodes[0]).with_features(InvoiceFeatures::known());
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[0]).with_features(channelmanager::provided_invoice_features());
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
{
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
- &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 200_000),
- &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 10_000),
+ &get_channel_details(Some(3), nodes[0], channelmanager::provided_init_features(), 200_000),
+ &get_channel_details(Some(2), nodes[0], channelmanager::provided_init_features(), 10_000),
]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].len(), 1);
}
{
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
- &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 50_000),
- &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 50_000),
+ &get_channel_details(Some(3), nodes[0], channelmanager::provided_init_features(), 50_000),
+ &get_channel_details(Some(2), nodes[0], channelmanager::provided_init_features(), 50_000),
]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 2);
assert_eq!(route.paths[0].len(), 1);
// smallest of them, avoiding further fragmenting our available outbound balance to
// this node.
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
- &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 50_000),
- &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 50_000),
- &get_channel_details(Some(5), nodes[0], InitFeatures::known(), 50_000),
- &get_channel_details(Some(6), nodes[0], InitFeatures::known(), 300_000),
- &get_channel_details(Some(7), nodes[0], InitFeatures::known(), 50_000),
- &get_channel_details(Some(8), nodes[0], InitFeatures::known(), 50_000),
- &get_channel_details(Some(9), nodes[0], InitFeatures::known(), 50_000),
- &get_channel_details(Some(4), nodes[0], InitFeatures::known(), 1_000_000),
+ &get_channel_details(Some(2), nodes[0], channelmanager::provided_init_features(), 50_000),
+ &get_channel_details(Some(3), nodes[0], channelmanager::provided_init_features(), 50_000),
+ &get_channel_details(Some(5), nodes[0], channelmanager::provided_init_features(), 50_000),
+ &get_channel_details(Some(6), nodes[0], channelmanager::provided_init_features(), 300_000),
+ &get_channel_details(Some(7), nodes[0], channelmanager::provided_init_features(), 50_000),
+ &get_channel_details(Some(8), nodes[0], channelmanager::provided_init_features(), 50_000),
+ &get_channel_details(Some(9), nodes[0], channelmanager::provided_init_features(), 50_000),
+ &get_channel_details(Some(4), nodes[0], channelmanager::provided_init_features(), 1_000_000),
]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].len(), 1);
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes));
// Without penalizing each hop 100 msats, a longer path with lower fees is chosen.
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(
&our_id, &payment_params, &network_graph.read_only(), None, 100, 42,
// Applying a 100 msat penalty to each hop results in taking channels 7 and 10 to nodes[6]
// from nodes[2] rather than channel 6, 11, and 8, even though the longer path is cheaper.
- let scorer = test_utils::TestScorer::with_penalty(100);
+ let scorer = ln_test_utils::TestScorer::with_penalty(100);
let route = get_route(
&our_id, &payment_params, &network_graph.read_only(), None, 100, 42,
Arc::clone(&logger), &scorer, &random_seed_bytes
let network_graph = network.read_only();
// A path to nodes[6] exists when no penalties are applied to any channel.
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(
&our_id, &payment_params, &network_graph, None, 100, 42,
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let network_graph = network.read_only();
- let scorer = test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
// Make sure that generally there is at least one route available
let feasible_max_total_cltv_delta = 1008;
let feasible_payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
.with_max_total_cltv_expiry_delta(feasible_max_total_cltv_delta);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, 0, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let network_graph = network.read_only();
- let scorer = test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
let mut payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
.with_max_path_count(1);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// We should be able to find a route initially, and then after we fail a few random
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let network_graph = network.read_only();
- let scorer = test_utils::TestScorer::with_penalty(0);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// First check we can actually create a long route on this graph.
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes));
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let network_graph = network.read_only();
let network_nodes = network_graph.nodes();
let network_channels = network_graph.channels();
- let scorer = test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::with_penalty(0);
let payment_params = PaymentParameters::from_node_id(nodes[3]);
- let keys_manager = test_utils::TestKeysInterface::new(&[4u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[4u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let mut route = get_route(&our_id, &payment_params, &network_graph, None, 100, 0,
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let network_graph = network.read_only();
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let payment_params = PaymentParameters::from_node_id(nodes[3]);
excess_data: Vec::new()
});
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features());
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// 100,000 sats is less than the available liquidity on each channel, set above.
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
fn generate_routes() {
use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
- let mut d = match super::test_utils::get_route_file() {
+ let mut d = match super::bench_utils::get_route_file() {
Ok(f) => f,
Err(e) => {
eprintln!("{}", e);
return;
},
};
- let logger = test_utils::TestLogger::new();
+ let logger = ln_test_utils::TestLogger::new();
let graph = NetworkGraph::read(&mut d, &logger).unwrap();
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
fn generate_routes_mpp() {
use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
- let mut d = match super::test_utils::get_route_file() {
+ let mut d = match super::bench_utils::get_route_file() {
Ok(f) => f,
Err(e) => {
eprintln!("{}", e);
return;
},
};
- let logger = test_utils::TestLogger::new();
+ let logger = ln_test_utils::TestLogger::new();
let graph = NetworkGraph::read(&mut d, &logger).unwrap();
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
let src = &PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
seed = seed.overflowing_mul(0xdeadbeef).0;
let dst = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
- let payment_params = PaymentParameters::from_node_id(dst).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(dst).with_features(channelmanager::provided_invoice_features());
let amt = seed as u64 % 200_000_000;
let params = ProbabilisticScoringParameters::default();
let scorer = ProbabilisticScorer::new(params, &graph, &logger);
let (secp_ctx, network_graph, _, _, logger) = build_line_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let scorer_params = ProbabilisticScoringParameters::default();
}
#[cfg(all(test, not(feature = "no-std")))]
-pub(crate) mod test_utils {
+pub(crate) mod bench_utils {
use std::fs::File;
/// Tries to open a network graph file, or panics with a URL to fetch it.
pub(crate) fn get_route_file() -> Result<std::fs::File, &'static str> {
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
use chain::transaction::OutPoint;
use chain::keysinterface::{KeysManager,KeysInterface};
- use ln::channelmanager::{ChannelCounterparty, ChannelDetails};
+ use ln::channelmanager::{self, ChannelCounterparty, ChannelDetails};
use ln::features::{InitFeatures, InvoiceFeatures};
use routing::gossip::NetworkGraph;
use routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringParameters};
}
fn read_network_graph(logger: &DummyLogger) -> NetworkGraph<&DummyLogger> {
- let mut d = test_utils::get_route_file().unwrap();
+ let mut d = bench_utils::get_route_file().unwrap();
NetworkGraph::read(&mut d, logger).unwrap()
}
ChannelDetails {
channel_id: [0; 32],
counterparty: ChannelCounterparty {
- features: InitFeatures::known(),
+ features: channelmanager::provided_init_features(),
node_id,
unspendable_punishment_reserve: 0,
forwarding_info: None,
let logger = DummyLogger {};
let network_graph = read_network_graph(&logger);
let scorer = FixedPenaltyScorer::with_penalty(0);
- generate_routes(bench, &network_graph, scorer, InvoiceFeatures::known());
+ generate_routes(bench, &network_graph, scorer, channelmanager::provided_invoice_features());
}
#[bench]
let network_graph = read_network_graph(&logger);
let params = ProbabilisticScoringParameters::default();
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- generate_routes(bench, &network_graph, scorer, InvoiceFeatures::known());
+ generate_routes(bench, &network_graph, scorer, channelmanager::provided_invoice_features());
}
fn generate_routes<S: Score>(
use util::time::Time;
use prelude::*;
-use core::fmt;
+use core::{cmp, fmt};
use core::cell::{RefCell, RefMut};
+use core::convert::TryInto;
use core::ops::{Deref, DerefMut};
use core::time::Duration;
use io::{self, Read};
score: Mutex<S>,
}
#[cfg(c_bindings)]
-/// (C-not exported)
+/// A locked `MultiThreadedLockableScore`.
+pub struct MultiThreadedScoreLock<'a, S: Score>(MutexGuard<'a, S>);
+#[cfg(c_bindings)]
+impl<'a, T: Score + 'a> Score for MultiThreadedScoreLock<'a, T> {
+ fn channel_penalty_msat(&self, scid: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
+ self.0.channel_penalty_msat(scid, source, target, usage)
+ }
+ fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
+ self.0.payment_path_failed(path, short_channel_id)
+ }
+ fn payment_path_successful(&mut self, path: &[&RouteHop]) {
+ self.0.payment_path_successful(path)
+ }
+ fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
+ self.0.probe_failed(path, short_channel_id)
+ }
+ fn probe_successful(&mut self, path: &[&RouteHop]) {
+ self.0.probe_successful(path)
+ }
+}
+#[cfg(c_bindings)]
+impl<'a, T: Score + 'a> Writeable for MultiThreadedScoreLock<'a, T> {
+ fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+ self.0.write(writer)
+ }
+}
+
+#[cfg(c_bindings)]
impl<'a, T: Score + 'a> LockableScore<'a> for MultiThreadedLockableScore<T> {
- type Locked = MutexGuard<'a, T>;
+ type Locked = MultiThreadedScoreLock<'a, T>;
- fn lock(&'a self) -> MutexGuard<'a, T> {
- Mutex::lock(&self.score).unwrap()
+ fn lock(&'a self) -> MultiThreadedScoreLock<'a, T> {
+ MultiThreadedScoreLock(Mutex::lock(&self.score).unwrap())
}
}
/// [`Score`] implementation using channel success probability distributions.
///
-/// Based on *Optimally Reliable & Cheap Payment Flows on the Lightning Network* by Rene Pickhardt
-/// and Stefan Richter [[1]]. Given the uncertainty of channel liquidity balances, probability
-/// distributions are defined based on knowledge learned from successful and unsuccessful attempts.
-/// Then the negative `log10` of the success probability is used to determine the cost of routing a
-/// specific HTLC amount through a channel.
+/// Channels are tracked with upper and lower liquidity bounds - when an HTLC fails at a channel,
+/// we learn that the upper-bound on the available liquidity is lower than the amount of the HTLC.
+/// When a payment is forwarded through a channel (but fails later in the route), we learn the
+/// lower-bound on the channel's available liquidity must be at least the value of the HTLC.
+///
+/// These bounds are then used to determine a success probability using the formula from
+/// *Optimally Reliable & Cheap Payment Flows on the Lightning Network* by Rene Pickhardt
+/// and Stefan Richter [[1]] (i.e. `(upper_bound - payment_amount) / (upper_bound - lower_bound)`).
///
-/// Knowledge about channel liquidity balances takes the form of upper and lower bounds on the
-/// possible liquidity. Certainty of the bounds is decreased over time using a decay function. See
-/// [`ProbabilisticScoringParameters`] for details.
+/// This probability is combined with the [`liquidity_penalty_multiplier_msat`] and
+/// [`liquidity_penalty_amount_multiplier_msat`] parameters to calculate a concrete penalty in
+/// milli-satoshis. The penalties, when added across all hops, have the property of being linear in
+/// terms of the entire path's success probability. This allows the router to directly compare
+/// penalties for different paths. See the documentation of those parameters for the exact formulas.
///
-/// Since the scorer aims to learn the current channel liquidity balances, it works best for nodes
-/// with high payment volume or that actively probe the [`NetworkGraph`]. Nodes with low payment
-/// volume are more likely to experience failed payment paths, which would need to be retried.
+/// The liquidity bounds are decayed by halving them every [`liquidity_offset_half_life`].
+///
+/// Further, we track the history of our upper and lower liquidity bounds for each channel,
+/// allowing us to assign a second penalty (using [`historical_liquidity_penalty_multiplier_msat`]
+/// and [`historical_liquidity_penalty_amount_multiplier_msat`]) based on the same probability
+/// formula, but using the history of a channel rather than our latest estimates for the liquidity
+/// bounds.
///
/// # Note
///
/// behavior.
///
/// [1]: https://arxiv.org/abs/2107.05322
+/// [`liquidity_penalty_multiplier_msat`]: ProbabilisticScoringParameters::liquidity_penalty_multiplier_msat
+/// [`liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringParameters::liquidity_penalty_amount_multiplier_msat
+/// [`liquidity_offset_half_life`]: ProbabilisticScoringParameters::liquidity_offset_half_life
+/// [`historical_liquidity_penalty_multiplier_msat`]: ProbabilisticScoringParameters::historical_liquidity_penalty_multiplier_msat
+/// [`historical_liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringParameters::historical_liquidity_penalty_amount_multiplier_msat
pub type ProbabilisticScorer<G, L> = ProbabilisticScorerUsingTime::<G, L, ConfiguredTime>;
/// Probabilistic [`Score`] implementation.
pub base_penalty_amount_multiplier_msat: u64,
/// A multiplier used in conjunction with the negative `log10` of the channel's success
- /// probability for a payment to determine the liquidity penalty.
+ /// probability for a payment, as determined by our latest estimates of the channel's
+ /// liquidity, to determine the liquidity penalty.
///
/// The penalty is based in part on the knowledge learned from prior successful and unsuccessful
/// payments. This knowledge is decayed over time based on [`liquidity_offset_half_life`]. The
/// uncertainty bounds of the channel liquidity balance. Amounts above the upper bound will
/// result in a `u64::max_value` penalty, however.
///
- /// Default value: 40,000 msat
+ /// `-log10(success_probability) * liquidity_penalty_multiplier_msat`
+ ///
+ /// Default value: 30,000 msat
///
/// [`liquidity_offset_half_life`]: Self::liquidity_offset_half_life
pub liquidity_penalty_multiplier_msat: u64,
- /// The time required to elapse before any knowledge learned about channel liquidity balances is
- /// cut in half.
+ /// Whenever this amount of time elapses since the last update to a channel's liquidity bounds,
+ /// the distance from the bounds to "zero" is cut in half. In other words, the lower-bound on
+ /// the available liquidity is halved and the upper-bound moves half-way to the channel's total
+ /// capacity.
+ ///
+ /// Because halving the liquidity bounds grows the uncertainty on the channel's liquidity,
+ /// the penalty for an amount within the new bounds may change. See the [`ProbabilisticScorer`]
+ /// struct documentation for more info on the way the liquidity bounds are used.
///
- /// The bounds are defined in terms of offsets and are initially zero. Increasing the offsets
- /// gives tighter bounds on the channel liquidity balance. Thus, halving the offsets decreases
- /// the certainty of the channel liquidity balance.
+ /// For example, if the channel's capacity is 1 million sats, and the current upper and lower
+ /// liquidity bounds are 200,000 sats and 600,000 sats, after this amount of time the upper
+ /// and lower liquidity bounds will be decayed to 100,000 and 800,000 sats.
///
- /// Default value: 1 hour
+ /// Default value: 6 hours
///
/// # Note
///
pub liquidity_offset_half_life: Duration,
/// A multiplier used in conjunction with a payment amount and the negative `log10` of the
- /// channel's success probability for the payment to determine the amount penalty.
+ /// channel's success probability for the payment, as determined by our latest estimates of the
+ /// channel's liquidity, to determine the amount penalty.
///
/// The purpose of the amount penalty is to avoid having fees dominate the channel cost (i.e.,
/// fees plus penalty) for large payments. The penalty is computed as the product of this
/// probabilities, the multiplier will have a decreasing effect as the negative `log10` will
/// fall below `1`.
///
- /// Default value: 256 msat
+ /// Default value: 192 msat
pub liquidity_penalty_amount_multiplier_msat: u64,
+ /// A multiplier used in conjunction with the negative `log10` of the channel's success
+ /// probability for the payment, as determined based on the history of our estimates of the
+ /// channel's available liquidity, to determine a penalty.
+ ///
+ /// This penalty is similar to [`liquidity_penalty_multiplier_msat`], however, instead of using
+ /// only our latest estimate for the current liquidity available in the channel, it estimates
+ /// success probability based on the estimated liquidity available in the channel through
+ /// history. Specifically, every time we update our liquidity bounds on a given channel, we
+ /// track which of several buckets those bounds fall into, exponentially decaying the
+ /// probability of each bucket as new samples are added.
+ ///
+ /// Default value: 10,000 msat
+ ///
+ /// [`liquidity_penalty_multiplier_msat`]: Self::liquidity_penalty_multiplier_msat
+ pub historical_liquidity_penalty_multiplier_msat: u64,
+
+ /// A multiplier used in conjunction with the payment amount and the negative `log10` of the
+ /// channel's success probability for the payment, as determined based on the history of our
+ /// estimates of the channel's available liquidity, to determine a penalty.
+ ///
+ /// The purpose of the amount penalty is to avoid having fees dominate the channel cost for
+ /// large payments. The penalty is computed as the product of this multiplier and the `2^20`ths
+ /// of the payment amount, weighted by the negative `log10` of the success probability.
+ ///
+ /// This penalty is similar to [`liquidity_penalty_amount_multiplier_msat`], however, instead
+ /// of using only our latest estimate for the current liquidity available in the channel, it
+ /// estimates success probability based on the estimated liquidity available in the channel
+ /// through history. Specifically, every time we update our liquidity bounds on a given
+ /// channel, we track which of several buckets those bounds fall into, exponentially decaying
+ /// the probability of each bucket as new samples are added.
+ ///
+ /// Default value: 64 msat
+ ///
+ /// [`liquidity_penalty_amount_multiplier_msat`]: Self::liquidity_penalty_amount_multiplier_msat
+ pub historical_liquidity_penalty_amount_multiplier_msat: u64,
+
+ /// If we aren't learning any new datapoints for a channel, the historical liquidity bounds
+ /// tracking can simply live on with increasingly stale data. Instead, when a channel has not
+ /// seen a liquidity estimate update for this amount of time, the historical datapoints are
+ /// decayed by half.
+ ///
+ /// Note that after 16 or more half lives all historical data will be completely gone.
+ ///
+ /// Default value: 14 days
+ pub historical_no_updates_half_life: Duration,
+
/// Manual penalties used for the given nodes. Allows to set a particular penalty for a given
/// node. Note that a manual penalty of `u64::max_value()` means the node would not ever be
/// considered during path finding.
pub considered_impossible_penalty_msat: u64,
}
+/// Tracks the historical state of a distribution as a weighted average of how much time was spent
+/// in each of 8 buckets.
+#[derive(Clone, Copy)]
+struct HistoricalBucketRangeTracker {
+ buckets: [u16; 8],
+}
+
+impl HistoricalBucketRangeTracker {
+ fn new() -> Self { Self { buckets: [0; 8] } }
+ fn track_datapoint(&mut self, bucket_idx: u8) {
+ // We have 8 leaky buckets for min and max liquidity. Each bucket tracks the amount of time
+ // we spend in each bucket as a 16-bit fixed-point number with a 5 bit fractional part.
+ //
+ // Each time we update our liquidity estimate, we add 32 (1.0 in our fixed-point system) to
+ // the buckets for the current min and max liquidity offset positions.
+ //
+ // We then decay each bucket by multiplying by 2047/2048 (avoiding dividing by a
+ // non-power-of-two). This ensures we can't actually overflow the u16 - when we get to
+ // 63,457 adding 32 and decaying by 2047/2048 leaves us back at 63,457.
+ //
+ // In total, this allows us to track data for the last 8,000 or so payments across a given
+ // channel.
+ //
+ // These constants are a balance - we try to fit in 2 bytes per bucket to reduce overhead,
+ // and need to balance having more bits in the decimal part (to ensure decay isn't too
+ // non-linear) with having too few bits in the mantissa, causing us to not store very many
+ // datapoints.
+ //
+ // The constants were picked experimentally, selecting a decay amount that restricts us
+ // from overflowing buckets without having to cap them manually.
+ debug_assert!(bucket_idx < 8);
+ if bucket_idx < 8 {
+ for e in self.buckets.iter_mut() {
+ *e = ((*e as u32) * 2047 / 2048) as u16;
+ }
+ self.buckets[bucket_idx as usize] = self.buckets[bucket_idx as usize].saturating_add(32);
+ }
+ }
+ /// Decay all buckets by the given number of half-lives. Used to more aggressively remove old
+ /// datapoints as we receive newer information.
+ fn time_decay_data(&mut self, half_lives: u32) {
+ for e in self.buckets.iter_mut() {
+ *e = e.checked_shr(half_lives).unwrap_or(0);
+ }
+ }
+}
+
+impl_writeable_tlv_based!(HistoricalBucketRangeTracker, { (0, buckets, required) });
+
+struct HistoricalMinMaxBuckets<'a> {
+ min_liquidity_offset_history: &'a HistoricalBucketRangeTracker,
+ max_liquidity_offset_history: &'a HistoricalBucketRangeTracker,
+}
+
+impl HistoricalMinMaxBuckets<'_> {
+ #[inline]
+ fn calculate_success_probability_times_billion(&self, required_decays: u32, payment_amt_64th_bucket: u8) -> Option<u64> {
+ // If historical penalties are enabled, calculate the penalty by walking the set of
+ // historical liquidity bucket (min, max) combinations (where min_idx < max_idx) and, for
+ // each, calculate the probability of success given our payment amount, then total the
+ // weighted average probability of success.
+ //
+ // We use a sliding scale to decide which point within a given bucket will be compared to
+ // the amount being sent - for lower-bounds, the amount being sent is compared to the lower
+ // edge of the first bucket (i.e. zero), but compared to the upper 7/8ths of the last
+ // bucket (i.e. 9 times the index, or 63), with each bucket in between increasing the
+ // comparison point by 1/64th. For upper-bounds, the same applies, however with an offset
+ // of 1/64th (i.e. starting at one and ending at 64). This avoids failing to assign
+ // penalties to channels at the edges.
+ //
+ // If we used the bottom edge of buckets, we'd end up never assigning any penalty at all to
+ // such a channel when sending less than ~0.19% of the channel's capacity (e.g. ~200k sats
+ // for a 1 BTC channel!).
+ //
+ // If we used the middle of each bucket we'd never assign any penalty at all when sending
+ // less than 1/16th of a channel's capacity, or 1/8th if we used the top of the bucket.
+ let mut total_valid_points_tracked = 0;
+
+ // Rather than actually decaying the individual buckets, which would lose precision, we
+ // simply track whether all buckets would be decayed to zero, in which case we treat it as
+ // if we had no data.
+ let mut is_fully_decayed = true;
+ let mut check_track_bucket_contains_undecayed_points =
+ |bucket_val: u16| if bucket_val.checked_shr(required_decays).unwrap_or(0) > 0 { is_fully_decayed = false; };
+
+ for (min_idx, min_bucket) in self.min_liquidity_offset_history.buckets.iter().enumerate() {
+ check_track_bucket_contains_undecayed_points(*min_bucket);
+ for max_bucket in self.max_liquidity_offset_history.buckets.iter().take(8 - min_idx) {
+ total_valid_points_tracked += (*min_bucket as u64) * (*max_bucket as u64);
+ check_track_bucket_contains_undecayed_points(*max_bucket);
+ }
+ }
+ // If the total valid points is smaller than 1.0 (i.e. 32 in our fixed-point scheme), treat
+ // it as if we were fully decayed.
+ if total_valid_points_tracked.checked_shr(required_decays).unwrap_or(0) < 32*32 || is_fully_decayed {
+ return None;
+ }
+
+ let mut cumulative_success_prob_times_billion = 0;
+ for (min_idx, min_bucket) in self.min_liquidity_offset_history.buckets.iter().enumerate() {
+ for (max_idx, max_bucket) in self.max_liquidity_offset_history.buckets.iter().enumerate().take(8 - min_idx) {
+ let bucket_prob_times_million = (*min_bucket as u64) * (*max_bucket as u64)
+ * 1024 * 1024 / total_valid_points_tracked;
+ let min_64th_bucket = min_idx as u8 * 9;
+ let max_64th_bucket = (7 - max_idx as u8) * 9 + 1;
+ if payment_amt_64th_bucket > max_64th_bucket {
+ // Success probability 0, the payment amount is above the max liquidity
+ } else if payment_amt_64th_bucket <= min_64th_bucket {
+ cumulative_success_prob_times_billion += bucket_prob_times_million * 1024;
+ } else {
+ cumulative_success_prob_times_billion += bucket_prob_times_million *
+ ((max_64th_bucket - payment_amt_64th_bucket) as u64) * 1024 /
+ ((max_64th_bucket - min_64th_bucket) as u64);
+ }
+ }
+ }
+
+ Some(cumulative_success_prob_times_billion)
+ }
+}
+
/// Accounting for channel liquidity balance uncertainty.
///
/// Direction is defined in terms of [`NodeId`] partial ordering, where the source node is the
/// Time when the liquidity bounds were last modified.
last_updated: T,
+
+ min_liquidity_offset_history: HistoricalBucketRangeTracker,
+ max_liquidity_offset_history: HistoricalBucketRangeTracker,
}
/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
/// decayed with a given half life.
-struct DirectedChannelLiquidity<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> {
+struct DirectedChannelLiquidity<'a, L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> {
min_liquidity_offset_msat: L,
max_liquidity_offset_msat: L,
+ min_liquidity_offset_history: BRT,
+ max_liquidity_offset_history: BRT,
capacity_msat: u64,
last_updated: U,
now: T,
- half_life: Duration,
+ params: &'a ProbabilisticScoringParameters,
}
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
let log_direction = |source, target| {
if let Some((directed_info, _)) = chan_debug.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
- let dir_liq = liq.as_directed(source, target, amt, self.params.liquidity_offset_half_life);
+ let dir_liq = liq.as_directed(source, target, amt, &self.params);
log_debug!(self.logger, "Liquidity from {:?} to {:?} via {} is in the range ({}, {})",
source, target, scid, dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat());
} else {
if let Some(liq) = self.channel_liquidities.get(&scid) {
if let Some((directed_info, source)) = chan.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
- let dir_liq = liq.as_directed(source, target, amt, self.params.liquidity_offset_half_life);
+ let dir_liq = liq.as_directed(source, target, amt, &self.params);
return Some((dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat()));
}
}
base_penalty_msat: 0,
base_penalty_amount_multiplier_msat: 0,
liquidity_penalty_multiplier_msat: 0,
- liquidity_offset_half_life: Duration::from_secs(3600),
+ liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
liquidity_penalty_amount_multiplier_msat: 0,
+ historical_liquidity_penalty_multiplier_msat: 0,
+ historical_liquidity_penalty_amount_multiplier_msat: 0,
+ historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
manual_node_penalties: HashMap::new(),
anti_probing_penalty_msat: 0,
considered_impossible_penalty_msat: 0,
Self {
base_penalty_msat: 500,
base_penalty_amount_multiplier_msat: 8192,
- liquidity_penalty_multiplier_msat: 40_000,
- liquidity_offset_half_life: Duration::from_secs(3600),
- liquidity_penalty_amount_multiplier_msat: 256,
+ liquidity_penalty_multiplier_msat: 30_000,
+ liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
+ liquidity_penalty_amount_multiplier_msat: 192,
+ historical_liquidity_penalty_multiplier_msat: 10_000,
+ historical_liquidity_penalty_amount_multiplier_msat: 64,
+ historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
manual_node_penalties: HashMap::new(),
anti_probing_penalty_msat: 250,
considered_impossible_penalty_msat: 1_0000_0000_000,
Self {
min_liquidity_offset_msat: 0,
max_liquidity_offset_msat: 0,
+ min_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
+ max_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
last_updated: T::now(),
}
}
/// Returns a view of the channel liquidity directed from `source` to `target` assuming
/// `capacity_msat`.
- fn as_directed(
- &self, source: &NodeId, target: &NodeId, capacity_msat: u64, half_life: Duration
- ) -> DirectedChannelLiquidity<&u64, T, &T> {
- let (min_liquidity_offset_msat, max_liquidity_offset_msat) = if source < target {
- (&self.min_liquidity_offset_msat, &self.max_liquidity_offset_msat)
- } else {
- (&self.max_liquidity_offset_msat, &self.min_liquidity_offset_msat)
- };
+ fn as_directed<'a>(
+ &self, source: &NodeId, target: &NodeId, capacity_msat: u64, params: &'a ProbabilisticScoringParameters
+ ) -> DirectedChannelLiquidity<'a, &u64, &HistoricalBucketRangeTracker, T, &T> {
+ let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
+ if source < target {
+ (&self.min_liquidity_offset_msat, &self.max_liquidity_offset_msat,
+ &self.min_liquidity_offset_history, &self.max_liquidity_offset_history)
+ } else {
+ (&self.max_liquidity_offset_msat, &self.min_liquidity_offset_msat,
+ &self.max_liquidity_offset_history, &self.min_liquidity_offset_history)
+ };
DirectedChannelLiquidity {
min_liquidity_offset_msat,
max_liquidity_offset_msat,
+ min_liquidity_offset_history,
+ max_liquidity_offset_history,
capacity_msat,
last_updated: &self.last_updated,
now: T::now(),
- half_life,
+ params,
}
}
/// Returns a mutable view of the channel liquidity directed from `source` to `target` assuming
/// `capacity_msat`.
- fn as_directed_mut(
- &mut self, source: &NodeId, target: &NodeId, capacity_msat: u64, half_life: Duration
- ) -> DirectedChannelLiquidity<&mut u64, T, &mut T> {
- let (min_liquidity_offset_msat, max_liquidity_offset_msat) = if source < target {
- (&mut self.min_liquidity_offset_msat, &mut self.max_liquidity_offset_msat)
- } else {
- (&mut self.max_liquidity_offset_msat, &mut self.min_liquidity_offset_msat)
- };
+ fn as_directed_mut<'a>(
+ &mut self, source: &NodeId, target: &NodeId, capacity_msat: u64, params: &'a ProbabilisticScoringParameters
+ ) -> DirectedChannelLiquidity<'a, &mut u64, &mut HistoricalBucketRangeTracker, T, &mut T> {
+ let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
+ if source < target {
+ (&mut self.min_liquidity_offset_msat, &mut self.max_liquidity_offset_msat,
+ &mut self.min_liquidity_offset_history, &mut self.max_liquidity_offset_history)
+ } else {
+ (&mut self.max_liquidity_offset_msat, &mut self.min_liquidity_offset_msat,
+ &mut self.max_liquidity_offset_history, &mut self.min_liquidity_offset_history)
+ };
DirectedChannelLiquidity {
min_liquidity_offset_msat,
max_liquidity_offset_msat,
+ min_liquidity_offset_history,
+ max_liquidity_offset_history,
capacity_msat,
last_updated: &mut self.last_updated,
now: T::now(),
- half_life,
+ params,
}
}
}
const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20;
const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
-impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<L, T, U> {
+impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<'_, L, BRT, T, U> {
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
/// this direction.
fn penalty_msat(&self, amount_msat: u64, params: &ProbabilisticScoringParameters) -> u64 {
let max_liquidity_msat = self.max_liquidity_msat();
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
- if amount_msat <= min_liquidity_msat {
+
+ let mut res = if amount_msat <= min_liquidity_msat {
0
} else if amount_msat >= max_liquidity_msat {
// Equivalent to hitting the else clause below with the amount equal to the effective
// capacity and without any certainty on the liquidity upper bound, plus the
// impossibility penalty.
let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048;
- self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params)
+ Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
+ params.liquidity_penalty_multiplier_msat,
+ params.liquidity_penalty_amount_multiplier_msat)
.saturating_add(params.considered_impossible_penalty_msat)
} else {
let numerator = (max_liquidity_msat - amount_msat).saturating_add(1);
} else {
let negative_log10_times_2048 =
approx::negative_log10_times_2048(numerator, denominator);
- self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params)
+ Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
+ params.liquidity_penalty_multiplier_msat,
+ params.liquidity_penalty_amount_multiplier_msat)
+ }
+ };
+
+ if params.historical_liquidity_penalty_multiplier_msat != 0 ||
+ params.historical_liquidity_penalty_amount_multiplier_msat != 0 {
+ let required_decays = self.now.duration_since(*self.last_updated).as_secs()
+ .checked_div(params.historical_no_updates_half_life.as_secs())
+ .map_or(u32::max_value(), |decays| cmp::min(decays, u32::max_value() as u64) as u32);
+ let payment_amt_64th_bucket = amount_msat * 64 / self.capacity_msat;
+ debug_assert!(payment_amt_64th_bucket <= 64);
+ if payment_amt_64th_bucket > 64 { return res; }
+
+ let buckets = HistoricalMinMaxBuckets {
+ min_liquidity_offset_history: &self.min_liquidity_offset_history,
+ max_liquidity_offset_history: &self.max_liquidity_offset_history,
+ };
+ if let Some(cumulative_success_prob_times_billion) = buckets
+ .calculate_success_probability_times_billion(required_decays, payment_amt_64th_bucket as u8) {
+ let historical_negative_log10_times_2048 = approx::negative_log10_times_2048(cumulative_success_prob_times_billion + 1, 1024 * 1024 * 1024);
+ res = res.saturating_add(Self::combined_penalty_msat(amount_msat,
+ historical_negative_log10_times_2048, params.historical_liquidity_penalty_multiplier_msat,
+ params.historical_liquidity_penalty_amount_multiplier_msat));
+ } else {
+ // If we don't have any valid points (or, once decayed, we have less than a full
+ // point), redo the non-historical calculation with no liquidity bounds tracked and
+ // the historical penalty multipliers.
+ let max_capacity = self.capacity_msat.saturating_sub(amount_msat).saturating_add(1);
+ let negative_log10_times_2048 =
+ approx::negative_log10_times_2048(max_capacity, self.capacity_msat.saturating_add(1));
+ res = res.saturating_add(Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
+ params.historical_liquidity_penalty_multiplier_msat,
+ params.historical_liquidity_penalty_amount_multiplier_msat));
+ return res;
}
}
+
+ res
}
/// Computes the liquidity penalty from the penalty multipliers.
#[inline(always)]
- fn combined_penalty_msat(
- &self, amount_msat: u64, negative_log10_times_2048: u64,
- params: &ProbabilisticScoringParameters
+ fn combined_penalty_msat(amount_msat: u64, negative_log10_times_2048: u64,
+ liquidity_penalty_multiplier_msat: u64, liquidity_penalty_amount_multiplier_msat: u64,
) -> u64 {
let liquidity_penalty_msat = {
// Upper bound the liquidity penalty to ensure some channel is selected.
- let multiplier_msat = params.liquidity_penalty_multiplier_msat;
+ let multiplier_msat = liquidity_penalty_multiplier_msat;
let max_penalty_msat = multiplier_msat.saturating_mul(NEGATIVE_LOG10_UPPER_BOUND);
(negative_log10_times_2048.saturating_mul(multiplier_msat) / 2048).min(max_penalty_msat)
};
let amount_penalty_msat = negative_log10_times_2048
- .saturating_mul(params.liquidity_penalty_amount_multiplier_msat)
+ .saturating_mul(liquidity_penalty_amount_multiplier_msat)
.saturating_mul(amount_msat) / 2048 / AMOUNT_PENALTY_DIVISOR;
liquidity_penalty_msat.saturating_add(amount_penalty_msat)
fn decayed_offset_msat(&self, offset_msat: u64) -> u64 {
self.now.duration_since(*self.last_updated).as_secs()
- .checked_div(self.half_life.as_secs())
+ .checked_div(self.params.liquidity_offset_half_life.as_secs())
.and_then(|decays| offset_msat.checked_shr(decays as u32))
.unwrap_or(0)
}
}
-impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChannelLiquidity<L, T, U> {
+impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTracker>, T: Time, U: DerefMut<Target = T>> DirectedChannelLiquidity<'_, L, BRT, T, U> {
/// Adjusts the channel liquidity balance bounds when failing to route `amount_msat`.
fn failed_at_channel<Log: Deref>(&mut self, amount_msat: u64, chan_descr: fmt::Arguments, logger: &Log) where Log::Target: Logger {
- if amount_msat < self.max_liquidity_msat() {
- log_debug!(logger, "Setting max liquidity of {} to {}", chan_descr, amount_msat);
+ let existing_max_msat = self.max_liquidity_msat();
+ if amount_msat < existing_max_msat {
+ log_debug!(logger, "Setting max liquidity of {} from {} to {}", chan_descr, existing_max_msat, amount_msat);
self.set_max_liquidity_msat(amount_msat);
} else {
- log_trace!(logger, "Max liquidity of {} already more than {}", chan_descr, amount_msat);
+ log_trace!(logger, "Max liquidity of {} is {} (already less than or equal to {})",
+ chan_descr, existing_max_msat, amount_msat);
}
}
/// Adjusts the channel liquidity balance bounds when failing to route `amount_msat` downstream.
fn failed_downstream<Log: Deref>(&mut self, amount_msat: u64, chan_descr: fmt::Arguments, logger: &Log) where Log::Target: Logger {
- if amount_msat > self.min_liquidity_msat() {
- log_debug!(logger, "Setting min liquidity of {} to {}", chan_descr, amount_msat);
+ let existing_min_msat = self.min_liquidity_msat();
+ if amount_msat > existing_min_msat {
+ log_debug!(logger, "Setting min liquidity of {} from {} to {}", existing_min_msat, chan_descr, amount_msat);
self.set_min_liquidity_msat(amount_msat);
} else {
- log_trace!(logger, "Min liquidity of {} already less than {}", chan_descr, amount_msat);
+ log_trace!(logger, "Min liquidity of {} is {} (already greater than or equal to {})",
+ chan_descr, existing_min_msat, amount_msat);
}
}
self.set_max_liquidity_msat(max_liquidity_msat);
}
+ fn update_history_buckets(&mut self) {
+ let half_lives = self.now.duration_since(*self.last_updated).as_secs()
+ .checked_div(self.params.historical_no_updates_half_life.as_secs())
+ .map(|v| v.try_into().unwrap_or(u32::max_value())).unwrap_or(u32::max_value());
+ self.min_liquidity_offset_history.time_decay_data(half_lives);
+ self.max_liquidity_offset_history.time_decay_data(half_lives);
+
+ debug_assert!(*self.min_liquidity_offset_msat <= self.capacity_msat);
+ self.min_liquidity_offset_history.track_datapoint(
+ // Ensure the bucket index we pass is in the range [0, 7], even if the liquidity offset
+ // is zero or the channel's capacity, though the second should generally never happen.
+ (self.min_liquidity_offset_msat.saturating_sub(1) * 8 / self.capacity_msat)
+ .try_into().unwrap_or(32)); // 32 is bogus for 8 buckets, and will be ignored
+ debug_assert!(*self.max_liquidity_offset_msat <= self.capacity_msat);
+ self.max_liquidity_offset_history.track_datapoint(
+ // Ensure the bucket index we pass is in the range [0, 7], even if the liquidity offset
+ // is zero or the channel's capacity, though the second should generally never happen.
+ (self.max_liquidity_offset_msat.saturating_sub(1) * 8 / self.capacity_msat)
+ .try_into().unwrap_or(32)); // 32 is bogus for 8 buckets, and will be ignored
+ }
+
/// Adjusts the lower bound of the channel liquidity balance in this direction.
fn set_min_liquidity_msat(&mut self, amount_msat: u64) {
*self.min_liquidity_offset_msat = amount_msat;
} else {
self.decayed_offset_msat(*self.max_liquidity_offset_msat)
};
+ self.update_history_buckets();
*self.last_updated = self.now;
}
} else {
self.decayed_offset_msat(*self.min_liquidity_offset_msat)
};
+ self.update_history_buckets();
*self.last_updated = self.now;
}
}
_ => {},
}
- let liquidity_offset_half_life = self.params.liquidity_offset_half_life;
let amount_msat = usage.amount_msat;
let capacity_msat = usage.effective_capacity.as_msat()
.saturating_sub(usage.inflight_htlc_msat);
self.channel_liquidities
.get(&short_channel_id)
.unwrap_or(&ChannelLiquidity::new())
- .as_directed(source, target, capacity_msat, liquidity_offset_half_life)
+ .as_directed(source, target, capacity_msat, &self.params)
.penalty_msat(amount_msat, &self.params)
.saturating_add(anti_probing_penalty_msat)
.saturating_add(base_penalty_msat)
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
let amount_msat = path.split_last().map(|(hop, _)| hop.fee_msat).unwrap_or(0);
- let liquidity_offset_half_life = self.params.liquidity_offset_half_life;
log_trace!(self.logger, "Scoring path through to SCID {} as having failed at {} msat", short_channel_id, amount_msat);
let network_graph = self.network_graph.read_only();
for (hop_idx, hop) in path.iter().enumerate() {
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(ChannelLiquidity::new)
- .as_directed_mut(source, &target, capacity_msat, liquidity_offset_half_life)
+ .as_directed_mut(source, &target, capacity_msat, &self.params)
.failed_at_channel(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
break;
}
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(ChannelLiquidity::new)
- .as_directed_mut(source, &target, capacity_msat, liquidity_offset_half_life)
+ .as_directed_mut(source, &target, capacity_msat, &self.params)
.failed_downstream(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
} else {
log_debug!(self.logger, "Not able to penalize channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop).",
fn payment_path_successful(&mut self, path: &[&RouteHop]) {
let amount_msat = path.split_last().map(|(hop, _)| hop.fee_msat).unwrap_or(0);
- let liquidity_offset_half_life = self.params.liquidity_offset_half_life;
log_trace!(self.logger, "Scoring path through SCID {} as having succeeded at {} msat.",
path.split_last().map(|(hop, _)| hop.short_channel_id).unwrap_or(0), amount_msat);
let network_graph = self.network_graph.read_only();
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(ChannelLiquidity::new)
- .as_directed_mut(source, &target, capacity_msat, liquidity_offset_half_life)
+ .as_directed_mut(source, &target, capacity_msat, &self.params)
.successful(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
} else {
log_debug!(self.logger, "Not able to learn for channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop).",
let duration_since_epoch = T::duration_since_epoch() - self.last_updated.elapsed();
write_tlv_fields!(w, {
(0, self.min_liquidity_offset_msat, required),
+ (1, Some(self.min_liquidity_offset_history), option),
(2, self.max_liquidity_offset_msat, required),
+ (3, Some(self.max_liquidity_offset_history), option),
(4, duration_since_epoch, required),
});
Ok(())
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let mut min_liquidity_offset_msat = 0;
let mut max_liquidity_offset_msat = 0;
+ let mut min_liquidity_offset_history = Some(HistoricalBucketRangeTracker::new());
+ let mut max_liquidity_offset_history = Some(HistoricalBucketRangeTracker::new());
let mut duration_since_epoch = Duration::from_secs(0);
read_tlv_fields!(r, {
(0, min_liquidity_offset_msat, required),
+ (1, min_liquidity_offset_history, option),
(2, max_liquidity_offset_msat, required),
+ (3, max_liquidity_offset_history, option),
(4, duration_since_epoch, required),
});
// On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
Ok(Self {
min_liquidity_offset_msat,
max_liquidity_offset_msat,
+ min_liquidity_offset_history: min_liquidity_offset_history.unwrap(),
+ max_liquidity_offset_history: max_liquidity_offset_history.unwrap(),
last_updated,
})
}
#[cfg(test)]
mod tests {
- use super::{ChannelLiquidity, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime};
+ use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime};
use util::time::Time;
use util::time::tests::SinceEpoch;
- use ln::features::{ChannelFeatures, NodeFeatures};
+ use ln::channelmanager;
use ln::msgs::{ChannelAnnouncement, ChannelUpdate, UnsignedChannelAnnouncement, UnsignedChannelUpdate};
use routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId};
use routing::router::RouteHop;
let node_2_secret = &SecretKey::from_slice(&[40; 32]).unwrap();
let secp_ctx = Secp256k1::new();
let unsigned_announcement = UnsignedChannelAnnouncement {
- features: ChannelFeatures::known(),
+ features: channelmanager::provided_channel_features(),
chain_hash: genesis_hash,
short_channel_id,
node_id_1: PublicKey::from_secret_key(&secp_ctx, &node_1_key),
vec![
RouteHop {
pubkey: source_pubkey(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: 41,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 1,
cltv_expiry_delta: 18,
},
RouteHop {
pubkey: target_pubkey(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: 42,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: 2,
cltv_expiry_delta: 18,
},
RouteHop {
pubkey: recipient_pubkey(),
- node_features: NodeFeatures::known(),
+ node_features: channelmanager::provided_node_features(),
short_channel_id: 43,
- channel_features: ChannelFeatures::known(),
+ channel_features: channelmanager::provided_channel_features(),
fee_msat: amount_msat,
cltv_expiry_delta: 18,
},
let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
- min_liquidity_offset_msat: 700, max_liquidity_offset_msat: 100, last_updated
+ min_liquidity_offset_msat: 700, max_liquidity_offset_msat: 100, last_updated,
+ min_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
+ max_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
})
.with_channel(43,
ChannelLiquidity {
- min_liquidity_offset_msat: 700, max_liquidity_offset_msat: 100, last_updated
+ min_liquidity_offset_msat: 700, max_liquidity_offset_msat: 100, last_updated,
+ min_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
+ max_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
});
let source = source_node_id();
let target = target_node_id();
// Update minimum liquidity.
- let liquidity_offset_half_life = scorer.params.liquidity_offset_half_life;
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 100);
assert_eq!(liquidity.max_liquidity_msat(), 300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 900);
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&source, &target, 1_000, liquidity_offset_half_life)
+ .as_directed_mut(&source, &target, 1_000, &scorer.params)
.set_min_liquidity_msat(200);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 800);
// Update maximum liquidity.
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&target, &recipient, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &recipient, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 900);
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&recipient, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&recipient, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 100);
assert_eq!(liquidity.max_liquidity_msat(), 300);
scorer.channel_liquidities.get_mut(&43).unwrap()
- .as_directed_mut(&target, &recipient, 1_000, liquidity_offset_half_life)
+ .as_directed_mut(&target, &recipient, 1_000, &scorer.params)
.set_max_liquidity_msat(200);
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&target, &recipient, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &recipient, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 200);
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&recipient, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&recipient, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 800);
assert_eq!(liquidity.max_liquidity_msat(), 1000);
}
let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
- min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated
+ min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated,
+ min_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
+ max_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
});
let source = source_node_id();
let target = target_node_id();
assert!(source > target);
// Check initial bounds.
- let liquidity_offset_half_life = scorer.params.liquidity_offset_half_life;
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 800);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 600);
// Reset from source to target.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&source, &target, 1_000, liquidity_offset_half_life)
+ .as_directed_mut(&source, &target, 1_000, &scorer.params)
.set_min_liquidity_msat(900);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 900);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 100);
// Reset from target to source.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&target, &source, 1_000, liquidity_offset_half_life)
+ .as_directed_mut(&target, &source, 1_000, &scorer.params)
.set_min_liquidity_msat(400);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 600);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
}
let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
- min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated
+ min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated,
+ min_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
+ max_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
});
let source = source_node_id();
let target = target_node_id();
assert!(source > target);
// Check initial bounds.
- let liquidity_offset_half_life = scorer.params.liquidity_offset_half_life;
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 800);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 600);
// Reset from source to target.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&source, &target, 1_000, liquidity_offset_half_life)
+ .as_directed_mut(&source, &target, 1_000, &scorer.params)
.set_max_liquidity_msat(300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
// Reset from target to source.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&target, &source, 1_000, liquidity_offset_half_life)
+ .as_directed_mut(&target, &source, 1_000, &scorer.params)
.set_max_liquidity_msat(600);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 1_000, liquidity_offset_half_life);
+ .as_directed(&source, &target, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 1_000, liquidity_offset_half_life);
+ .as_directed(&target, &source, 1_000, &scorer.params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 600);
}
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
- min_liquidity_offset_msat: 40, max_liquidity_offset_msat: 40, last_updated
+ min_liquidity_offset_msat: 40, max_liquidity_offset_msat: 40, last_updated,
+ min_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
+ max_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
});
let source = source_node_id();
let target = target_node_id();
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1985);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1983);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1639);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1637);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1607);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1606);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1331);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1387);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1379);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1363);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1355);
}
#[test]
let params = ProbabilisticScoringParameters {
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
- anti_probing_penalty_msat: 0, ..Default::default()
+ anti_probing_penalty_msat: 0, ..ProbabilisticScoringParameters::zero_penalty()
};
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
let params = ProbabilisticScoringParameters {
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
base_penalty_amount_multiplier_msat: (1 << 30),
- anti_probing_penalty_msat: 0, ..Default::default()
+ anti_probing_penalty_msat: 0, ..ProbabilisticScoringParameters::zero_penalty()
};
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
}
+ #[test]
+ fn remembers_historical_failures() {
+ let logger = TestLogger::new();
+ let network_graph = network_graph(&logger);
+ let params = ProbabilisticScoringParameters {
+ historical_liquidity_penalty_multiplier_msat: 1024,
+ historical_liquidity_penalty_amount_multiplier_msat: 1024,
+ historical_no_updates_half_life: Duration::from_secs(10),
+ ..ProbabilisticScoringParameters::zero_penalty()
+ };
+ let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let source = source_node_id();
+ let target = target_node_id();
+
+ let usage = ChannelUsage {
+ amount_msat: 100,
+ inflight_htlc_msat: 0,
+ effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_024) },
+ };
+ // With no historical data the normal liquidity penalty calculation is used.
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+
+ scorer.payment_path_failed(&payment_path_for_amount(1).iter().collect::<Vec<_>>(), 42);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2048);
+
+ // Even after we tell the scorer we definitely have enough available liquidity, it will
+ // still remember that there was some failure in the past, and assign a non-0 penalty.
+ scorer.payment_path_failed(&payment_path_for_amount(1000).iter().collect::<Vec<_>>(), 43);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 198);
+
+ // Advance the time forward 16 half-lives (which the docs claim will ensure all data is
+ // gone), and check that we're back to where we started.
+ SinceEpoch::advance(Duration::from_secs(10 * 16));
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+ }
+
#[test]
fn adds_anti_probing_penalty() {
let logger = TestLogger::new();
--- /dev/null
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+use routing::gossip::{NetworkGraph, P2PGossipSync};
+use ln::features::{ChannelFeatures, NodeFeatures};
+use ln::msgs::{UnsignedChannelAnnouncement, ChannelAnnouncement, RoutingMessageHandler,
+ NodeAnnouncement, UnsignedNodeAnnouncement, ChannelUpdate, UnsignedChannelUpdate, MAX_VALUE_MSAT};
+use util::test_utils;
+use util::ser::Writeable;
+
+use bitcoin::hashes::sha256d::Hash as Sha256dHash;
+use bitcoin::hashes::Hash;
+use bitcoin::network::constants::Network;
+use bitcoin::blockdata::constants::genesis_block;
+
+use hex;
+
+use bitcoin::secp256k1::{PublicKey,SecretKey};
+use bitcoin::secp256k1::{Secp256k1, All};
+
+use prelude::*;
+use sync::{self, Arc};
+
+// Using the same keys for LN and BTC ids
+pub(super) fn add_channel(
+ gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+ secp_ctx: &Secp256k1<All>, node_1_privkey: &SecretKey, node_2_privkey: &SecretKey, features: ChannelFeatures, short_channel_id: u64
+) {
+ let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
+ let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
+
+ let unsigned_announcement = UnsignedChannelAnnouncement {
+ features,
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id,
+ node_id_1,
+ node_id_2,
+ bitcoin_key_1: node_id_1,
+ bitcoin_key_2: node_id_2,
+ excess_data: Vec::new(),
+ };
+
+ let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
+ let valid_announcement = ChannelAnnouncement {
+ node_signature_1: secp_ctx.sign_ecdsa(&msghash, node_1_privkey),
+ node_signature_2: secp_ctx.sign_ecdsa(&msghash, node_2_privkey),
+ bitcoin_signature_1: secp_ctx.sign_ecdsa(&msghash, node_1_privkey),
+ bitcoin_signature_2: secp_ctx.sign_ecdsa(&msghash, node_2_privkey),
+ contents: unsigned_announcement.clone(),
+ };
+ match gossip_sync.handle_channel_announcement(&valid_announcement) {
+ Ok(res) => assert!(res),
+ _ => panic!()
+ };
+}
+
+pub(super) fn add_or_update_node(
+ gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+ secp_ctx: &Secp256k1<All>, node_privkey: &SecretKey, features: NodeFeatures, timestamp: u32
+) {
+ let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey);
+ let unsigned_announcement = UnsignedNodeAnnouncement {
+ features,
+ timestamp,
+ node_id,
+ rgb: [0; 3],
+ alias: [0; 32],
+ addresses: Vec::new(),
+ excess_address_data: Vec::new(),
+ excess_data: Vec::new(),
+ };
+ let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
+ let valid_announcement = NodeAnnouncement {
+ signature: secp_ctx.sign_ecdsa(&msghash, node_privkey),
+ contents: unsigned_announcement.clone()
+ };
+
+ match gossip_sync.handle_node_announcement(&valid_announcement) {
+ Ok(_) => (),
+ Err(_) => panic!()
+ };
+}
+
+pub(super) fn update_channel(
+ gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+ secp_ctx: &Secp256k1<All>, node_privkey: &SecretKey, update: UnsignedChannelUpdate
+) {
+ let msghash = hash_to_message!(&Sha256dHash::hash(&update.encode()[..])[..]);
+ let valid_channel_update = ChannelUpdate {
+ signature: secp_ctx.sign_ecdsa(&msghash, node_privkey),
+ contents: update.clone()
+ };
+
+ match gossip_sync.handle_channel_update(&valid_channel_update) {
+ Ok(res) => assert!(res),
+ Err(_) => panic!()
+ };
+}
+
+pub(super) fn get_nodes(secp_ctx: &Secp256k1<All>) -> (SecretKey, PublicKey, Vec<SecretKey>, Vec<PublicKey>) {
+ let privkeys: Vec<SecretKey> = (2..22).map(|i| {
+ SecretKey::from_slice(&hex::decode(format!("{:02x}", i).repeat(32)).unwrap()[..]).unwrap()
+ }).collect();
+
+ let pubkeys = privkeys.iter().map(|secret| PublicKey::from_secret_key(&secp_ctx, secret)).collect();
+
+ let our_privkey = SecretKey::from_slice(&hex::decode("01".repeat(32)).unwrap()[..]).unwrap();
+ let our_id = PublicKey::from_secret_key(&secp_ctx, &our_privkey);
+
+ (our_privkey, our_id, privkeys, pubkeys)
+}
+
+pub(super) fn id_to_feature_flags(id: u8) -> Vec<u8> {
+ // Set the feature flags to the id'th odd (ie non-required) feature bit so that we can
+ // test for it later.
+ let idx = (id - 1) * 2 + 1;
+ if idx > 8*3 {
+ vec![1 << (idx - 8*3), 0, 0, 0]
+ } else if idx > 8*2 {
+ vec![1 << (idx - 8*2), 0, 0]
+ } else if idx > 8*1 {
+ vec![1 << (idx - 8*1), 0]
+ } else {
+ vec![1 << idx]
+ }
+}
+
+pub(super) fn build_line_graph() -> (
+ Secp256k1<All>, sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
+ P2PGossipSync<sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>>,
+ sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>,
+) {
+ let secp_ctx = Secp256k1::new();
+ let logger = Arc::new(test_utils::TestLogger::new());
+ let chain_monitor = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+ let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
+ let network_graph = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
+ let gossip_sync = P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
+
+ // Build network from our_id to node 19:
+ // our_id -1(1)2- node0 -1(2)2- node1 - ... - node19
+ let (our_privkey, _, privkeys, _) = get_nodes(&secp_ctx);
+
+ for (idx, (cur_privkey, next_privkey)) in core::iter::once(&our_privkey)
+ .chain(privkeys.iter()).zip(privkeys.iter()).enumerate() {
+ let cur_short_channel_id = (idx as u64) + 1;
+ add_channel(&gossip_sync, &secp_ctx, &cur_privkey, &next_privkey,
+ ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), cur_short_channel_id);
+ update_channel(&gossip_sync, &secp_ctx, &cur_privkey, UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: cur_short_channel_id,
+ timestamp: idx as u32,
+ flags: 0,
+ cltv_expiry_delta: 0,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &next_privkey, UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: cur_short_channel_id,
+ timestamp: (idx as u32)+1,
+ flags: 1,
+ cltv_expiry_delta: 0,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+ add_or_update_node(&gossip_sync, &secp_ctx, &next_privkey,
+ NodeFeatures::from_le_bytes(id_to_feature_flags(1)), 0);
+ }
+
+ (secp_ctx, network_graph, gossip_sync, chain_monitor, logger)
+}
+
+pub(super) fn build_graph() -> (
+ Secp256k1<All>,
+ sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
+ P2PGossipSync<sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>>,
+ sync::Arc<test_utils::TestChainSource>,
+ sync::Arc<test_utils::TestLogger>,
+) {
+ let secp_ctx = Secp256k1::new();
+ let logger = Arc::new(test_utils::TestLogger::new());
+ let chain_monitor = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+ let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
+ let network_graph = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
+ let gossip_sync = P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
+ // Build network from our_id to node6:
+ //
+ // -1(1)2- node0 -1(3)2-
+ // / \
+ // our_id -1(12)2- node7 -1(13)2--- node2
+ // \ /
+ // -1(2)2- node1 -1(4)2-
+ //
+ //
+ // chan1 1-to-2: disabled
+ // chan1 2-to-1: enabled, 0 fee
+ //
+ // chan2 1-to-2: enabled, ignored fee
+ // chan2 2-to-1: enabled, 0 fee
+ //
+ // chan3 1-to-2: enabled, 0 fee
+ // chan3 2-to-1: enabled, 100 msat fee
+ //
+ // chan4 1-to-2: enabled, 100% fee
+ // chan4 2-to-1: enabled, 0 fee
+ //
+ // chan12 1-to-2: enabled, ignored fee
+ // chan12 2-to-1: enabled, 0 fee
+ //
+ // chan13 1-to-2: enabled, 200% fee
+ // chan13 2-to-1: enabled, 0 fee
+ //
+ //
+ // -1(5)2- node3 -1(8)2--
+ // | 2 |
+ // | (11) |
+ // / 1 \
+ // node2--1(6)2- node4 -1(9)2--- node6 (not in global route map)
+ // \ /
+ // -1(7)2- node5 -1(10)2-
+ //
+ // Channels 5, 8, 9 and 10 are private channels.
+ //
+ // chan5 1-to-2: enabled, 100 msat fee
+ // chan5 2-to-1: enabled, 0 fee
+ //
+ // chan6 1-to-2: enabled, 0 fee
+ // chan6 2-to-1: enabled, 0 fee
+ //
+ // chan7 1-to-2: enabled, 100% fee
+ // chan7 2-to-1: enabled, 0 fee
+ //
+ // chan8 1-to-2: enabled, variable fee (0 then 1000 msat)
+ // chan8 2-to-1: enabled, 0 fee
+ //
+ // chan9 1-to-2: enabled, 1001 msat fee
+ // chan9 2-to-1: enabled, 0 fee
+ //
+ // chan10 1-to-2: enabled, 0 fee
+ // chan10 2-to-1: enabled, 0 fee
+ //
+ // chan11 1-to-2: enabled, 0 fee
+ // chan11 2-to-1: enabled, 0 fee
+
+ let (our_privkey, _, privkeys, _) = get_nodes(&secp_ctx);
+
+ add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[0], ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), 1);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[0], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 1,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: 0,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[0], NodeFeatures::from_le_bytes(id_to_feature_flags(1)), 0);
+
+ add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(2)), 2);
+ update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 2,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (5 << 4) | 3,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: u32::max_value(),
+ fee_proportional_millionths: u32::max_value(),
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 2,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: 0,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[1], NodeFeatures::from_le_bytes(id_to_feature_flags(2)), 0);
+
+ add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[7], ChannelFeatures::from_le_bytes(id_to_feature_flags(12)), 12);
+ update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 12,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (5 << 4) | 3,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: u32::max_value(),
+ fee_proportional_millionths: u32::max_value(),
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[7], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 12,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: 0,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[7], NodeFeatures::from_le_bytes(id_to_feature_flags(8)), 0);
+
+ add_channel(&gossip_sync, &secp_ctx, &privkeys[0], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(3)), 3);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[0], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 3,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (3 << 4) | 1,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 3,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: (3 << 4) | 2,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 100,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_channel(&gossip_sync, &secp_ctx, &privkeys[1], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(4)), 4);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 4,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (4 << 4) | 1,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 1000000,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 4,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: (4 << 4) | 2,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_channel(&gossip_sync, &secp_ctx, &privkeys[7], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(13)), 13);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[7], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 13,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (13 << 4) | 1,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 2000000,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 13,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: (13 << 4) | 2,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[2], NodeFeatures::from_le_bytes(id_to_feature_flags(3)), 0);
+
+ add_channel(&gossip_sync, &secp_ctx, &privkeys[2], &privkeys[4], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 6,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (6 << 4) | 1,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 6,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: (6 << 4) | 2,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new(),
+ });
+
+ add_channel(&gossip_sync, &secp_ctx, &privkeys[4], &privkeys[3], ChannelFeatures::from_le_bytes(id_to_feature_flags(11)), 11);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 11,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (11 << 4) | 1,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 11,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: (11 << 4) | 2,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[4], NodeFeatures::from_le_bytes(id_to_feature_flags(5)), 0);
+
+ add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[3], NodeFeatures::from_le_bytes(id_to_feature_flags(4)), 0);
+
+ add_channel(&gossip_sync, &secp_ctx, &privkeys[2], &privkeys[5], ChannelFeatures::from_le_bytes(id_to_feature_flags(7)), 7);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 7,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: (7 << 4) | 1,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 1000000,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[5], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 7,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: (7 << 4) | 2,
+ htlc_minimum_msat: 0,
+ htlc_maximum_msat: MAX_VALUE_MSAT,
+ fee_base_msat: 0,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[5], NodeFeatures::from_le_bytes(id_to_feature_flags(6)), 0);
+
+ (secp_ctx, network_graph, gossip_sync, chain_monitor, logger)
+}
use util::ser::{self, FixedLengthReader, LengthReadableArgs, Writeable};
// Used for for testing various lengths of serialization.
- #[derive(Debug, PartialEq)]
+ #[derive(Debug, PartialEq, Eq)]
struct TestWriteable {
field1: Vec<u8>,
field2: Vec<u8>,
/// Options which apply on a per-channel basis and may change at runtime or based on negotiation
/// with our counterparty.
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// to such payments may be sustantial if there are many dust HTLCs present when the
/// channel is force-closed.
///
+ /// The dust threshold for each HTLC is based on the `dust_limit_satoshis` for each party in a
+ /// channel negotiated throughout the channel open process, along with the fees required to have
+ /// a broadcastable HTLC spending transaction. When a channel supports anchor outputs
+ /// (specifically the zero fee HTLC transaction variant), this threshold no longer takes into
+ /// account the HTLC transaction fee as it is zero.
+ ///
/// This limit is applied for sent, forwarded, and received HTLCs and limits the total
/// exposure across all three types per-channel. Setting this too low may prevent the
/// sending or receipt of low-value HTLCs on high-traffic nodes, and this limit is very
// You may not use this file except in accordance with one or both of these
// licenses.
+use ln::channel::{ANCHOR_OUTPUT_VALUE_SATOSHI, MIN_CHAN_DUST_LIMIT_SATOSHIS};
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, HolderCommitmentTransaction, CommitmentTransaction, ChannelTransactionParameters, TrustedCommitmentTransaction, ClosingTransaction};
use ln::{chan_utils, msgs, PaymentPreimage};
use chain::keysinterface::{Sign, InMemorySigner, BaseSign};
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&this_htlc, self.opt_anchors(), &keys);
- let sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, EcdsaSighashType::All).unwrap()[..]);
+ let sighash_type = if self.opt_anchors() {
+ EcdsaSighashType::SinglePlusAnyoneCanPay
+ } else {
+ EcdsaSighashType::All
+ };
+ let sighash = hash_to_message!(
+ &sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(
+ 0, &htlc_redeemscript, this_htlc.amount_msat / 1000, sighash_type,
+ ).unwrap()[..]
+ );
secp_ctx.verify_ecdsa(&sighash, sig, &keys.countersignatory_htlc_key).unwrap();
}
Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap())
}
+ fn sign_holder_anchor_input(
+ &self, anchor_tx: &mut Transaction, input: usize, secp_ctx: &Secp256k1<secp256k1::All>,
+ ) -> Result<Signature, ()> {
+ debug_assert!(MIN_CHAN_DUST_LIMIT_SATOSHIS > ANCHOR_OUTPUT_VALUE_SATOSHI);
+ // As long as our minimum dust limit is enforced and is greater than our anchor output
+ // value, an anchor output can only have an index within [0, 1].
+ assert!(anchor_tx.input[input].previous_output.vout == 0 || anchor_tx.input[input].previous_output.vout == 1);
+ self.inner.sign_holder_anchor_input(anchor_tx, input, secp_ctx)
+ }
+
fn sign_channel_announcement(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>)
-> Result<(Signature, Signature), ()> {
self.inner.sign_channel_announcement(msg, secp_ctx)
/// Indicates an error on the client's part (usually some variant of attempting to use too-low or
/// too-high values)
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub enum APIError {
/// Indicates the API was wholly misused (see err for more). Cases where these can be returned
/// are documented, but generally indicates some precondition of a function was violated.
/// A human-readable error message
err: String
},
- /// An attempt to call watch/update_channel returned an Err (ie you did this!), causing the
- /// attempted action to fail.
- MonitorUpdateFailed,
+ /// An attempt to call [`chain::Watch::watch_channel`]/[`chain::Watch::update_channel`]
+ /// returned a [`ChannelMonitorUpdateStatus::InProgress`] indicating the persistence of a
+ /// monitor update is awaiting async resolution. Once it resolves the attempted action should
+ /// complete automatically.
+ ///
+ /// [`chain::Watch::watch_channel`]: crate::chain::Watch::watch_channel
+ /// [`chain::Watch::update_channel`]: crate::chain::Watch::update_channel
+ /// [`ChannelMonitorUpdateStatus::InProgress`]: crate::chain::ChannelMonitorUpdateStatus::InProgress
+ MonitorUpdateInProgress,
/// [`KeysInterface::get_shutdown_scriptpubkey`] returned a shutdown scriptpubkey incompatible
/// with the channel counterparty as negotiated in [`InitFeatures`].
///
APIError::FeeRateTooHigh {ref err, ref feerate} => write!(f, "{} feerate: {}", err, feerate),
APIError::RouteError {ref err} => write!(f, "Route error: {}", err),
APIError::ChannelUnavailable {ref err} => write!(f, "Channel unavailable: {}", err),
- APIError::MonitorUpdateFailed => f.write_str("Client indicated a channel monitor update failed"),
+ APIError::MonitorUpdateInProgress => f.write_str("Client indicated a channel monitor update is in progress but not yet complete"),
APIError::IncompatibleShutdownScript { ref script } => {
write!(f, "Provided a scriptpubkey format not accepted by peer: {}", script)
},
//! few other things.
use chain::keysinterface::SpendableOutputDescriptor;
+use ln::chan_utils::HTLCOutputInCommitment;
use ln::channelmanager::PaymentId;
use ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
use ln::features::ChannelTypeFeatures;
use util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper};
use routing::router::{RouteHop, RouteParameters};
-use bitcoin::{PackedLockTime, Transaction};
+use bitcoin::{PackedLockTime, Transaction, OutPoint};
use bitcoin::blockdata::script::Script;
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256::Hash as Sha256;
(2, SpontaneousPayment)
);
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// The reason the channel was closed. See individual variants more details.
pub enum ClosureReason {
/// Closure generated from receiving a peer error message.
);
/// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum HTLCDestination {
/// We tried forwarding to a channel but failed to do so. An example of such an instance is when
/// there is insufficient capacity in our outbound channel.
}
);
+/// A descriptor used to sign for a commitment transaction's anchor output.
+#[derive(Clone, Debug)]
+pub struct AnchorDescriptor {
+ /// A unique identifier used along with `channel_value_satoshis` to re-derive the
+ /// [`InMemorySigner`] required to sign `input`.
+ ///
+ /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
+ pub channel_keys_id: [u8; 32],
+ /// The value in satoshis of the channel we're attempting to spend the anchor output of. This is
+ /// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign
+ /// `input`.
+ ///
+ /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
+ pub channel_value_satoshis: u64,
+ /// The transaction input's outpoint corresponding to the commitment transaction's anchor
+ /// output.
+ pub outpoint: OutPoint,
+}
+
+/// Represents the different types of transactions, originating from LDK, to be bumped.
+#[derive(Clone, Debug)]
+pub enum BumpTransactionEvent {
+ /// Indicates that a channel featuring anchor outputs is to be closed by broadcasting the local
+ /// commitment transaction. Since commitment transactions have a static feerate pre-agreed upon,
+ /// they may need additional fees to be attached through a child transaction using the popular
+ /// [Child-Pays-For-Parent](https://bitcoinops.org/en/topics/cpfp) fee bumping technique. This
+ /// child transaction must include the anchor input described within `anchor_descriptor` along
+ /// with additional inputs to meet the target feerate. Failure to meet the target feerate
+ /// decreases the confirmation odds of the transaction package (which includes the commitment
+ /// and child anchor transactions), possibly resulting in a loss of funds. Once the transaction
+ /// is constructed, it must be fully signed for and broadcasted by the consumer of the event
+ /// along with the `commitment_tx` enclosed. Note that the `commitment_tx` must always be
+ /// broadcast first, as the child anchor transaction depends on it.
+ ///
+ /// The consumer should be able to sign for any of the additional inputs included within the
+ /// child anchor transaction. To sign its anchor input, an [`InMemorySigner`] should be
+ /// re-derived through [`KeysManager::derive_channel_keys`] with the help of
+ /// [`AnchorDescriptor::channel_keys_id`] and [`AnchorDescriptor::channel_value_satoshis`].
+ ///
+ /// It is possible to receive more than one instance of this event if a valid child anchor
+ /// transaction is never broadcast or is but not with a sufficient fee to be mined. Care should
+ /// be taken by the consumer of the event to ensure any future iterations of the child anchor
+ /// transaction adhere to the [Replace-By-Fee
+ /// rules](https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md)
+ /// for fee bumps to be accepted into the mempool, and eventually the chain. As the frequency of
+ /// these events is not user-controlled, users may ignore/drop the event if they are no longer
+ /// able to commit external confirmed funds to the child anchor transaction.
+ ///
+ /// The set of `pending_htlcs` on the commitment transaction to be broadcast can be inspected to
+ /// determine whether a significant portion of the channel's funds are allocated to HTLCs,
+ /// enabling users to make their own decisions regarding the importance of the commitment
+ /// transaction's confirmation. Note that this is not required, but simply exists as an option
+ /// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
+ /// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
+ /// be not urgent.
+ ///
+ /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
+ /// [`KeysManager::derive_channel_keys`]: crate::chain::keysinterface::KeysManager::derive_channel_keys
+ ChannelClose {
+ /// The target feerate that the transaction package, which consists of the commitment
+ /// transaction and the to-be-crafted child anchor transaction, must meet.
+ package_target_feerate_sat_per_1000_weight: u32,
+ /// The channel's commitment transaction to bump the fee of. This transaction should be
+ /// broadcast along with the anchor transaction constructed as a result of consuming this
+ /// event.
+ commitment_tx: Transaction,
+ /// The absolute fee in satoshis of the commitment transaction. This can be used along the
+ /// with weight of the commitment transaction to determine its feerate.
+ commitment_tx_fee_satoshis: u64,
+ /// The descriptor to sign the anchor input of the anchor transaction constructed as a
+ /// result of consuming this event.
+ anchor_descriptor: AnchorDescriptor,
+ /// The set of pending HTLCs on the commitment transaction that need to be resolved once the
+ /// commitment transaction confirms.
+ pending_htlcs: Vec<HTLCOutputInCommitment>,
+ },
+}
+
/// An Event which you should probably take some action in response to.
///
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
/// Destination of the HTLC that failed to be processed.
failed_next_destination: HTLCDestination,
},
+ #[cfg(anchors)]
+ /// Indicates that a transaction originating from LDK needs to have its fee bumped. This event
+ /// requires confirmed external funds to be readily available to spend.
+ ///
+ /// LDK does not currently generate this event. It is limited to the scope of channels with
+ /// anchor outputs, which will be introduced in a future release.
+ BumpTransaction(BumpTransactionEvent),
}
impl Writeable for Event {
(2, failed_next_destination, required),
})
},
+ #[cfg(anchors)]
+ &Event::BumpTransaction(ref event)=> {
+ 27u8.write(writer)?;
+ match event {
+ // We never write the ChannelClose events as they'll be replayed upon restarting
+ // anyway if the commitment transaction remains unconfirmed.
+ BumpTransactionEvent::ChannelClose { .. } => {}
+ }
+ }
// Note that, going forward, all new events must only write data inside of
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
// data via `write_tlv_fields`.
use bitcoin::secp256k1::PublicKey;
use routing::router::Route;
-use ln::chan_utils::HTLCType;
+use ln::chan_utils::HTLCClaim;
use util::logger::DebugBytes;
pub(crate) struct DebugPubKey<'a>(pub &'a PublicKey);
impl<'a> core::fmt::Display for DebugTx<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
if self.0.input.len() >= 1 && self.0.input.iter().any(|i| !i.witness.is_empty()) {
- if self.0.input.len() == 1 && self.0.input[0].witness.last().unwrap().len() == 71 &&
- (self.0.input[0].sequence.0 >> 8*3) as u8 == 0x80 {
+ let first_input = &self.0.input[0];
+ let witness_script_len = first_input.witness.last().unwrap_or(&[]).len();
+ if self.0.input.len() == 1 && witness_script_len == 71 &&
+ (first_input.sequence.0 >> 8*3) as u8 == 0x80 {
write!(f, "commitment tx ")?;
- } else if self.0.input.len() == 1 && self.0.input[0].witness.last().unwrap().len() == 71 {
+ } else if self.0.input.len() == 1 && witness_script_len == 71 {
write!(f, "closing tx ")?;
- } else if self.0.input.len() == 1 && HTLCType::scriptlen_to_htlctype(self.0.input[0].witness.last().unwrap().len()) == Some(HTLCType::OfferedHTLC) &&
- self.0.input[0].witness.len() == 5 {
+ } else if self.0.input.len() == 1 && HTLCClaim::from_witness(&first_input.witness) == Some(HTLCClaim::OfferedTimeout) {
write!(f, "HTLC-timeout tx ")?;
- } else if self.0.input.len() == 1 && HTLCType::scriptlen_to_htlctype(self.0.input[0].witness.last().unwrap().len()) == Some(HTLCType::AcceptedHTLC) &&
- self.0.input[0].witness.len() == 5 {
+ } else if self.0.input.len() == 1 && HTLCClaim::from_witness(&first_input.witness) == Some(HTLCClaim::AcceptedPreimage) {
write!(f, "HTLC-success tx ")?;
} else {
+ let mut num_preimage = 0;
+ let mut num_timeout = 0;
+ let mut num_revoked = 0;
for inp in &self.0.input {
- if !inp.witness.is_empty() {
- if HTLCType::scriptlen_to_htlctype(inp.witness.last().unwrap().len()) == Some(HTLCType::OfferedHTLC) { write!(f, "preimage-")?; break }
- else if HTLCType::scriptlen_to_htlctype(inp.witness.last().unwrap().len()) == Some(HTLCType::AcceptedHTLC) { write!(f, "timeout-")?; break }
+ let htlc_claim = HTLCClaim::from_witness(&inp.witness);
+ match htlc_claim {
+ Some(HTLCClaim::AcceptedPreimage)|Some(HTLCClaim::OfferedPreimage) => num_preimage += 1,
+ Some(HTLCClaim::AcceptedTimeout)|Some(HTLCClaim::OfferedTimeout) => num_timeout += 1,
+ Some(HTLCClaim::Revocation) => num_revoked += 1,
+ None => continue,
}
}
- write!(f, "tx ")?;
+ if num_preimage > 0 || num_timeout > 0 || num_revoked > 0 {
+ write!(f, "HTLC claim tx ({} preimage, {} timeout, {} revoked)",
+ num_preimage, num_timeout, num_revoked)?;
+ }
}
} else {
debug_assert!(false, "We should never generate unknown transaction types");
pub(crate) mod atomic_counter;
pub(crate) mod byte_utils;
pub(crate) mod chacha20;
-#[cfg(all(not(test), feature = "std"))]
+#[cfg(all(any(feature = "_bench_unstable", not(test)), feature = "std"))]
pub(crate) mod fairrwlock;
#[cfg(fuzzing)]
pub mod zbase32;
impl<ChannelSigner: Sign, K: KVStorePersister> Persist<ChannelSigner> for K {
// TODO: We really need a way for the persister to inform the user that its time to crash/shut
// down once these start returning failure.
- // A PermanentFailure implies we need to shut down since we're force-closing channels without
- // even broadcasting!
+ // A PermanentFailure implies we should probably just shut down the node since we're
+ // force-closing channels without even broadcasting!
- fn persist_new_channel(&self, funding_txo: OutPoint, monitor: &ChannelMonitor<ChannelSigner>, _update_id: MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn persist_new_channel(&self, funding_txo: OutPoint, monitor: &ChannelMonitor<ChannelSigner>, _update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
let key = format!("monitors/{}_{}", funding_txo.txid.to_hex(), funding_txo.index);
- self.persist(&key, monitor)
- .map_err(|_| chain::ChannelMonitorUpdateErr::PermanentFailure)
+ match self.persist(&key, monitor) {
+ Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
+ Err(_) => chain::ChannelMonitorUpdateStatus::PermanentFailure,
+ }
}
- fn update_persisted_channel(&self, funding_txo: OutPoint, _update: &Option<ChannelMonitorUpdate>, monitor: &ChannelMonitor<ChannelSigner>, _update_id: MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn update_persisted_channel(&self, funding_txo: OutPoint, _update: &Option<ChannelMonitorUpdate>, monitor: &ChannelMonitor<ChannelSigner>, _update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
let key = format!("monitors/{}_{}", funding_txo.txid.to_hex(), funding_txo.index);
- self.persist(&key, monitor)
- .map_err(|_| chain::ChannelMonitorUpdateErr::PermanentFailure)
+ match self.persist(&key, monitor) {
+ Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
+ Err(_) => chain::ChannelMonitorUpdateStatus::PermanentFailure,
+ }
}
}
pub const MAX_SCID_VOUT_INDEX: u64 = 0xffff;
/// A `short_channel_id` construction error
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Eq)]
pub enum ShortChannelIdError {
BlockOverflow,
TxIndexOverflow,
/// In TLV we occasionally send fields which only consist of, or potentially end with, a
/// variable-length integer which is simply truncated by skipping high zero bytes. This type
/// encapsulates such integers implementing Readable/Writeable for them.
-#[cfg_attr(test, derive(PartialEq, Debug))]
+#[cfg_attr(test, derive(PartialEq, Eq, Debug))]
pub(crate) struct HighZeroBytesDroppedBigSize<T>(pub T);
macro_rules! impl_writeable_primitive {
impl_array!(COMPACT_SIGNATURE_SIZE); // for Signature
impl_array!(1300); // for OnionPacket.hop_data
+impl Writeable for [u16; 8] {
+ #[inline]
+ fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+ for v in self.iter() {
+ w.write_all(&v.to_be_bytes())?
+ }
+ Ok(())
+ }
+}
+
+impl Readable for [u16; 8] {
+ #[inline]
+ fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+ let mut buf = [0u8; 16];
+ r.read_exact(&mut buf)?;
+ let mut res = [0u16; 8];
+ for (idx, v) in res.iter_mut().enumerate() {
+ *v = (buf[idx] as u16) << 8 | (buf[idx + 1] as u16)
+ }
+ Ok(res)
+ }
+}
+
// HashMap
impl<K, V> Writeable for HashMap<K, V>
where K: Writeable + Eq + Hash,
/// The character set consists of ASCII alphanumeric characters, hyphens, and periods.
/// Its length is guaranteed to be representable by a single byte.
/// This serialization is used by BOLT 7 hostnames.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Hostname(String);
impl Hostname {
/// Returns the length of the hostname.
use chain::channelmonitor::MonitorEvent;
use chain::transaction::OutPoint;
use chain::keysinterface;
+use ln::channelmanager;
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::{msgs, wire};
use ln::script::ShutdownScript;
}
}
impl<'a> chain::Watch<EnforcingSigner> for TestChainMonitor<'a> {
- fn watch_channel(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor<EnforcingSigner>) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn watch_channel(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor<EnforcingSigner>) -> chain::ChannelMonitorUpdateStatus {
// At every point where we get a monitor update, we should be able to send a useful monitor
// to a watchtower and disk...
let mut w = TestVecWriter(Vec::new());
self.chain_monitor.watch_channel(funding_txo, new_monitor)
}
- fn update_channel(&self, funding_txo: OutPoint, update: channelmonitor::ChannelMonitorUpdate) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn update_channel(&self, funding_txo: OutPoint, update: channelmonitor::ChannelMonitorUpdate) -> chain::ChannelMonitorUpdateStatus {
// Every monitor update should survive roundtrip
let mut w = TestVecWriter(Vec::new());
update.write(&mut w).unwrap();
}
pub struct TestPersister {
- pub update_ret: Mutex<Result<(), chain::ChannelMonitorUpdateErr>>,
+ pub update_ret: Mutex<chain::ChannelMonitorUpdateStatus>,
/// If this is set to Some(), after the next return, we'll always return this until update_ret
/// is changed:
- pub next_update_ret: Mutex<Option<Result<(), chain::ChannelMonitorUpdateErr>>>,
+ pub next_update_ret: Mutex<Option<chain::ChannelMonitorUpdateStatus>>,
/// When we get an update_persisted_channel call with no ChannelMonitorUpdate, we insert the
/// MonitorUpdateId here.
pub chain_sync_monitor_persistences: Mutex<HashMap<OutPoint, HashSet<MonitorUpdateId>>>,
impl TestPersister {
pub fn new() -> Self {
Self {
- update_ret: Mutex::new(Ok(())),
+ update_ret: Mutex::new(chain::ChannelMonitorUpdateStatus::Completed),
next_update_ret: Mutex::new(None),
chain_sync_monitor_persistences: Mutex::new(HashMap::new()),
offchain_monitor_updates: Mutex::new(HashMap::new()),
}
}
- pub fn set_update_ret(&self, ret: Result<(), chain::ChannelMonitorUpdateErr>) {
+ pub fn set_update_ret(&self, ret: chain::ChannelMonitorUpdateStatus) {
*self.update_ret.lock().unwrap() = ret;
}
- pub fn set_next_update_ret(&self, next_ret: Option<Result<(), chain::ChannelMonitorUpdateErr>>) {
+ pub fn set_next_update_ret(&self, next_ret: Option<chain::ChannelMonitorUpdateStatus>) {
*self.next_update_ret.lock().unwrap() = next_ret;
}
}
impl<Signer: keysinterface::Sign> chainmonitor::Persist<Signer> for TestPersister {
- fn persist_new_channel(&self, _funding_txo: OutPoint, _data: &channelmonitor::ChannelMonitor<Signer>, _id: MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn persist_new_channel(&self, _funding_txo: OutPoint, _data: &channelmonitor::ChannelMonitor<Signer>, _id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
let ret = self.update_ret.lock().unwrap().clone();
if let Some(next_ret) = self.next_update_ret.lock().unwrap().take() {
*self.update_ret.lock().unwrap() = next_ret;
ret
}
- fn update_persisted_channel(&self, funding_txo: OutPoint, update: &Option<channelmonitor::ChannelMonitorUpdate>, _data: &channelmonitor::ChannelMonitor<Signer>, update_id: MonitorUpdateId) -> Result<(), chain::ChannelMonitorUpdateErr> {
+ fn update_persisted_channel(&self, funding_txo: OutPoint, update: &Option<channelmonitor::ChannelMonitorUpdate>, _data: &channelmonitor::ChannelMonitor<Signer>, update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
let ret = self.update_ret.lock().unwrap().clone();
if let Some(next_ret) = self.next_update_ret.lock().unwrap().take() {
*self.update_ret.lock().unwrap() = next_ret;
self.received_msg(wire::Message::ChannelReestablish(msg.clone()));
}
fn peer_disconnected(&self, _their_node_id: &PublicKey, _no_connection_possible: bool) {}
- fn peer_connected(&self, _their_node_id: &PublicKey, _msg: &msgs::Init) {
+ fn peer_connected(&self, _their_node_id: &PublicKey, _msg: &msgs::Init) -> Result<(), ()> {
// Don't bother with `received_msg` for Init as its auto-generated and we don't want to
// bother re-generating the expected Init message in all tests.
+ Ok(())
}
fn handle_error(&self, _their_node_id: &PublicKey, msg: &msgs::ErrorMessage) {
self.received_msg(wire::Message::Error(msg.clone()));
}
fn provided_node_features(&self) -> NodeFeatures {
- NodeFeatures::known_channel_features()
+ channelmanager::provided_node_features()
}
fn provided_init_features(&self, _their_init_features: &PublicKey) -> InitFeatures {
- InitFeatures::known_channel_features()
+ channelmanager::provided_init_features()
}
}
let node_1_btckey = SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = SecretKey::from_slice(&[39; 32]).unwrap();
let unsigned_ann = msgs::UnsignedChannelAnnouncement {
- features: ChannelFeatures::known(),
+ features: ChannelFeatures::empty(),
chain_hash: genesis_block(network).header.block_hash(),
short_channel_id: short_chan_id,
node_id_1: PublicKey::from_secret_key(&secp_ctx, &node_1_privkey),
None
}
- fn peer_connected(&self, their_node_id: &PublicKey, init_msg: &msgs::Init) {
+ fn peer_connected(&self, their_node_id: &PublicKey, init_msg: &msgs::Init) -> Result<(), ()> {
if !init_msg.features.supports_gossip_queries() {
- return ();
+ return Ok(());
}
#[allow(unused_mut, unused_assignments)]
timestamp_range: u32::max_value(),
},
});
+ Ok(())
}
fn handle_reply_channel_range(&self, _their_node_id: &PublicKey, _msg: msgs::ReplyChannelRange) -> Result<(), msgs::LightningError> {
Future {
state: Arc::new(Mutex::new(FutureState {
callbacks: Vec::new(),
- complete: false,
+ complete: true,
}))
}
} else if let Some(existing_state) = &lock.1 {
impl Future {
/// Registers a callback to be called upon completion of this future. If the future has already
/// completed, the callback will be called immediately.
+ ///
+ /// (C-not exported) use the bindings-only `register_callback_fn` instead
pub fn register_callback(&self, callback: Box<dyn FutureCallback>) {
let mut state = self.state.lock().unwrap();
if state.complete {
state.callbacks.push(callback);
}
}
+
+ // C bindings don't (currently) know how to map `Box<dyn Trait>`, and while it could add the
+ // following wrapper, doing it in the bindings is currently much more work than simply doing it
+ // here.
+ /// Registers a callback to be called upon completion of this future. If the future has already
+ /// completed, the callback will be called immediately.
+ #[cfg(c_bindings)]
+ pub fn register_callback_fn<F: 'static + FutureCallback>(&self, callback: F) {
+ self.register_callback(Box::new(callback));
+ }
}
mod std_future {
use core::future::Future as FutureTrait;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+ #[test]
+ fn notifier_pre_notified_future() {
+ // Previously, if we generated a future after a `Notifier` had been notified, the future
+ // would never complete. This tests this behavior, ensuring the future instead completes
+ // immediately.
+ let notifier = Notifier::new();
+ notifier.notify();
+
+ let callback = Arc::new(AtomicBool::new(false));
+ let callback_ref = Arc::clone(&callback);
+ notifier.get_future().register_callback(Box::new(move || assert!(!callback_ref.fetch_or(true, Ordering::SeqCst))));
+ assert!(callback.load(Ordering::SeqCst));
+ }
+
#[cfg(feature = "std")]
#[test]
fn test_wait_timeout() {
edition = "2018"
[features]
-default = ["lightning/no-std", "lightning-invoice/no-std"]
+default = ["lightning/no-std", "lightning-invoice/no-std", "lightning-rapid-gossip-sync/no-std"]
[dependencies]
lightning = { path = "../lightning", default-features = false }
lightning-invoice = { path = "../lightning-invoice", default-features = false }
+lightning-rapid-gossip-sync = { path = "../lightning-rapid-gossip-sync", default-features = false }
--- /dev/null
+disable_all_formatting = true
\ No newline at end of file