From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Sat, 20 May 2023 22:55:43 +0000 (+0000) Subject: Merge pull request #2226 from alecchendev/2023-04-persist-network-graph-on-rgs X-Git-Tag: v0.0.116-alpha1~34 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=6aca7e1c4db17f43b79504fd44b942b4bc08db9d;hp=2afbdf5d1c1b531b08950ddca9143450ba458245;p=rust-lightning Merge pull request #2226 from alecchendev/2023-04-persist-network-graph-on-rgs Update BP `NetworkGraph` and `Scorer` persist frequency --- diff --git a/.gitignore b/.gitignore index 7a889b5b8..28e55b41c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ Cargo.lock lightning/target lightning/ldk-net_graph-*.bin lightning-custom-message/target +lightning-transaction-sync/target no-std-check/target diff --git a/CHANGELOG.md b/CHANGELOG.md index d8475c003..2874f33db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,100 @@ +# 0.0.115 - Apr 24, 2023 - "Rebroadcast the Bugfixes" + +## API Updates + * The MSRV of the main LDK crates has been increased to 1.48 (#2107). + * Attempting to claim an un-expired payment on a channel which has closed no + longer fails. The expiry time of payments is exposed via + `PaymentClaimable::claim_deadline` (#2148). + * `payment_metadata` is now supported in `Invoice` deserialization, sending, + and receiving (via a new `RecipientOnionFields` struct) (#2139, #2127). + * `Event::PaymentFailed` now exposes a failure reason (#2142). + * BOLT12 messages now support stateless generation and validation (#1989). + * The `NetworkGraph` is now pruned of stale data after RGS processing (#2161). + * Max inbound HTLCs in-flight can be changed in the handshake config (#2138). + * `lightning-transaction-sync` feature `esplora-async-https` was added (#2085). + * A `ChannelPending` event is now emitted after the initial handshake (#2098). + * `PaymentForwarded::outbound_amount_forwarded_msat` was added (#2136). + * `ChannelManager::list_channels_by_counterparty` was added (#2079). + * `ChannelDetails::feerate_sat_per_1000_weight` was added (#2094). + * `Invoice::fallback_addresses` was added to fetch `bitcoin` types (#2023). + * The offer/refund description is now exposed in `Invoice{,Request}` (#2206). + +## Backwards Compatibility + * Payments sent with the legacy `*_with_route` methods on LDK 0.0.115+ will no + longer be retryable via the LDK 0.0.114- `retry_payment` method (#2139). + * `Event::PaymentPathFailed::retry` was removed and will always be `None` for + payments initiated on 0.0.115 which fail on an earlier version (#2063). + * `Route`s and `PaymentParameters` with blinded path information will not be + readable on prior versions of LDK. Such objects are not currently constructed + by LDK, but may be when processing BOLT12 data in a coming release (#2146). + * Providing `ChannelMonitorUpdate`s generated by LDK 0.0.115 to a + `ChannelMonitor` on 0.0.114 or before may panic (#2059). Note that this is + in general unsupported, and included here only for completeness. + +## Bug Fixes + * Fixed a case where `process_events_async` may `poll` a `Future` which has + already completed (#2081). + * Fixed deserialization of `u16` arrays. This bug may have previously corrupted + the historical buckets in a `ProbabilisticScorer`. Users relying on the + historical buckets may wish to wipe their scorer on upgrade to remove corrupt + data rather than waiting on it to decay (#2191). + * The `process_events_async` task is now `Send` and can thus be polled on a + multi-threaded runtime (#2199). + * Fixed a missing macro export causing + `impl_writeable_tlv_based_enum{,_upgradable}` calls to not compile (#2091). + * Fixed compilation of `lightning-invoice` with both `no-std` and serde (#2187) + * Fix an issue where the `background-processor` would not wake when a + `ChannelMonitorUpdate` completed asynchronously, causing delays (#2090). + * Fix an issue where `process_events_async` would exit immediately (#2145). + * `Router` calls from the `ChannelManager` now call `find_route_with_id` rather + than `find_route`, as was intended and described in the API (#2092). + * Ensure `process_events_async` always exits if any sleep future returns true, + not just if all sleep futures repeatedly return true (#2145). + * `channel_update` messages no longer set the disable bit unless the peer has + been disconnected for some time. This should resolve cases where channels are + disabled for extended periods of time (#2198). + * We no longer remove CLN nodes from the network graph for violating the BOLT + spec in some cases after failing to pay through them (#2220). + * Fixed a debug assertion which may panic under heavy load (#2172). + * `CounterpartyForceClosed::peer_msg` is now wrapped in UntrustedString (#2114) + * Fixed a potential deadlock in `funding_transaction_generated` (#2158). + +## Security + * Transaction re-broadcasting is now substantially more aggressive, including a + new regular rebroadcast feature called on a timer from the + `background-processor` or from `ChainMonitor::rebroadcast_pending_claims`. + This should substantially increase transaction confirmation reliability + without relying on downstream `TransactionBroadcaster` implementations for + rebroadcasting (#2203, #2205, #2208). + * Implemented the changes from BOLT PRs #1031, #1032, and #1040 which resolve a + privacy vulnerability which allows an intermediate node on the path to + discover the final destination for a payment (#2062). + +In total, this release features 110 files changed, 11928 insertions, 6368 +deletions in 215 commits from 21 authors, in alphabetical order: + * Advait + * Alan Cohen + * Alec Chen + * Allan Douglas R. de Oliveira + * Arik Sosman + * Elias Rohrer + * Evan Feenstra + * Jeffrey Czyz + * John Cantrell + * Lucas Soriano del Pino + * Marc Tyndel + * Matt Corallo + * Paul Miller + * Steven + * Steven Williamson + * Steven Zhao + * Tony Giorgio + * Valentine Wallace + * Wilmer Paulino + * benthecarman + * munjesi + + # 0.0.114 - Mar 3, 2023 - "Faster Async BOLT12 Retries" ## API Updates diff --git a/fuzz/src/bin/gen_target.sh b/fuzz/src/bin/gen_target.sh index d7928188d..34cae5107 100755 --- a/fuzz/src/bin/gen_target.sh +++ b/fuzz/src/bin/gen_target.sh @@ -56,3 +56,15 @@ GEN_TEST msg_ping msg_targets:: GEN_TEST msg_pong msg_targets:: GEN_TEST msg_channel_details msg_targets:: + +GEN_TEST msg_open_channel_v2 msg_targets:: +GEN_TEST msg_accept_channel_v2 msg_targets:: +GEN_TEST msg_tx_add_input msg_targets:: +GEN_TEST msg_tx_add_output msg_targets:: +GEN_TEST msg_tx_remove_input msg_targets:: +GEN_TEST msg_tx_remove_output msg_targets:: +GEN_TEST msg_tx_complete msg_targets:: +GEN_TEST msg_tx_signatures msg_targets:: +GEN_TEST msg_tx_init_rbf msg_targets:: +GEN_TEST msg_tx_ack_rbf msg_targets:: +GEN_TEST msg_tx_abort msg_targets:: diff --git a/fuzz/src/bin/msg_accept_channel_v2_target.rs b/fuzz/src/bin/msg_accept_channel_v2_target.rs new file mode 100644 index 000000000..354a5a8c4 --- /dev/null +++ b/fuzz/src/bin/msg_accept_channel_v2_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_accept_channel_v2::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_accept_channel_v2_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_accept_channel_v2_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_accept_channel_v2_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_accept_channel_v2_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_accept_channel_v2_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_accept_channel_v2") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_accept_channel_v2_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_open_channel_v2_target.rs b/fuzz/src/bin/msg_open_channel_v2_target.rs new file mode 100644 index 000000000..c7949bf9d --- /dev/null +++ b/fuzz/src/bin/msg_open_channel_v2_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_open_channel_v2::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_open_channel_v2_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_open_channel_v2_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_open_channel_v2_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_open_channel_v2_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_open_channel_v2_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_open_channel_v2") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_open_channel_v2_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_abort_target.rs b/fuzz/src/bin/msg_tx_abort_target.rs new file mode 100644 index 000000000..66783563a --- /dev/null +++ b/fuzz/src/bin/msg_tx_abort_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_abort::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_abort_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_abort_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_abort_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_abort_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_abort_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_abort") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_abort_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_ack_rbf_target.rs b/fuzz/src/bin/msg_tx_ack_rbf_target.rs new file mode 100644 index 000000000..2e6aaedc2 --- /dev/null +++ b/fuzz/src/bin/msg_tx_ack_rbf_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_ack_rbf::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_ack_rbf_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_ack_rbf_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_ack_rbf_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_ack_rbf_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_ack_rbf_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_ack_rbf") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_ack_rbf_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_add_input_target.rs b/fuzz/src/bin/msg_tx_add_input_target.rs new file mode 100644 index 000000000..1da8bbd93 --- /dev/null +++ b/fuzz/src/bin/msg_tx_add_input_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_add_input::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_add_input_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_add_input_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_add_input_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_add_input_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_add_input_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_add_input") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_add_input_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_add_output_target.rs b/fuzz/src/bin/msg_tx_add_output_target.rs new file mode 100644 index 000000000..a06d51aad --- /dev/null +++ b/fuzz/src/bin/msg_tx_add_output_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_add_output::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_add_output_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_add_output_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_add_output_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_add_output_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_add_output_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_add_output") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_add_output_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_complete_target.rs b/fuzz/src/bin/msg_tx_complete_target.rs new file mode 100644 index 000000000..5bb2f855a --- /dev/null +++ b/fuzz/src/bin/msg_tx_complete_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_complete::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_complete_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_complete_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_complete_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_complete_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_complete_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_complete") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_complete_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_init_rbf_target.rs b/fuzz/src/bin/msg_tx_init_rbf_target.rs new file mode 100644 index 000000000..74556abb1 --- /dev/null +++ b/fuzz/src/bin/msg_tx_init_rbf_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_init_rbf::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_init_rbf_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_init_rbf_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_init_rbf_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_init_rbf_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_init_rbf_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_init_rbf") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_init_rbf_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_remove_input_target.rs b/fuzz/src/bin/msg_tx_remove_input_target.rs new file mode 100644 index 000000000..d6b9cff28 --- /dev/null +++ b/fuzz/src/bin/msg_tx_remove_input_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_remove_input::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_remove_input_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_remove_input_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_remove_input_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_remove_input_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_remove_input_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_remove_input") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_remove_input_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_remove_output_target.rs b/fuzz/src/bin/msg_tx_remove_output_target.rs new file mode 100644 index 000000000..2c6b17d81 --- /dev/null +++ b/fuzz/src/bin/msg_tx_remove_output_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_remove_output::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_remove_output_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_remove_output_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_remove_output_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_remove_output_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_remove_output_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_remove_output") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_remove_output_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/bin/msg_tx_signatures_target.rs b/fuzz/src/bin/msg_tx_signatures_target.rs new file mode 100644 index 000000000..ee650ec2b --- /dev/null +++ b/fuzz/src/bin/msg_tx_signatures_target.rs @@ -0,0 +1,113 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on target_template.txt +// To modify it, modify target_template.txt and run gen_target.sh instead. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate lightning_fuzz; +use lightning_fuzz::msg_targets::msg_tx_signatures::*; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + msg_tx_signatures_run(data.as_ptr(), data.len()); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + msg_tx_signatures_run(data.as_ptr(), data.len()); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + msg_tx_signatures_run(data.as_ptr(), data.len()); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + msg_tx_signatures_run(data.as_ptr(), data.len()); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + use lightning_fuzz::utils::test_logger::StringBuffer; + + use std::sync::{atomic, Arc}; + { + let data: Vec = vec![0]; + msg_tx_signatures_run(data.as_ptr(), data.len()); + } + let mut threads = Vec::new(); + let threads_running = Arc::new(atomic::AtomicUsize::new(0)); + if let Ok(tests) = fs::read_dir("test_cases/msg_tx_signatures") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + threads_running.fetch_add(1, atomic::Ordering::AcqRel); + + let thread_count_ref = Arc::clone(&threads_running); + let main_thread_ref = std::thread::current(); + threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), + std::thread::spawn(move || { + let string_logger = StringBuffer::new(); + + let panic_logger = string_logger.clone(); + let res = if ::std::panic::catch_unwind(move || { + msg_tx_signatures_test(&data, panic_logger); + }).is_err() { + Some(string_logger.into_string()) + } else { None }; + thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); + main_thread_ref.unpark(); + res + }) + )); + while threads_running.load(atomic::Ordering::Acquire) > 32 { + std::thread::park(); + } + } + } + let mut failed_outputs = Vec::new(); + for (test, thread) in threads.drain(..) { + if let Some(output) = thread.join().unwrap() { + println!("\nOutput of {}:\n{}\n", test, output); + failed_outputs.push(test); + } + } + if !failed_outputs.is_empty() { + println!("Test cases which failed: "); + for case in failed_outputs { + println!("{}", case); + } + panic!(); + } +} diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 0461c7577..7d507fa43 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -18,8 +18,6 @@ //! send-side handling is correct, other peers. We consider it a failure if any action results in a //! channel being force-closed. -use bitcoin::TxMerkleNode; -use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::blockdata::script::{Builder, Script}; @@ -37,7 +35,7 @@ use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, chainmonitor, chan use lightning::chain::channelmonitor::{ChannelMonitor, MonitorEvent}; use lightning::chain::transaction::OutPoint; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; -use lightning::chain::keysinterface::{KeyMaterial, InMemorySigner, Recipient, EntropySource, NodeSigner, SignerProvider}; +use lightning::sign::{KeyMaterial, InMemorySigner, Recipient, EntropySource, NodeSigner, SignerProvider}; use lightning::events; use lightning::events::MessageSendEventsProvider; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; @@ -45,6 +43,7 @@ use lightning::ln::channelmanager::{ChainParameters, ChannelDetails, ChannelMana use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE; use lightning::ln::msgs::{self, CommitmentUpdate, ChannelMessageHandler, DecodeError, UpdateAddHTLC, Init}; use lightning::ln::script::ShutdownScript; +use lightning::ln::functional_test_utils::*; use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState}; use lightning::util::errors::APIError; use lightning::util::logger::Logger; @@ -259,18 +258,18 @@ impl SignerProvider for KeyProvider { }) } - fn get_destination_script(&self) -> Script { + fn get_destination_script(&self) -> Result { let secp_ctx = Secp256k1::signing_only(); let channel_monitor_claim_key = SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, self.node_secret[31]]).unwrap(); let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() + Ok(Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()) } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + fn get_shutdown_scriptpubkey(&self) -> Result { let secp_ctx = Secp256k1::signing_only(); let secret_key = SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, self.node_secret[31]]).unwrap(); let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); - ShutdownScript::new_p2wpkh(&pubkey_hash) + Ok(ShutdownScript::new_p2wpkh(&pubkey_hash)) } } @@ -547,11 +546,11 @@ pub fn do_test(data: &[u8], underlying_out: Out) { macro_rules! confirm_txn { ($node: expr) => { { let chain_hash = genesis_block(Network::Bitcoin).block_hash(); - let mut header = BlockHeader { version: 0x20000000, prev_blockhash: chain_hash, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; + let mut header = create_dummy_header(chain_hash, 42); let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect(); $node.transactions_confirmed(&header, &txdata, 1); for _ in 2..100 { - header = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; + header = create_dummy_header(header.block_hash(), 42); } $node.best_block_updated(&header, 99); } } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 876a412da..5544dbded 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -13,8 +13,6 @@ //! or payments to send/ways to handle events generated. //! This test has been very useful, though due to its complexity good starting inputs are critical. -use bitcoin::TxMerkleNode; -use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::blockdata::script::{Builder, Script}; @@ -34,13 +32,14 @@ use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen}; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::chain::chainmonitor; use lightning::chain::transaction::OutPoint; -use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider}; +use lightning::sign::{InMemorySigner, Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider}; use lightning::events::Event; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::ln::channelmanager::{ChainParameters, ChannelDetails, ChannelManager, PaymentId, RecipientOnionFields, Retry}; use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,IgnoringMessageHandler}; use lightning::ln::msgs::{self, DecodeError}; use lightning::ln::script::ShutdownScript; +use lightning::ln::functional_test_utils::*; use lightning::routing::gossip::{P2PGossipSync, NetworkGraph}; use lightning::routing::utxo::UtxoLookup; use lightning::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router}; @@ -48,7 +47,7 @@ use lightning::util::config::UserConfig; use lightning::util::errors::APIError; use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState}; use lightning::util::logger::Logger; -use lightning::util::ser::{Readable, ReadableArgs, Writeable}; +use lightning::util::ser::{ReadableArgs, Writeable}; use crate::utils::test_logger; use crate::utils::test_persister::TestPersister; @@ -228,7 +227,7 @@ impl<'a> MoneyLossDetector<'a> { } self.blocks_connected += 1; - let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height].0, merkle_root: TxMerkleNode::all_zeros(), time: self.blocks_connected, bits: 42, nonce: 42 }; + let header = create_dummy_header(self.header_hashes[self.height].0, self.blocks_connected); self.height += 1; self.manager.transactions_confirmed(&header, &txdata, self.height as u32); self.manager.best_block_updated(&header, self.height as u32); @@ -245,7 +244,7 @@ impl<'a> MoneyLossDetector<'a> { fn disconnect_block(&mut self) { if self.height > 0 && (self.max_height < 6 || self.height >= self.max_height - 6) { - let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height - 1].0, merkle_root: TxMerkleNode::all_zeros(), time: self.header_hashes[self.height].1, bits: 42, nonce: 42 }; + let header = create_dummy_header(self.header_hashes[self.height - 1].0, self.header_hashes[self.height].1); self.manager.block_disconnected(&header, self.height as u32); self.monitor.block_disconnected(&header, self.height as u32); self.height -= 1; @@ -376,18 +375,18 @@ impl SignerProvider for KeyProvider { )) } - fn get_destination_script(&self) -> Script { + fn get_destination_script(&self) -> Result { let secp_ctx = Secp256k1::signing_only(); let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() + Ok(Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()) } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + fn get_shutdown_scriptpubkey(&self) -> Result { let secp_ctx = Secp256k1::signing_only(); let secret_key = SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]).unwrap(); let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); - ShutdownScript::new_p2wpkh(&pubkey_hash) + Ok(ShutdownScript::new_p2wpkh(&pubkey_hash)) } } @@ -458,7 +457,8 @@ pub fn do_test(data: &[u8], logger: &Arc) { chan_handler: channelmanager.clone(), route_handler: gossip_sync.clone(), onion_message_handler: IgnoringMessageHandler {}, - }, 0, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], Arc::clone(&logger), IgnoringMessageHandler{}, keys_manager.clone())); + custom_message_handler: IgnoringMessageHandler {}, + }, 0, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], Arc::clone(&logger), keys_manager.clone())); let mut should_forward = false; let mut payments_received: Vec = Vec::new(); @@ -751,16 +751,16 @@ mod tests { // 00 030000000000000000000000000000000000000000000000000000000000000002 03000000000000000000000000000000 - noise act two (0||pubkey||mac) // // 030012 - inbound read from peer id 0 of len 18 - // 000a 03000000000000000000000000000000 - message header indicating message length 10 - // 03001a - inbound read from peer id 0 of len 26 - // 0010 00022000 00022000 03000000000000000000000000000000 - init message (type 16) with static_remotekey (0x2000) and mac + // 0010 03000000000000000000000000000000 - message header indicating message length 16 + // 030020 - inbound read from peer id 0 of len 32 + // 0010 00021aaa 0008aaaaaaaaaaaa9aaa 03000000000000000000000000000000 - init message (type 16) with static_remotekey required and other bits optional and mac // // 030012 - inbound read from peer id 0 of len 18 - // 0141 03000000000000000000000000000000 - message header indicating message length 321 + // 0147 03000000000000000000000000000000 - message header indicating message length 327 // 0300fe - inbound read from peer id 0 of len 254 // 0020 7500000000000000000000000000000000000000000000000000000000000000 ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679 000000000000c350 0000000000000000 0000000000000162 ffffffffffffffff 0000000000000222 0000000000000000 000000fd 0006 01e3 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 030000000000000000000000000000000000000000000000000000000000000004 - beginning of open_channel message - // 030053 - inbound read from peer id 0 of len 83 - // 030000000000000000000000000000000000000000000000000000000000000005 020900000000000000000000000000000000000000000000000000000000000000 01 03000000000000000000000000000000 - rest of open_channel and mac + // 030059 - inbound read from peer id 0 of len 89 + // 030000000000000000000000000000000000000000000000000000000000000005 020900000000000000000000000000000000000000000000000000000000000000 01 0000 01021000 03000000000000000000000000000000 - rest of open_channel and mac // // 00fd00fd - Two feerate requests (all returning min feerate, which our open_channel also uses) (gonna be ingested by FuzzEstimator) // - client should now respond with accept_channel (CHECK 1: type 33 to peer 03000000) @@ -799,19 +799,19 @@ mod tests { // 000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000 - inbound noise act 3 // // 030112 - inbound read from peer id 1 of len 18 - // 000a 01000000000000000000000000000000 - message header indicating message length 10 - // 03011a - inbound read from peer id 1 of len 26 - // 0010 00022000 00022000 01000000000000000000000000000000 - init message (type 16) with static_remotekey (0x2000) and mac + // 0010 01000000000000000000000000000000 - message header indicating message length 16 + // 030120 - inbound read from peer id 1 of len 32 + // 0010 00021aaa 0008aaaaaaaaaaaa9aaa 01000000000000000000000000000000 - init message (type 16) with static_remotekey required and other bits optional and mac // // 05 01 030200000000000000000000000000000000000000000000000000000000000000 00c350 0003e8 - create outbound channel to peer 1 for 50k sat // 00fd - One feerate requests (all returning min feerate) (gonna be ingested by FuzzEstimator) // // 030112 - inbound read from peer id 1 of len 18 - // 0110 01000000000000000000000000000000 - message header indicating message length 272 + // 0112 01000000000000000000000000000000 - message header indicating message length 274 // 0301ff - inbound read from peer id 1 of len 255 // 0021 0000000000000000000000000000000000000000000000000000000000000e05 0000000000000162 00000000004c4b40 00000000000003e8 00000000000003e8 00000002 03f0 0005 030000000000000000000000000000000000000000000000000000000000000100 030000000000000000000000000000000000000000000000000000000000000200 030000000000000000000000000000000000000000000000000000000000000300 030000000000000000000000000000000000000000000000000000000000000400 030000000000000000000000000000000000000000000000000000000000000500 02660000000000000000000000000000 - beginning of accept_channel - // 030121 - inbound read from peer id 1 of len 33 - // 0000000000000000000000000000000000 01000000000000000000000000000000 - rest of accept_channel and mac + // 030123 - inbound read from peer id 1 of len 35 + // 0000000000000000000000000000000000 0000 01000000000000000000000000000000 - rest of accept_channel and mac // // 0a - create the funding transaction (client should send funding_created now) // @@ -1005,7 +1005,7 @@ mod tests { // - client now fails the HTLC backwards as it was unable to extract the payment preimage (CHECK 9 duplicate and CHECK 10) let logger = Arc::new(TrackingLogger { lines: Mutex::new(HashMap::new()) }); - super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012000a0300000000000000000000000000000003001a00100002200000022000030000000000000000000000000000000300120141030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000162ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030053030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112000a0100000000000000000000000000000003011a0010000220000002200001000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120110010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000016200000000004c4b4000000000000003e800000000000003e80000000203f00005030000000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000200030000000000000000000000000000000000000000000000000000000000000300030000000000000000000000000000000000000000000000000000000000000400030000000000000000000000000000000000000000000000000000000000000500026600000000000000000000000000000301210000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005551202030927c00401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff53000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c00000000000001600142800000000000000000000000000000000000000050000200c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc)); + super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012001003000000000000000000000000000000030020001000021aaa0008aaaaaaaaaaaa9aaa030000000000000000000000000000000300120147030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000162ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030059030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010000010210000300000000000000000000000000000000fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112001001000000000000000000000000000000030120001000021aaa0008aaaaaaaaaaaa9aaa01000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120112010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000016200000000004c4b4000000000000003e800000000000003e80000000203f000050300000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000002000300000000000000000000000000000000000000000000000000000000000003000300000000000000000000000000000000000000000000000000000000000004000300000000000000000000000000000000000000000000000000000000000005000266000000000000000000000000000003012300000000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005551202030927c00401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff53000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c00000000000001600142800000000000000000000000000000000000000050000200c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc)); let log_entries = logger.lines.lock().unwrap(); assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1 diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index e88588489..394d57fce 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -11,7 +11,7 @@ use bitcoin::secp256k1::{KeyPair, Parity, PublicKey, Secp256k1, SecretKey, self} use crate::utils::test_logger; use core::convert::{Infallible, TryFrom}; use lightning::blinded_path::BlindedPath; -use lightning::chain::keysinterface::EntropySource; +use lightning::sign::EntropySource; use lightning::ln::PaymentHash; use lightning::ln::features::BlindedHopFeatures; use lightning::offers::invoice::{BlindedPayInfo, UnsignedInvoice}; diff --git a/fuzz/src/msg_targets/gen_target.sh b/fuzz/src/msg_targets/gen_target.sh index 753a98325..3937c5001 100755 --- a/fuzz/src/msg_targets/gen_target.sh +++ b/fuzz/src/msg_targets/gen_target.sh @@ -33,8 +33,8 @@ GEN_TEST lightning::ln::msgs::UpdateFailHTLC test_msg_simple "" GEN_TEST lightning::ln::msgs::UpdateFailMalformedHTLC test_msg_simple "" GEN_TEST lightning::ln::msgs::UpdateFee test_msg_simple "" GEN_TEST lightning::ln::msgs::UpdateFulfillHTLC test_msg_simple "" +GEN_TEST lightning::ln::msgs::ChannelReestablish test_msg_simple "" -GEN_TEST lightning::ln::msgs::ChannelReestablish test_msg "" GEN_TEST lightning::ln::msgs::DecodedOnionErrorPacket test_msg "" GEN_TEST lightning::ln::msgs::ChannelAnnouncement test_msg_exact "" @@ -47,3 +47,15 @@ GEN_TEST lightning::ln::msgs::WarningMessage test_msg_hole ", 32, 2" GEN_TEST lightning::ln::msgs::ChannelUpdate test_msg_hole ", 108, 1" GEN_TEST lightning::ln::channelmanager::ChannelDetails test_msg_simple "" + +GEN_TEST lightning::ln::msgs::OpenChannelV2 test_msg_simple "" +GEN_TEST lightning::ln::msgs::AcceptChannelV2 test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxAddInput test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxAddOutput test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxRemoveInput test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxRemoveOutput test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxComplete test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxSignatures test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxInitRbf test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxAckRbf test_msg_simple "" +GEN_TEST lightning::ln::msgs::TxAbort test_msg_simple "" diff --git a/fuzz/src/msg_targets/mod.rs b/fuzz/src/msg_targets/mod.rs index 67d66e23f..fe3bd14a7 100644 --- a/fuzz/src/msg_targets/mod.rs +++ b/fuzz/src/msg_targets/mod.rs @@ -31,3 +31,14 @@ pub mod msg_error_message; pub mod msg_warning_message; pub mod msg_channel_update; pub mod msg_channel_details; +pub mod msg_open_channel_v2; +pub mod msg_accept_channel_v2; +pub mod msg_tx_add_input; +pub mod msg_tx_add_output; +pub mod msg_tx_remove_input; +pub mod msg_tx_remove_output; +pub mod msg_tx_complete; +pub mod msg_tx_signatures; +pub mod msg_tx_init_rbf; +pub mod msg_tx_ack_rbf; +pub mod msg_tx_abort; diff --git a/fuzz/src/msg_targets/msg_accept_channel_v2.rs b/fuzz/src/msg_targets/msg_accept_channel_v2.rs new file mode 100644 index 000000000..36b646644 --- /dev/null +++ b/fuzz/src/msg_targets/msg_accept_channel_v2.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_accept_channel_v2_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::AcceptChannelV2, data); +} + +#[no_mangle] +pub extern "C" fn msg_accept_channel_v2_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::AcceptChannelV2, data); +} diff --git a/fuzz/src/msg_targets/msg_channel_reestablish.rs b/fuzz/src/msg_targets/msg_channel_reestablish.rs index 085755580..fdc2d1fa6 100644 --- a/fuzz/src/msg_targets/msg_channel_reestablish.rs +++ b/fuzz/src/msg_targets/msg_channel_reestablish.rs @@ -15,11 +15,11 @@ use crate::utils::test_logger; #[inline] pub fn msg_channel_reestablish_test(data: &[u8], _out: Out) { - test_msg!(lightning::ln::msgs::ChannelReestablish, data); + test_msg_simple!(lightning::ln::msgs::ChannelReestablish, data); } #[no_mangle] pub extern "C" fn msg_channel_reestablish_run(data: *const u8, datalen: usize) { let data = unsafe { std::slice::from_raw_parts(data, datalen) }; - test_msg!(lightning::ln::msgs::ChannelReestablish, data); + test_msg_simple!(lightning::ln::msgs::ChannelReestablish, data); } diff --git a/fuzz/src/msg_targets/msg_open_channel_v2.rs b/fuzz/src/msg_targets/msg_open_channel_v2.rs new file mode 100644 index 000000000..4f6457a3e --- /dev/null +++ b/fuzz/src/msg_targets/msg_open_channel_v2.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_open_channel_v2_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::OpenChannelV2, data); +} + +#[no_mangle] +pub extern "C" fn msg_open_channel_v2_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::OpenChannelV2, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_abort.rs b/fuzz/src/msg_targets/msg_tx_abort.rs new file mode 100644 index 000000000..c361b6546 --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_abort.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_abort_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxAbort, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_abort_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxAbort, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_ack_rbf.rs b/fuzz/src/msg_targets/msg_tx_ack_rbf.rs new file mode 100644 index 000000000..9931bfcfb --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_ack_rbf.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_ack_rbf_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxAckRbf, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_ack_rbf_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxAckRbf, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_add_input.rs b/fuzz/src/msg_targets/msg_tx_add_input.rs new file mode 100644 index 000000000..f212b59cd --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_add_input.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_add_input_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxAddInput, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_add_input_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxAddInput, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_add_output.rs b/fuzz/src/msg_targets/msg_tx_add_output.rs new file mode 100644 index 000000000..49b23218f --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_add_output.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_add_output_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxAddOutput, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_add_output_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxAddOutput, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_complete.rs b/fuzz/src/msg_targets/msg_tx_complete.rs new file mode 100644 index 000000000..c4227b152 --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_complete.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_complete_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxComplete, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_complete_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxComplete, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_init_rbf.rs b/fuzz/src/msg_targets/msg_tx_init_rbf.rs new file mode 100644 index 000000000..ea021dc60 --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_init_rbf.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_init_rbf_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxInitRbf, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_init_rbf_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxInitRbf, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_remove_input.rs b/fuzz/src/msg_targets/msg_tx_remove_input.rs new file mode 100644 index 000000000..fe69ad41b --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_remove_input.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_remove_input_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxRemoveInput, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_remove_input_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxRemoveInput, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_remove_output.rs b/fuzz/src/msg_targets/msg_tx_remove_output.rs new file mode 100644 index 000000000..6c09d4d9f --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_remove_output.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_remove_output_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxRemoveOutput, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_remove_output_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxRemoveOutput, data); +} diff --git a/fuzz/src/msg_targets/msg_tx_signatures.rs b/fuzz/src/msg_targets/msg_tx_signatures.rs new file mode 100644 index 000000000..54392d48c --- /dev/null +++ b/fuzz/src/msg_targets/msg_tx_signatures.rs @@ -0,0 +1,25 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +// This file is auto-generated by gen_target.sh based on msg_target_template.txt +// To modify it, modify msg_target_template.txt and run gen_target.sh instead. + +use crate::msg_targets::utils::VecWriter; +use crate::utils::test_logger; + +#[inline] +pub fn msg_tx_signatures_test(data: &[u8], _out: Out) { + test_msg_simple!(lightning::ln::msgs::TxSignatures, data); +} + +#[no_mangle] +pub extern "C" fn msg_tx_signatures_run(data: *const u8, datalen: usize) { + let data = unsafe { std::slice::from_raw_parts(data, datalen) }; + test_msg_simple!(lightning::ln::msgs::TxSignatures, data); +} diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 9bbf8b9cd..5fb2122ce 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -5,7 +5,7 @@ use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey}; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::RecoverableSignature; -use lightning::chain::keysinterface::{Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider}; +use lightning::sign::{Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider}; use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler}; use lightning::ln::script::ShutdownScript; use lightning::util::enforcing_trait_impls::EnforcingSigner; @@ -141,9 +141,9 @@ impl SignerProvider for KeyProvider { fn read_chan_signer(&self, _data: &[u8]) -> Result { unreachable!() } - fn get_destination_script(&self) -> Script { unreachable!() } + fn get_destination_script(&self) -> Result { unreachable!() } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { unreachable!() } + fn get_shutdown_scriptpubkey(&self) -> Result { unreachable!() } } #[cfg(test)] diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index d76607c03..359bbcc73 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -11,7 +11,7 @@ use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey, self}; use crate::utils::test_logger; use core::convert::{Infallible, TryFrom}; use lightning::blinded_path::BlindedPath; -use lightning::chain::keysinterface::EntropySource; +use lightning::sign::EntropySource; use lightning::ln::PaymentHash; use lightning::ln::features::BlindedHopFeatures; use lightning::offers::invoice::{BlindedPayInfo, UnsignedInvoice}; diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index fe6f1647f..00c53dfe5 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -17,7 +17,7 @@ use lightning::ln::msgs; use lightning::routing::gossip::{NetworkGraph, RoutingFees}; use lightning::routing::utxo::{UtxoFuture, UtxoLookup, UtxoLookupError, UtxoResult}; use lightning::routing::router::{find_route, PaymentParameters, RouteHint, RouteHintHop, RouteParameters}; -use lightning::routing::scoring::ProbabilisticScorer; +use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters}; use lightning::util::config::UserConfig; use lightning::util::ser::Readable; @@ -293,19 +293,19 @@ pub fn do_test(data: &[u8], out: Out) { }])); } } - let scorer = ProbabilisticScorer::new(Default::default(), &net_graph, &logger); + let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &net_graph, &logger); let random_seed_bytes: [u8; 32] = [get_slice!(1)[0]; 32]; for target in node_pks.iter() { let final_value_msat = slice_to_be64(get_slice!(8)); let final_cltv_expiry_delta = slice_to_be32(get_slice!(4)); let route_params = RouteParameters { payment_params: PaymentParameters::from_node_id(*target, final_cltv_expiry_delta) - .with_route_hints(last_hops.clone()), + .with_route_hints(last_hops.clone()).unwrap(), final_value_msat, }; let _ = find_route(&our_pubkey, &route_params, &net_graph, first_hops.map(|c| c.iter().collect::>()).as_ref().map(|a| a.as_slice()), - &logger, &scorer, &random_seed_bytes); + &logger, &scorer, &ProbabilisticScoringFeeParameters::default(), &random_seed_bytes); } }, } diff --git a/fuzz/targets.h b/fuzz/targets.h index 8f846c5e0..eb8d66f41 100644 --- a/fuzz/targets.h +++ b/fuzz/targets.h @@ -44,3 +44,14 @@ void msg_onion_hop_data_run(const unsigned char* data, size_t data_len); void msg_ping_run(const unsigned char* data, size_t data_len); void msg_pong_run(const unsigned char* data, size_t data_len); void msg_channel_details_run(const unsigned char* data, size_t data_len); +void msg_open_channel_v2_run(const unsigned char* data, size_t data_len); +void msg_accept_channel_v2_run(const unsigned char* data, size_t data_len); +void msg_tx_add_input_run(const unsigned char* data, size_t data_len); +void msg_tx_add_output_run(const unsigned char* data, size_t data_len); +void msg_tx_remove_input_run(const unsigned char* data, size_t data_len); +void msg_tx_remove_output_run(const unsigned char* data, size_t data_len); +void msg_tx_complete_run(const unsigned char* data, size_t data_len); +void msg_tx_signatures_run(const unsigned char* data, size_t data_len); +void msg_tx_init_rbf_run(const unsigned char* data, size_t data_len); +void msg_tx_ack_rbf_run(const unsigned char* data, size_t data_len); +void msg_tx_abort_run(const unsigned char* data, size_t data_len); diff --git a/lightning-background-processor/Cargo.toml b/lightning-background-processor/Cargo.toml index e2acb2240..1f6509e69 100644 --- a/lightning-background-processor/Cargo.toml +++ b/lightning-background-processor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-background-processor" -version = "0.0.114" +version = "0.0.115" authors = ["Valentine Wallace "] license = "MIT OR Apache-2.0" repository = "http://github.com/lightningdevkit/rust-lightning" @@ -21,11 +21,11 @@ default = ["std"] [dependencies] bitcoin = { version = "0.29.0", default-features = false } -lightning = { version = "0.0.114", path = "../lightning", default-features = false } -lightning-rapid-gossip-sync = { version = "0.0.114", path = "../lightning-rapid-gossip-sync", default-features = false } +lightning = { version = "0.0.115", path = "../lightning", default-features = false } +lightning-rapid-gossip-sync = { version = "0.0.115", path = "../lightning-rapid-gossip-sync", default-features = false } [dev-dependencies] tokio = { version = "1.14", features = [ "macros", "rt", "rt-multi-thread", "sync", "time" ] } -lightning = { version = "0.0.114", path = "../lightning", features = ["_test_utils"] } -lightning-invoice = { version = "0.22.0", path = "../lightning-invoice" } -lightning-persister = { version = "0.0.114", path = "../lightning-persister" } +lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] } +lightning-invoice = { version = "0.23.0", path = "../lightning-invoice" } +lightning-persister = { version = "0.0.115", path = "../lightning-persister" } diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index f72e98212..4d270286d 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -25,13 +25,12 @@ extern crate lightning_rapid_gossip_sync; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use lightning::chain::chainmonitor::{ChainMonitor, Persist}; -use lightning::chain::keysinterface::{EntropySource, NodeSigner, SignerProvider}; +use lightning::sign::{EntropySource, NodeSigner, SignerProvider}; use lightning::events::{Event, PathFailure}; #[cfg(feature = "std")] use lightning::events::{EventHandler, EventsProvider}; use lightning::ln::channelmanager::ChannelManager; -use lightning::ln::msgs::{ChannelMessageHandler, OnionMessageHandler, RoutingMessageHandler}; -use lightning::ln::peer_handler::{CustomMessageHandler, PeerManager, SocketDescriptor}; +use lightning::ln::peer_handler::APeerManager; use lightning::routing::gossip::{NetworkGraph, P2PGossipSync}; use lightning::routing::utxo::UtxoLookup; use lightning::routing::router::Router; @@ -81,6 +80,8 @@ use alloc::vec::Vec; /// /// [`ChannelMonitor`]: lightning::chain::channelmonitor::ChannelMonitor /// [`Event`]: lightning::events::Event +/// [`PeerManager::timer_tick_occurred`]: lightning::ln::peer_handler::PeerManager::timer_tick_occurred +/// [`PeerManager::process_events`]: lightning::ln::peer_handler::PeerManager::process_events #[cfg(feature = "std")] #[must_use = "BackgroundProcessor will immediately stop on drop. It should be stored until shutdown."] pub struct BackgroundProcessor { @@ -298,7 +299,7 @@ macro_rules! define_run_body { // ChannelManager, we want to minimize methods blocking on a ChannelManager // generally, and as a fallback place such blocking only immediately before // persistence. - $peer_manager.process_events(); + $peer_manager.as_ref().process_events(); // Exit the loop if the background processor was requested to stop. if $loop_exit_check { @@ -343,11 +344,11 @@ macro_rules! define_run_body { // more than a handful of seconds to complete, and shouldn't disconnect all our // peers. log_trace!($logger, "100ms sleep took more than a second, disconnecting peers."); - $peer_manager.disconnect_all_peers(); + $peer_manager.as_ref().disconnect_all_peers(); last_ping_call = $get_timer(PING_TIMER); } else if $timer_elapsed(&mut last_ping_call, PING_TIMER) { log_trace!($logger, "Calling PeerManager's timer_tick_occurred"); - $peer_manager.timer_tick_occurred(); + $peer_manager.as_ref().timer_tick_occurred(); last_ping_call = $get_timer(PING_TIMER); } @@ -514,11 +515,11 @@ use core::task; /// # use lightning_background_processor::{process_events_async, GossipSync}; /// # type MyBroadcaster = dyn lightning::chain::chaininterface::BroadcasterInterface + Send + Sync; /// # type MyFeeEstimator = dyn lightning::chain::chaininterface::FeeEstimator + Send + Sync; -/// # type MyNodeSigner = dyn lightning::chain::keysinterface::NodeSigner + Send + Sync; +/// # type MyNodeSigner = dyn lightning::sign::NodeSigner + Send + Sync; /// # type MyUtxoLookup = dyn lightning::routing::utxo::UtxoLookup + Send + Sync; /// # type MyFilter = dyn lightning::chain::Filter + Send + Sync; /// # type MyLogger = dyn lightning::util::logger::Logger + Send + Sync; -/// # type MyChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; +/// # type MyChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; /// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager; /// # type MyNetworkGraph = lightning::routing::gossip::NetworkGraph>; /// # type MyGossipSync = lightning::routing::gossip::P2PGossipSync, Arc, Arc>; @@ -587,10 +588,6 @@ pub async fn process_events_async< G: 'static + Deref> + Send + Sync, L: 'static + Deref + Send + Sync, P: 'static + Deref + Send + Sync, - Descriptor: 'static + SocketDescriptor + Send + Sync, - CMH: 'static + Deref + Send + Sync, - RMH: 'static + Deref + Send + Sync, - OMH: 'static + Deref + Send + Sync, EventHandlerFuture: core::future::Future, EventHandler: Fn(Event) -> EventHandlerFuture, PS: 'static + Deref + Send, @@ -598,8 +595,8 @@ pub async fn process_events_async< CM: 'static + Deref> + Send + Sync, PGS: 'static + Deref> + Send + Sync, RGS: 'static + Deref> + Send, - UMH: 'static + Deref + Send + Sync, - PM: 'static + Deref> + Send + Sync, + APM: APeerManager + Send + Sync, + PM: 'static + Deref + Send + Sync, S: 'static + Deref + Send + Sync, SC: for<'b> WriteableScore<'b>, SleepFuture: core::future::Future + core::marker::Unpin, @@ -621,10 +618,6 @@ where R::Target: 'static + Router, 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, CW, T, ES, NS, SP, F, R, L, SC>, { let mut should_break = false; @@ -737,18 +730,14 @@ impl BackgroundProcessor { G: 'static + Deref> + Send + Sync, L: 'static + Deref + Send + Sync, P: 'static + Deref + Send + Sync, - Descriptor: 'static + SocketDescriptor + Send + Sync, - CMH: 'static + Deref + Send + Sync, - OMH: 'static + Deref + Send + Sync, - RMH: 'static + Deref + Send + Sync, EH: 'static + EventHandler + Send, PS: 'static + Deref + Send, M: 'static + Deref::Signer, CF, T, F, L, P>> + Send + Sync, CM: 'static + Deref> + Send + Sync, PGS: 'static + Deref> + Send + Sync, RGS: 'static + Deref> + Send, - UMH: 'static + Deref + Send + Sync, - PM: 'static + Deref> + Send + Sync, + APM: APeerManager + Send + Sync, + PM: 'static + Deref + Send + Sync, S: 'static + Deref + Send + Sync, SC: for <'b> WriteableScore<'b>, >( @@ -767,10 +756,6 @@ impl BackgroundProcessor { R::Target: 'static + Router, 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, CW, T, ES, NS, SP, F, R, L, SC>, { let stop_thread = Arc::new(AtomicBool::new(false)); @@ -853,7 +838,6 @@ impl Drop for BackgroundProcessor { #[cfg(all(feature = "std", test))] mod tests { - use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::locktime::PackedLockTime; use bitcoin::blockdata::transaction::{Transaction, TxOut}; @@ -861,7 +845,7 @@ mod tests { use bitcoin::secp256k1::{SecretKey, PublicKey, Secp256k1}; use lightning::chain::{BestBlock, Confirm, chainmonitor}; use lightning::chain::channelmonitor::ANTI_REORG_DELAY; - use lightning::chain::keysinterface::{InMemorySigner, KeysManager}; + use lightning::sign::{InMemorySigner, KeysManager}; use lightning::chain::transaction::OutPoint; use lightning::events::{Event, PathFailure, MessageSendEventsProvider, MessageSendEvent}; use lightning::{get_event_msg, get_event}; @@ -869,6 +853,7 @@ mod tests { use lightning::ln::channelmanager; use lightning::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChainParameters, MIN_CLTV_EXPIRY_DELTA, PaymentId}; use lightning::ln::features::{ChannelFeatures, NodeFeatures}; + use lightning::ln::functional_test_utils::*; use lightning::ln::msgs::{ChannelMessageHandler, Init}; use lightning::ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler}; use lightning::routing::gossip::{NetworkGraph, NodeId, P2PGossipSync}; @@ -880,13 +865,11 @@ mod tests { use lightning::util::persist::KVStorePersister; use lightning_persister::FilesystemPersister; use std::collections::VecDeque; - use std::fs; + use std::{fs, env}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::sync::mpsc::SyncSender; use std::time::Duration; - use bitcoin::hashes::Hash; - use bitcoin::TxMerkleNode; use lightning_rapid_gossip_sync::RapidGossipSync; use super::{BackgroundProcessor, GossipSync, FRESHNESS_TIMER}; @@ -902,7 +885,7 @@ mod tests { fn disconnect_socket(&mut self) {} } - type ChannelManager = channelmanager::ChannelManager, Arc, Arc, Arc, Arc, Arc, Arc>>, Arc, Arc>>>, Arc>; + type ChannelManager = channelmanager::ChannelManager, Arc, Arc, Arc, Arc, Arc, Arc>>, Arc, Arc>, (), TestScorer>>, Arc>; type ChainMonitor = chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; @@ -1036,8 +1019,9 @@ mod tests { } impl Score for TestScorer { + type ScoreParams = (); fn channel_penalty_msat( - &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId, _usage: ChannelUsage + &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId, _usage: ChannelUsage, _score_params: &Self::ScoreParams ) -> u64 { unimplemented!(); } fn payment_path_failed(&mut self, actual_path: &Path, actual_short_channel_id: u64) { @@ -1137,7 +1121,9 @@ mod tests { path.to_str().unwrap().to_string() } - fn create_nodes(num_nodes: usize, persist_dir: String) -> Vec { + fn create_nodes(num_nodes: usize, persist_dir: &str) -> (String, Vec) { + let persist_temp_path = env::temp_dir().join(persist_dir); + let persist_dir = persist_temp_path.to_string_lossy().to_string(); let network = Network::Testnet; let mut nodes = Vec::new(); for i in 0..num_nodes { @@ -1148,9 +1134,9 @@ mod tests { let network_graph = Arc::new(NetworkGraph::new(network, logger.clone())); let scorer = Arc::new(Mutex::new(TestScorer::new())); let seed = [i as u8; 32]; - let router = Arc::new(DefaultRouter::new(network_graph.clone(), logger.clone(), seed, scorer.clone())); + let router = Arc::new(DefaultRouter::new(network_graph.clone(), logger.clone(), seed, scorer.clone(), ())); let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet)); - let persister = Arc::new(FilesystemPersister::new(format!("{}_persister_{}", persist_dir, i))); + let persister = Arc::new(FilesystemPersister::new(format!("{}_persister_{}", &persist_dir, i))); let now = Duration::from_secs(genesis_block.header.time as u64); let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos())); let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new(Some(chain_source.clone()), tx_broadcaster.clone(), logger.clone(), fee_estimator.clone(), persister.clone())); @@ -1159,8 +1145,12 @@ mod tests { let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster.clone(), router.clone(), logger.clone(), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), UserConfig::default(), params)); let p2p_gossip_sync = Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone())); let rapid_gossip_sync = Arc::new(RapidGossipSync::new(network_graph.clone(), logger.clone())); - let msg_handler = MessageHandler { chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new()), route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()), onion_message_handler: IgnoringMessageHandler{}}; - let peer_manager = Arc::new(PeerManager::new(msg_handler, 0, &seed, logger.clone(), IgnoringMessageHandler{}, keys_manager.clone())); + let msg_handler = MessageHandler { + chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new()), + route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()), + onion_message_handler: IgnoringMessageHandler{}, custom_message_handler: IgnoringMessageHandler{} + }; + let peer_manager = Arc::new(PeerManager::new(msg_handler, 0, &seed, logger.clone(), keys_manager.clone())); let node = Node { node: manager, p2p_gossip_sync, rapid_gossip_sync, peer_manager, chain_monitor, persister, tx_broadcaster, network_graph, logger, best_block, scorer }; nodes.push(node); } @@ -1172,7 +1162,7 @@ mod tests { } } - nodes + (persist_dir, nodes) } macro_rules! open_channel { @@ -1219,7 +1209,7 @@ mod tests { for i in 1..=depth { let prev_blockhash = node.best_block.block_hash(); let height = node.best_block.height() + 1; - let header = BlockHeader { version: 0x20000000, prev_blockhash, merkle_root: TxMerkleNode::all_zeros(), time: height, bits: 42, nonce: 42 }; + let header = create_dummy_header(prev_blockhash, height); let txdata = vec![(0, tx)]; node.best_block = BestBlock::new(header.block_hash(), height); match i { @@ -1244,7 +1234,7 @@ mod tests { // Test that when a new channel is created, the ChannelManager needs to be re-persisted with // updates. Also test that when new updates are available, the manager signals that it needs // re-persistence and is successfully re-persisted. - let nodes = create_nodes(2, "test_background_processor".to_string()); + let (persist_dir, nodes) = create_nodes(2, "test_background_processor"); // Go through the channel creation process so that each node has something to persist. Since // open_channel consumes events, it must complete before starting BackgroundProcessor to @@ -1282,7 +1272,7 @@ mod tests { } // Check that the initial channel manager data is persisted as expected. - let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "manager".to_string()); + let filepath = get_full_filepath(format!("{}_persister_0", &persist_dir), "manager".to_string()); check_persisted_data!(nodes[0].node, filepath.clone()); loop { @@ -1299,11 +1289,11 @@ mod tests { } // Check network graph is persisted - let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string()); + let filepath = get_full_filepath(format!("{}_persister_0", &persist_dir), "network_graph".to_string()); check_persisted_data!(nodes[0].network_graph, filepath.clone()); // Check scorer is persisted - let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "scorer".to_string()); + let filepath = get_full_filepath(format!("{}_persister_0", &persist_dir), "scorer".to_string()); check_persisted_data!(nodes[0].scorer, filepath.clone()); if !std::thread::panicking() { @@ -1316,7 +1306,7 @@ mod tests { // Test that `ChannelManager::timer_tick_occurred` is called every `FRESHNESS_TIMER`, // `ChainMonitor::rebroadcast_pending_claims` is called every `REBROADCAST_TIMER`, and // `PeerManager::timer_tick_occurred` every `PING_TIMER`. - let nodes = create_nodes(1, "test_timer_tick_called".to_string()); + let (_, nodes) = create_nodes(1, "test_timer_tick_called"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir)); let event_handler = |_: _| {}; @@ -1341,7 +1331,7 @@ mod tests { #[test] fn test_channel_manager_persist_error() { // Test that if we encounter an error during manager persistence, the thread panics. - let nodes = create_nodes(2, "test_persist_error".to_string()); + let (_, nodes) = create_nodes(2, "test_persist_error"); open_channel!(nodes[0], nodes[1], 100000); let data_dir = nodes[0].persister.get_data_dir(); @@ -1361,7 +1351,7 @@ mod tests { #[cfg(feature = "futures")] async fn test_channel_manager_persist_error_async() { // Test that if we encounter an error during manager persistence, the thread panics. - let nodes = create_nodes(2, "test_persist_error_sync".to_string()); + let (_, nodes) = create_nodes(2, "test_persist_error_sync"); open_channel!(nodes[0], nodes[1], 100000); let data_dir = nodes[0].persister.get_data_dir(); @@ -1389,7 +1379,7 @@ mod tests { #[test] fn test_network_graph_persist_error() { // Test that if we encounter an error during network graph persistence, an error gets returned. - let nodes = create_nodes(2, "test_persist_network_graph_error".to_string()); + let (_, nodes) = create_nodes(2, "test_persist_network_graph_error"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other, "test")); let event_handler = |_: _| {}; @@ -1407,7 +1397,7 @@ mod tests { #[test] fn test_scorer_persist_error() { // Test that if we encounter an error during scorer persistence, an error gets returned. - let nodes = create_nodes(2, "test_persist_scorer_error".to_string()); + let (_, nodes) = create_nodes(2, "test_persist_scorer_error"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir).with_scorer_error(std::io::ErrorKind::Other, "test")); let event_handler = |_: _| {}; @@ -1424,7 +1414,7 @@ mod tests { #[test] fn test_background_event_handling() { - let mut nodes = create_nodes(2, "test_background_event_handling".to_string()); + let (_, mut nodes) = create_nodes(2, "test_background_event_handling"); let channel_value = 100000; let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir.clone())); @@ -1498,7 +1488,7 @@ mod tests { #[test] fn test_scorer_persistence() { - let nodes = create_nodes(2, "test_scorer_persistence".to_string()); + let (_, nodes) = create_nodes(2, "test_scorer_persistence"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir)); let event_handler = |_: _| {}; @@ -1570,7 +1560,7 @@ mod tests { fn test_not_pruning_network_graph_until_graph_sync_completion() { let (sender, receiver) = std::sync::mpsc::sync_channel(1); - let nodes = create_nodes(2, "test_not_pruning_network_graph_until_graph_sync_completion".to_string()); + let (_, nodes) = create_nodes(2, "test_not_pruning_network_graph_until_graph_sync_completion"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir).with_graph_persistence_notifier(sender)); @@ -1589,7 +1579,7 @@ mod tests { async fn test_not_pruning_network_graph_until_graph_sync_completion_async() { let (sender, receiver) = std::sync::mpsc::sync_channel(1); - let nodes = create_nodes(2, "test_not_pruning_network_graph_until_graph_sync_completion_async".to_string()); + let (_, nodes) = create_nodes(2, "test_not_pruning_network_graph_until_graph_sync_completion_async"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir).with_graph_persistence_notifier(sender)); @@ -1729,7 +1719,7 @@ mod tests { _ => panic!("Unexpected event: {:?}", event), }; - let nodes = create_nodes(1, "test_payment_path_scoring".to_string()); + let (_, nodes) = create_nodes(1, "test_payment_path_scoring"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir)); 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())); @@ -1762,7 +1752,7 @@ mod tests { } }; - let nodes = create_nodes(1, "test_payment_path_scoring_async".to_string()); + let (_, nodes) = create_nodes(1, "test_payment_path_scoring_async"); let data_dir = nodes[0].persister.get_data_dir(); let persister = Arc::new(Persister::new(data_dir)); diff --git a/lightning-block-sync/Cargo.toml b/lightning-block-sync/Cargo.toml index 59f8c2356..a19c3ff8a 100644 --- a/lightning-block-sync/Cargo.toml +++ b/lightning-block-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-block-sync" -version = "0.0.114" +version = "0.0.115" authors = ["Jeffrey Czyz", "Matt Corallo"] license = "MIT OR Apache-2.0" repository = "http://github.com/lightningdevkit/rust-lightning" @@ -19,11 +19,11 @@ rpc-client = [ "serde_json", "chunked_transfer" ] [dependencies] bitcoin = "0.29.0" -lightning = { version = "0.0.114", path = "../lightning" } +lightning = { version = "0.0.115", path = "../lightning" } tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true } serde_json = { version = "1.0", optional = true } chunked_transfer = { version = "1.4", optional = true } [dev-dependencies] -lightning = { version = "0.0.114", path = "../lightning", features = ["_test_utils"] } +lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] } tokio = { version = "1.14", features = [ "macros", "rt" ] } diff --git a/lightning-block-sync/src/init.rs b/lightning-block-sync/src/init.rs index 866b247ed..5423bba51 100644 --- a/lightning-block-sync/src/init.rs +++ b/lightning-block-sync/src/init.rs @@ -47,8 +47,8 @@ BlockSourceResult where B::Target: BlockSource { /// use lightning::chain::channelmonitor::ChannelMonitor; /// use lightning::chain::chaininterface::BroadcasterInterface; /// use lightning::chain::chaininterface::FeeEstimator; -/// use lightning::chain::keysinterface; -/// use lightning::chain::keysinterface::{EntropySource, NodeSigner, SignerProvider}; +/// use lightning::sign; +/// use lightning::sign::{EntropySource, NodeSigner, SignerProvider}; /// use lightning::ln::channelmanager::{ChannelManager, ChannelManagerReadArgs}; /// use lightning::routing::router::Router; /// use lightning::util::config::UserConfig; diff --git a/lightning-block-sync/src/poll.rs b/lightning-block-sync/src/poll.rs index 9f7e8becf..e7171cf36 100644 --- a/lightning-block-sync/src/poll.rs +++ b/lightning-block-sync/src/poll.rs @@ -136,8 +136,11 @@ impl ValidatedBlockHeader { if let Network::Bitcoin = network { if self.height % 2016 == 0 { - let previous_work = previous_header.header.work(); - if work > (previous_work << 2) || work < (previous_work >> 2) { + let target = self.header.target(); + let previous_target = previous_header.header.target(); + let min_target = previous_target >> 2; + let max_target = previous_target << 2; + if target > max_target || target < min_target { return Err(BlockSourceError::persistent("invalid difficulty transition")) } } else if self.header.bits != previous_header.header.bits { diff --git a/lightning-custom-message/Cargo.toml b/lightning-custom-message/Cargo.toml index 509b6024d..68aa2a1cb 100644 --- a/lightning-custom-message/Cargo.toml +++ b/lightning-custom-message/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-custom-message" -version = "0.0.114" +version = "0.0.115" authors = ["Jeffrey Czyz"] license = "MIT OR Apache-2.0" repository = "http://github.com/lightningdevkit/rust-lightning" @@ -15,4 +15,4 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] bitcoin = "0.29.0" -lightning = { version = "0.0.114", path = "../lightning" } +lightning = { version = "0.0.115", path = "../lightning" } diff --git a/lightning-custom-message/src/lib.rs b/lightning-custom-message/src/lib.rs index a6e43978d..a0a70c9de 100644 --- a/lightning-custom-message/src/lib.rs +++ b/lightning-custom-message/src/lib.rs @@ -20,6 +20,7 @@ //! # use bitcoin::secp256k1::PublicKey; //! # use lightning::io; //! # use lightning::ln::msgs::{DecodeError, LightningError}; +//! # use lightning::ln::features::{InitFeatures, NodeFeatures}; //! use lightning::ln::peer_handler::CustomMessageHandler; //! use lightning::ln::wire::{CustomMessageReader, self}; //! use lightning::util::ser::Writeable; @@ -66,6 +67,12 @@ //! # fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> { //! # unimplemented!() //! # } +//! # fn provided_node_features(&self) -> NodeFeatures { +//! # unimplemented!() +//! # } +//! # fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { +//! # unimplemented!() +//! # } //! } //! //! #[derive(Debug)] @@ -106,6 +113,12 @@ //! # fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> { //! # unimplemented!() //! # } +//! # fn provided_node_features(&self) -> NodeFeatures { +//! # unimplemented!() +//! # } +//! # fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { +//! # unimplemented!() +//! # } //! } //! //! #[derive(Debug)] @@ -146,6 +159,12 @@ //! # fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> { //! # unimplemented!() //! # } +//! # fn provided_node_features(&self) -> NodeFeatures { +//! # unimplemented!() +//! # } +//! # fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { +//! # unimplemented!() +//! # } //! } //! //! # fn main() { @@ -268,6 +287,22 @@ macro_rules! composite_custom_message_handler { )* .collect() } + + fn provided_node_features(&self) -> $crate::lightning::ln::features::NodeFeatures { + $crate::lightning::ln::features::NodeFeatures::empty() + $( + | self.$field.provided_node_features() + )* + } + + fn provided_init_features( + &self, their_node_id: &$crate::bitcoin::secp256k1::PublicKey + ) -> $crate::lightning::ln::features::InitFeatures { + $crate::lightning::ln::features::InitFeatures::empty() + $( + | self.$field.provided_init_features(their_node_id) + )* + } } impl $crate::lightning::ln::wire::CustomMessageReader for $handler { diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index 9ab9bd548..5179fdc14 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "lightning-invoice" description = "Data structures to parse and serialize BOLT11 lightning invoices" -version = "0.22.0" +version = "0.23.0" authors = ["Sebastian Geisler "] documentation = "https://docs.rs/lightning-invoice/" license = "MIT OR Apache-2.0" @@ -21,7 +21,7 @@ std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std", "bech32/std"] [dependencies] bech32 = { version = "0.9.0", default-features = false } -lightning = { version = "0.0.114", path = "../lightning", default-features = false } +lightning = { version = "0.0.115", path = "../lightning", default-features = false } 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 } @@ -30,6 +30,6 @@ serde = { version = "1.0.118", optional = true } bitcoin = { version = "0.29.0", default-features = false } [dev-dependencies] -lightning = { version = "0.0.114", path = "../lightning", default-features = false, features = ["_test_utils"] } +lightning = { version = "0.0.115", path = "../lightning", default-features = false, features = ["_test_utils"] } hex = "0.4" serde_json = { version = "1"} diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index 0923fcc17..8ccd9d979 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -61,6 +61,7 @@ use secp256k1::PublicKey; use secp256k1::{Message, Secp256k1}; use secp256k1::ecdsa::RecoverableSignature; +use core::cmp::Ordering; use core::fmt::{Display, Formatter, self}; use core::iter::FilterMap; use core::num::ParseIntError; @@ -248,7 +249,7 @@ pub struct InvoiceBuilder(&str)` (see [`Invoice::from_str`]) /// /// [`Invoice::from_str`]: crate::Invoice#impl-FromStr -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct Invoice { signed_invoice: SignedRawInvoice, } @@ -258,7 +259,7 @@ pub struct Invoice { /// /// This is not exported to bindings users as we don't have a good way to map the reference lifetimes making this /// practically impossible to use safely in languages like C. -#[derive(Eq, PartialEq, Debug, Clone)] +#[derive(Eq, PartialEq, Debug, Clone, Ord, PartialOrd)] pub enum InvoiceDescription<'f> { /// Reference to the directly supplied description in the invoice Direct(&'f Description), @@ -272,7 +273,7 @@ pub enum InvoiceDescription<'f> { /// /// # Invariants /// The hash has to be either from the deserialized invoice or from the serialized [`RawInvoice`]. -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct SignedRawInvoice { /// The rawInvoice that the signature belongs to raw_invoice: RawInvoice, @@ -295,7 +296,7 @@ pub struct SignedRawInvoice { /// Decoding and encoding should not lead to information loss but may lead to different hashes. /// /// For methods without docs see the corresponding methods in [`Invoice`]. -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct RawInvoice { /// human readable part pub hrp: RawHrp, @@ -307,7 +308,7 @@ pub struct RawInvoice { /// Data of the [`RawInvoice`] that is encoded in the human readable part. /// /// This is not exported to bindings users as we don't yet support `Option` -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct RawHrp { /// The currency deferred from the 3rd and 4th character of the bech32 transaction pub currency: Currency, @@ -320,7 +321,7 @@ pub struct RawHrp { } /// Data of the [`RawInvoice`] that is encoded in the data part -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct RawDataPart { /// generation time of the invoice pub timestamp: PositiveTimestamp, @@ -335,11 +336,11 @@ pub struct RawDataPart { /// /// The Unix timestamp representing the stored time has to be positive and no greater than /// [`MAX_TIMESTAMP`]. -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct PositiveTimestamp(Duration); /// SI prefixes for the human readable part -#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Ord, PartialOrd)] pub enum SiPrefix { /// 10^-3 Milli, @@ -376,7 +377,7 @@ impl SiPrefix { } /// Enum representing the crypto currencies (or networks) supported by this library -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum Currency { /// Bitcoin mainnet Bitcoin, @@ -420,7 +421,7 @@ impl From for Network { /// Tagged field which may have an unknown tag /// /// This is not exported to bindings users as we don't currently support TaggedField -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum RawTaggedField { /// Parsed tagged field with known tag KnownSemantics(TaggedField), @@ -435,7 +436,7 @@ pub enum RawTaggedField { /// This is not exported to bindings users as we don't yet support enum variants with the same name the struct contained /// in the variant. #[allow(missing_docs)] -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum TaggedField { PaymentHash(Sha256), Description(Description), @@ -451,33 +452,42 @@ pub enum TaggedField { } /// SHA-256 hash -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct Sha256(/// This is not exported to bindings users as the native hash types are not currently mapped pub sha256::Hash); +impl Sha256 { + /// Constructs a new [`Sha256`] from the given bytes, which are assumed to be the output of a + /// single sha256 hash. + #[cfg(c_bindings)] + pub fn from_bytes(bytes: &[u8; 32]) -> Self { + Self(sha256::Hash::from_slice(bytes).expect("from_slice only fails if len is not 32")) + } +} + /// Description string /// /// # Invariants /// The description can be at most 639 __bytes__ long -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct Description(String); /// Payee public key -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct PayeePubKey(pub PublicKey); /// Positive duration that defines when (relatively to the timestamp) in the future the invoice /// expires -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct ExpiryTime(Duration); /// `min_final_cltv_expiry_delta` to use for the last HTLC in the route -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct MinFinalCltvExpiryDelta(pub u64); /// Fallback address in case no LN payment is possible #[allow(missing_docs)] -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum Fallback { SegWitProgram { version: WitnessVersion, @@ -491,12 +501,24 @@ pub enum Fallback { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct InvoiceSignature(pub RecoverableSignature); +impl PartialOrd for InvoiceSignature { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.serialize_compact().1.partial_cmp(&other.0.serialize_compact().1) + } +} + +impl Ord for InvoiceSignature { + fn cmp(&self, other: &Self) -> Ordering { + self.0.serialize_compact().1.cmp(&other.0.serialize_compact().1) + } +} + /// Private routing information /// /// # Invariants /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops) /// -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct PrivateRoute(RouteHint); /// Tag constants as specified in BOLT11 @@ -1716,7 +1738,7 @@ impl<'de> Deserialize<'de> for Invoice { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { let bolt11 = String::deserialize(deserializer)? .parse::() - .map_err(|e| D::Error::custom(alloc::format!("{:?}", e)))?; + .map_err(|e| D::Error::custom(format_args!("{:?}", e)))?; Ok(bolt11) } diff --git a/lightning-invoice/src/payment.rs b/lightning-invoice/src/payment.rs index 11757be2e..c08a00a0c 100644 --- a/lightning-invoice/src/payment.rs +++ b/lightning-invoice/src/payment.rs @@ -15,7 +15,7 @@ use bitcoin_hashes::Hash; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; -use lightning::chain::keysinterface::{NodeSigner, SignerProvider, EntropySource}; +use lightning::sign::{NodeSigner, SignerProvider, EntropySource}; use lightning::ln::PaymentHash; use lightning::ln::channelmanager::{ChannelManager, PaymentId, Retry, RetryableSendFailure, RecipientOnionFields}; use lightning::routing::router::{PaymentParameters, RouteParameters, Router}; @@ -152,9 +152,9 @@ fn pay_invoice_using_amount( let mut payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key(), invoice.min_final_cltv_expiry_delta() as u32) .with_expiry_time(expiry_time_from_unix_epoch(invoice).as_secs()) - .with_route_hints(invoice.route_hints()); + .with_route_hints(invoice.route_hints()).unwrap(); if let Some(features) = invoice.features() { - payment_params = payment_params.with_features(features.clone()); + payment_params = payment_params.with_bolt11_features(features.clone()).unwrap(); } let route_params = RouteParameters { payment_params, diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs index 5f378ab6f..b3b7c2b91 100644 --- a/lightning-invoice/src/utils.rs +++ b/lightning-invoice/src/utils.rs @@ -7,7 +7,7 @@ use bech32::ToBase32; use bitcoin_hashes::Hash; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; -use lightning::chain::keysinterface::{Recipient, NodeSigner, SignerProvider, EntropySource}; +use lightning::sign::{Recipient, NodeSigner, SignerProvider, EntropySource}; use lightning::ln::{PaymentHash, PaymentSecret}; use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, MIN_FINAL_CLTV_EXPIRY_DELTA}; use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA}; @@ -50,7 +50,7 @@ use core::time::Duration; /// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this /// requirement). /// -/// [`PhantomKeysManager`]: lightning::chain::keysinterface::PhantomKeysManager +/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager /// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints /// [`ChannelManager::create_inbound_payment`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment /// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash @@ -86,9 +86,11 @@ where /// participating node /// * It is fine to cache `phantom_route_hints` and reuse it across invoices, as long as the data is /// updated when a channel becomes disabled or closes -/// * Note that if too many channels are included in [`PhantomRouteHints::channels`], the invoice -/// may be too long for QR code scanning. To fix this, `PhantomRouteHints::channels` may be pared -/// down +/// * Note that the route hints generated from `phantom_route_hints` will be limited to a maximum +/// of 3 hints to ensure that the invoice can be scanned in a QR code. These hints are selected +/// in the order that the nodes in `PhantomRouteHints` are specified, selecting one hint per node +/// until the maximum is hit. Callers may provide as many `PhantomRouteHints::channels` as +/// desired, but note that some nodes will be trimmed if more than 3 nodes are provided. /// /// `description_hash` is a SHA-256 hash of the description text /// @@ -105,7 +107,7 @@ where /// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this /// requirement). /// -/// [`PhantomKeysManager`]: lightning::chain::keysinterface::PhantomKeysManager +/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager /// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints /// [`ChannelManager::create_inbound_payment`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment /// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash @@ -200,19 +202,52 @@ where invoice = invoice.amount_milli_satoshis(amt); } + for route_hint in select_phantom_hints(amt_msat, phantom_route_hints, logger) { + invoice = invoice.private_route(route_hint); + } + + let raw_invoice = match invoice.build_raw() { + Ok(inv) => inv, + Err(e) => return Err(SignOrCreationError::CreationError(e)) + }; + let hrp_str = raw_invoice.hrp.to_string(); + let hrp_bytes = hrp_str.as_bytes(); + let data_without_signature = raw_invoice.data.to_base32(); + let signed_raw_invoice = raw_invoice.sign(|_| node_signer.sign_invoice(hrp_bytes, &data_without_signature, Recipient::PhantomNode)); + match signed_raw_invoice { + Ok(inv) => Ok(Invoice::from_signed(inv).unwrap()), + Err(e) => Err(SignOrCreationError::SignError(e)) + } +} + +/// Utility to select route hints for phantom invoices. +/// See [`PhantomKeysManager`] for more information on phantom node payments. +/// +/// To ensure that the phantom invoice is still readable by QR code, we limit to 3 hints per invoice: +/// * Select up to three channels per node. +/// * Select one hint from each node, up to three hints or until we run out of hints. +/// +/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager +fn select_phantom_hints(amt_msat: Option, phantom_route_hints: Vec, + logger: L) -> Vec +where + L::Target: Logger, +{ + let mut phantom_hints: Vec> = Vec::new(); + for PhantomRouteHints { channels, phantom_scid, real_node_pubkey } in phantom_route_hints { log_trace!(logger, "Generating phantom route hints for node {}", log_pubkey!(real_node_pubkey)); - let mut route_hints = filter_channels(channels, amt_msat, &logger); + let mut route_hints = sort_and_filter_channels(channels, amt_msat, &logger); - // If we have any public channel, the route hints from `filter_channels` will be empty. - // In that case we create a RouteHint on which we will push a single hop with the phantom - // route into the invoice, and let the sender find the path to the `real_node_pubkey` + // If we have any public channel, the route hints from `sort_and_filter_channels` will be + // empty. In that case we create a RouteHint on which we will push a single hop with the + // phantom route into the invoice, and let the sender find the path to the `real_node_pubkey` // node by looking at our public channels. if route_hints.is_empty() { route_hints.push(RouteHint(vec![])) } - for mut route_hint in route_hints { + for route_hint in &mut route_hints { route_hint.0.push(RouteHintHop { src_node_id: real_node_pubkey, short_channel_id: phantom_scid, @@ -223,21 +258,37 @@ where cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA, htlc_minimum_msat: None, htlc_maximum_msat: None,}); - invoice = invoice.private_route(route_hint.clone()); } + + phantom_hints.push(route_hints); } - let raw_invoice = match invoice.build_raw() { - Ok(inv) => inv, - Err(e) => return Err(SignOrCreationError::CreationError(e)) - }; - let hrp_str = raw_invoice.hrp.to_string(); - let hrp_bytes = hrp_str.as_bytes(); - let data_without_signature = raw_invoice.data.to_base32(); - let signed_raw_invoice = raw_invoice.sign(|_| node_signer.sign_invoice(hrp_bytes, &data_without_signature, Recipient::PhantomNode)); - match signed_raw_invoice { - Ok(inv) => Ok(Invoice::from_signed(inv).unwrap()), - Err(e) => Err(SignOrCreationError::SignError(e)) + // We have one vector per real node involved in creating the phantom invoice. To distribute + // the hints across our real nodes we add one hint from each in turn until no node has any hints + // left (if one node has more hints than any other, these will accumulate at the end of the + // vector). + let mut invoice_hints: Vec = Vec::new(); + let mut hint_idx = 0; + + loop { + let mut remaining_hints = false; + + for hints in phantom_hints.iter() { + if invoice_hints.len() == 3 { + return invoice_hints + } + + if hint_idx < hints.len() { + invoice_hints.push(hints[hint_idx].clone()); + remaining_hints = true + } + } + + if !remaining_hints { + return invoice_hints + } + + hint_idx +=1; } } @@ -485,7 +536,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has invoice = invoice.amount_milli_satoshis(amt); } - let route_hints = filter_channels(channels, amt_msat, &logger); + let route_hints = sort_and_filter_channels(channels, amt_msat, &logger); for hint in route_hints { invoice = invoice.private_route(hint); } @@ -504,19 +555,26 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has } } -/// Filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include +/// Sorts and filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include /// in the invoice. /// /// The filtering is based on the following criteria: /// * Only one channel per counterparty node -/// * Always select the channel with the highest inbound capacity per counterparty node +/// * If the counterparty has a channel that is above the `min_inbound_capacity_msat` + 10% scaling +/// factor (to allow some margin for change in inbound), select the channel with the lowest +/// inbound capacity that is above this threshold. +/// * If no `min_inbound_capacity_msat` is specified, or the counterparty has no channels above the +/// minimum + 10% scaling factor, select the channel with the highest inbound capacity per counterparty. /// * Prefer channels with capacity at least `min_inbound_capacity_msat` and where the channel /// `is_usable` (i.e. the peer is connected). /// * If any public channel exists, only public [`RouteHint`]s will be returned. /// * If any public, announced, channel exists (i.e. a channel with 7+ confs, to ensure the /// announcement has had a chance to propagate), no [`RouteHint`]s will be returned, as the /// sender is expected to find the path by looking at the public channels instead. -fn filter_channels( +/// * Limited to a total of 3 channels. +/// * Sorted by lowest inbound capacity if an online channel with the minimum amount requested exists, +/// otherwise sort by highest inbound capacity to give the payment the best chance of succeeding. +fn sort_and_filter_channels( channels: Vec, min_inbound_capacity_msat: Option, logger: &L ) -> Vec where L::Target: Logger { let mut filtered_channels: HashMap = HashMap::new(); @@ -570,12 +628,16 @@ fn filter_channels( // If this channel is public and the previous channel is not, ensure we replace the // previous channel to avoid announcing non-public channels. let new_now_public = channel.is_public && !entry.get().is_public; + // Decide whether we prefer the currently selected channel with the node to the new one, + // based on their inbound capacity. + let prefer_current = prefer_current_channel(min_inbound_capacity_msat, current_max_capacity, + channel.inbound_capacity_msat); // If the public-ness of the channel has not changed (in which case simply defer to - // `new_now_public), and this channel has a greater capacity, prefer to announce - // this channel. - let new_higher_capacity = channel.is_public == entry.get().is_public && - channel.inbound_capacity_msat > current_max_capacity; - if new_now_public || new_higher_capacity { + // `new_now_public), and this channel has more desirable inbound than the incumbent, + // prefer to include this channel. + let new_channel_preferable = channel.is_public == entry.get().is_public && !prefer_current; + + if new_now_public || new_channel_preferable { log_trace!(logger, "Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints", log_pubkey!(channel.counterparty.node_id), @@ -617,7 +679,7 @@ fn filter_channels( // the payment value and where we're currently connected to the channel counterparty. // Even if we cannot satisfy both goals, always ensure we include *some* hints, preferring // those which meet at least one criteria. - filtered_channels + let mut eligible_channels = filtered_channels .into_iter() .map(|(_, channel)| channel) .filter(|channel| { @@ -654,8 +716,50 @@ fn filter_channels( include_channel }) - .map(route_hint_from_channel) - .collect::>() + .collect::>(); + + eligible_channels.sort_unstable_by(|a, b| { + if online_min_capacity_channel_exists { + a.inbound_capacity_msat.cmp(&b.inbound_capacity_msat) + } else { + b.inbound_capacity_msat.cmp(&a.inbound_capacity_msat) + }}); + eligible_channels.into_iter().take(3).map(route_hint_from_channel).collect::>() +} + +/// prefer_current_channel chooses a channel to use for route hints between a currently selected and candidate +/// channel based on the inbound capacity of each channel and the minimum inbound capacity requested for the hints, +/// returning true if the current channel should be preferred over the candidate channel. +/// * If no minimum amount is requested, the channel with the most inbound is chosen to maximize the chances that a +/// payment of any size will succeed. +/// * If we have channels with inbound above our minimum requested inbound (plus a 10% scaling factor, expressed as a +/// percentage) then we choose the lowest inbound channel with above this amount. If we have sufficient inbound +/// channels, we don't want to deplete our larger channels with small payments (the off-chain version of "grinding +/// our change"). +/// * If no channel above our minimum amount exists, then we just prefer the channel with the most inbound to give +/// payments the best chance of succeeding in multiple parts. +fn prefer_current_channel(min_inbound_capacity_msat: Option, current_channel: u64, + candidate_channel: u64) -> bool { + + // If no min amount is given for the hints, err of the side of caution and choose the largest channel inbound to + // maximize chances of any payment succeeding. + if min_inbound_capacity_msat.is_none() { + return current_channel > candidate_channel + } + + let scaled_min_inbound = min_inbound_capacity_msat.unwrap() * 110; + let current_sufficient = current_channel * 100 >= scaled_min_inbound; + let candidate_sufficient = candidate_channel * 100 >= scaled_min_inbound; + + if current_sufficient && candidate_sufficient { + return current_channel < candidate_channel + } else if current_sufficient { + return true + } else if candidate_sufficient { + return false + } + + current_channel > candidate_channel } #[cfg(test)] @@ -664,7 +768,7 @@ mod test { use crate::{Currency, Description, InvoiceDescription, SignOrCreationError, CreationError}; use bitcoin_hashes::{Hash, sha256}; use bitcoin_hashes::sha256::Hash as Sha256; - use lightning::chain::keysinterface::PhantomKeysManager; + use lightning::sign::PhantomKeysManager; use lightning::events::{MessageSendEvent, MessageSendEventsProvider, Event}; use lightning::ln::{PaymentPreimage, PaymentHash}; use lightning::ln::channelmanager::{PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY_DELTA, PaymentId, RecipientOnionFields, Retry}; @@ -676,6 +780,34 @@ mod test { use crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch; use std::collections::HashSet; + #[test] + fn test_prefer_current_channel() { + // No minimum, prefer larger candidate channel. + assert_eq!(crate::utils::prefer_current_channel(None, 100, 200), false); + + // No minimum, prefer larger current channel. + assert_eq!(crate::utils::prefer_current_channel(None, 200, 100), true); + + // Minimum set, prefer current channel over minimum + buffer. + assert_eq!(crate::utils::prefer_current_channel(Some(100), 115, 100), true); + + // Minimum set, prefer candidate channel over minimum + buffer. + assert_eq!(crate::utils::prefer_current_channel(Some(100), 105, 125), false); + + // Minimum set, both channels sufficient, prefer smaller current channel. + assert_eq!(crate::utils::prefer_current_channel(Some(100), 115, 125), true); + + // Minimum set, both channels sufficient, prefer smaller candidate channel. + assert_eq!(crate::utils::prefer_current_channel(Some(100), 200, 160), false); + + // Minimum set, neither sufficient, prefer larger current channel. + assert_eq!(crate::utils::prefer_current_channel(Some(200), 100, 50), true); + + // Minimum set, neither sufficient, prefer larger candidate channel. + assert_eq!(crate::utils::prefer_current_channel(Some(200), 100, 150), false); + } + + #[test] fn test_from_channelmanager() { let chanmon_cfgs = create_chanmon_cfgs(2); @@ -706,8 +838,8 @@ mod test { let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key(), invoice.min_final_cltv_expiry_delta() as u32) - .with_features(invoice.features().unwrap().clone()) - .with_route_hints(invoice.route_hints()); + .with_bolt11_features(invoice.features().unwrap().clone()).unwrap() + .with_route_hints(invoice.route_hints()).unwrap(); let route_params = RouteParameters { payment_params, final_value_msat: invoice.amount_milli_satoshis().unwrap(), @@ -883,17 +1015,19 @@ mod test { } #[test] - fn test_hints_has_only_highest_inbound_capacity_channel() { + fn test_hints_has_only_lowest_inbound_capacity_channel_above_minimum() { let chanmon_cfgs = create_chanmon_cfgs(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_1_0_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0); - let chan_1_0_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 10_000_000, 0); - let _chan_1_0_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 1_000_000, 0); + + let _chan_1_0_inbound_below_amt = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 10_000, 0); + let _chan_1_0_large_inbound_above_amt = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 500_000, 0); + let chan_1_0_low_inbound_above_amt = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 200_000, 0); + let mut scid_aliases = HashSet::new(); - scid_aliases.insert(chan_1_0_high_inbound_capacity.0.short_channel_id_alias.unwrap()); - match_invoice_routes(Some(5000), &nodes[0], scid_aliases); + scid_aliases.insert(chan_1_0_low_inbound_above_amt.0.short_channel_id_alias.unwrap()); + match_invoice_routes(Some(100_000_000), &nodes[0], scid_aliases); } #[test] @@ -925,6 +1059,48 @@ mod test { match_invoice_routes(Some(1_000_000_000), &nodes[0], scid_aliases); } + #[test] + fn test_insufficient_inbound_sort_by_highest_capacity() { + let chanmon_cfgs = create_chanmon_cfgs(5); + let node_cfgs = create_node_cfgs(5, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, None]); + let nodes = create_network(5, &node_cfgs, &node_chanmgrs); + let _chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0); + let chan_2_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 2, 0, 200_000, 0); + let chan_3_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 3, 0, 300_000, 0); + let chan_4_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 4, 0, 400_000, 0); + + // When no single channel has enough inbound capacity for the payment, we expect the three + // highest inbound channels to be chosen. + let mut scid_aliases = HashSet::new(); + scid_aliases.insert(chan_2_0.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_3_0.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_4_0.0.short_channel_id_alias.unwrap()); + + match_invoice_routes(Some(1_000_000_000), &nodes[0], scid_aliases.clone()); + } + + #[test] + fn test_sufficient_inbound_sort_by_lowest_capacity() { + let chanmon_cfgs = create_chanmon_cfgs(5); + let node_cfgs = create_node_cfgs(5, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, None]); + let nodes = create_network(5, &node_cfgs, &node_chanmgrs); + let chan_1_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0); + let chan_2_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 2, 0, 200_000, 0); + let chan_3_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 3, 0, 300_000, 0); + let _chan_4_0 = create_unannounced_chan_between_nodes_with_value(&nodes, 4, 0, 400_000, 0); + + // When we have channels that have sufficient inbound for the payment, test that we sort + // by lowest inbound capacity. + let mut scid_aliases = HashSet::new(); + scid_aliases.insert(chan_1_0.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_2_0.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_3_0.0.short_channel_id_alias.unwrap()); + + match_invoice_routes(Some(50_000_000), &nodes[0], scid_aliases.clone()); + } + #[test] fn test_forwarding_info_not_assigned_channel_excluded_from_hints() { let chanmon_cfgs = create_chanmon_cfgs(3); @@ -1118,8 +1294,8 @@ mod test { let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key(), invoice.min_final_cltv_expiry_delta() as u32) - .with_features(invoice.features().unwrap().clone()) - .with_route_hints(invoice.route_hints()); + .with_bolt11_features(invoice.features().unwrap().clone()).unwrap() + .with_route_hints(invoice.route_hints()).unwrap(); let params = RouteParameters { payment_params, final_value_msat: invoice.amount_milli_satoshis().unwrap(), @@ -1459,7 +1635,7 @@ mod test { #[test] #[cfg(feature = "std")] - fn test_multi_node_hints_has_only_highest_inbound_capacity_channel() { + fn test_multi_node_hints_has_only_lowest_inbound_channel_above_minimum() { let mut chanmon_cfgs = create_chanmon_cfgs(3); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; @@ -1470,17 +1646,17 @@ mod test { 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); - let chan_0_1_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0); - let _chan_0_1_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0); + let _chan_0_1_below_amt = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0); + let _chan_0_1_above_amt_high_inbound = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 500_000, 0); + let chan_0_1_above_amt_low_inbound = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 180_000, 0); let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001); let mut scid_aliases = HashSet::new(); - scid_aliases.insert(chan_0_1_high_inbound_capacity.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_0_1_above_amt_low_inbound.0.short_channel_id_alias.unwrap()); scid_aliases.insert(chan_0_2.0.short_channel_id_alias.unwrap()); match_multi_node_invoice_routes( - Some(10_000), + Some(100_000_000), &nodes[1], vec![&nodes[1], &nodes[2],], scid_aliases, @@ -1562,7 +1738,98 @@ mod test { ); } - #[cfg(feature = "std")] + #[test] + fn test_multi_node_hints_limited_to_3() { + let mut chanmon_cfgs = create_chanmon_cfgs(6); + let seed_1 = [42 as u8; 32]; + let seed_2 = [43 as u8; 32]; + let seed_3 = [44 as u8; 32]; + let seed_4 = [45 as u8; 32]; + let cross_node_seed = [44 as u8; 32]; + chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); + chanmon_cfgs[3].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[4].keys_manager.backing = PhantomKeysManager::new(&seed_3, 43, 44, &cross_node_seed); + chanmon_cfgs[5].keys_manager.backing = PhantomKeysManager::new(&seed_4, 43, 44, &cross_node_seed); + let node_cfgs = create_node_cfgs(6, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &[None, None, None, None, None, None]); + let nodes = create_network(6, &node_cfgs, &node_chanmgrs); + + // Setup each phantom node with two channels from distinct peers. + let chan_0_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 10_000, 0); + let chan_1_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 20_000, 0); + let chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 20_000, 0); + let _chan_1_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 3, 10_000, 0); + let chan_0_4 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 4, 20_000, 0); + let _chan_1_4 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000, 0); + let _chan_0_5 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 5, 20_000, 0); + let _chan_1_5 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000, 0); + + // Set invoice amount > all channels inbound so that every one is eligible for inclusion + // and hints will be sorted by largest inbound capacity. + let invoice_amt = Some(100_000_000); + + // With 4 phantom nodes, assert that we include 1 hint per node, up to 3 nodes. + let mut scid_aliases = HashSet::new(); + scid_aliases.insert(chan_1_2.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_0_3.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_0_4.0.short_channel_id_alias.unwrap()); + + match_multi_node_invoice_routes( + invoice_amt, + &nodes[3], + vec![&nodes[2], &nodes[3], &nodes[4], &nodes[5]], + scid_aliases, + false, + ); + + // With 2 phantom nodes, assert that we include no more than 3 hints. + let mut scid_aliases = HashSet::new(); + scid_aliases.insert(chan_1_2.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_0_3.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_0_2.0.short_channel_id_alias.unwrap()); + + match_multi_node_invoice_routes( + invoice_amt, + &nodes[3], + vec![&nodes[2], &nodes[3]], + scid_aliases, + false, + ); + } + + #[test] + fn test_multi_node_hints_at_least_3() { + let mut chanmon_cfgs = create_chanmon_cfgs(5); + let seed_1 = [42 as u8; 32]; + let seed_2 = [43 as u8; 32]; + let cross_node_seed = [44 as u8; 32]; + chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); + chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + let node_cfgs = create_node_cfgs(5, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, None]); + let nodes = create_network(5, &node_cfgs, &node_chanmgrs); + + let _chan_0_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 3, 10_000, 0); + let chan_1_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 3, 20_000, 0); + let chan_2_3 = create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 30_000, 0); + let chan_0_4 = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 4, 10_000, 0); + + // Since the invoice amount is above all channels inbound, all four are eligible. Test that + // we still include 3 hints from 2 distinct nodes sorted by inbound. + let mut scid_aliases = HashSet::new(); + scid_aliases.insert(chan_1_3.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_2_3.0.short_channel_id_alias.unwrap()); + scid_aliases.insert(chan_0_4.0.short_channel_id_alias.unwrap()); + + match_multi_node_invoice_routes( + Some(100_000_000), + &nodes[3], + vec![&nodes[3], &nodes[4],], + scid_aliases, + false, + ); + } + fn match_multi_node_invoice_routes<'a, 'b: 'a, 'c: 'b>( invoice_amt: Option, invoice_node: &Node<'a, 'b, 'c>, diff --git a/lightning-net-tokio/Cargo.toml b/lightning-net-tokio/Cargo.toml index 6250628d2..a0fdcf839 100644 --- a/lightning-net-tokio/Cargo.toml +++ b/lightning-net-tokio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-net-tokio" -version = "0.0.114" +version = "0.0.115" authors = ["Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/lightningdevkit/rust-lightning/" @@ -16,9 +16,9 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] bitcoin = "0.29.0" -lightning = { version = "0.0.114", path = "../lightning" } +lightning = { version = "0.0.115", path = "../lightning" } tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] } [dev-dependencies] tokio = { version = "1.14", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] } -lightning = { version = "0.0.114", path = "../lightning", features = ["_test_utils"] } +lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] } diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index 48f1736d0..2f0c96396 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -36,12 +36,10 @@ use tokio::{io, time}; use tokio::sync::mpsc; use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use lightning::chain::keysinterface::NodeSigner; use lightning::ln::peer_handler; use lightning::ln::peer_handler::SocketDescriptor as LnSocketTrait; -use lightning::ln::peer_handler::CustomMessageHandler; -use lightning::ln::msgs::{ChannelMessageHandler, NetAddress, OnionMessageHandler, RoutingMessageHandler}; -use lightning::util::logger::Logger; +use lightning::ln::peer_handler::APeerManager; +use lightning::ln::msgs::NetAddress; use std::ops::Deref; use std::task; @@ -80,53 +78,25 @@ struct Connection { id: u64, } impl Connection { - async fn poll_event_process( + async fn poll_event_process( peer_manager: PM, mut event_receiver: mpsc::Receiver<()>, - ) where - PM: Deref> + 'static + Send + Sync, - CMH: Deref + 'static + Send + Sync, - RMH: Deref + 'static + Send + Sync, - OMH: Deref + 'static + Send + Sync, - L: Deref + 'static + Send + Sync, - UMH: Deref + 'static + Send + Sync, - NS: Deref + 'static + Send + Sync, - CMH::Target: ChannelMessageHandler + Send + Sync, - RMH::Target: RoutingMessageHandler + Send + Sync, - OMH::Target: OnionMessageHandler + Send + Sync, - L::Target: Logger + Send + Sync, - UMH::Target: CustomMessageHandler + Send + Sync, - NS::Target: NodeSigner + Send + Sync, - { + ) where PM::Target: APeerManager { loop { if event_receiver.recv().await.is_none() { return; } - peer_manager.process_events(); + peer_manager.as_ref().process_events(); } } - async fn schedule_read( + async fn schedule_read( peer_manager: PM, us: Arc>, mut reader: io::ReadHalf, mut read_wake_receiver: mpsc::Receiver<()>, mut write_avail_receiver: mpsc::Receiver<()>, - ) where - PM: Deref> + 'static + Send + Sync + Clone, - CMH: Deref + 'static + Send + Sync, - RMH: Deref + 'static + Send + Sync, - OMH: Deref + 'static + Send + Sync, - L: Deref + 'static + Send + Sync, - UMH: Deref + 'static + Send + Sync, - NS: Deref + 'static + Send + Sync, - CMH::Target: ChannelMessageHandler + 'static + Send + Sync, - RMH::Target: RoutingMessageHandler + 'static + Send + Sync, - OMH::Target: OnionMessageHandler + 'static + Send + Sync, - L::Target: Logger + 'static + Send + Sync, - UMH::Target: CustomMessageHandler + 'static + Send + Sync, - NS::Target: NodeSigner + 'static + Send + Sync, - { + ) where PM::Target: APeerManager { // Create a waker to wake up poll_event_process, above let (event_waker, event_receiver) = mpsc::channel(1); tokio::spawn(Self::poll_event_process(peer_manager.clone(), event_receiver)); @@ -160,7 +130,7 @@ impl Connection { tokio::select! { v = write_avail_receiver.recv() => { assert!(v.is_some()); // We can't have dropped the sending end, its in the us Arc! - if peer_manager.write_buffer_space_avail(&mut our_descriptor).is_err() { + if peer_manager.as_ref().write_buffer_space_avail(&mut our_descriptor).is_err() { break Disconnect::CloseConnection; } }, @@ -168,7 +138,7 @@ impl Connection { read = reader.read(&mut buf), if !read_paused => match read { Ok(0) => break Disconnect::PeerDisconnected, Ok(len) => { - let read_res = peer_manager.read_event(&mut our_descriptor, &buf[0..len]); + let read_res = peer_manager.as_ref().read_event(&mut our_descriptor, &buf[0..len]); let mut us_lock = us.lock().unwrap(); match read_res { Ok(pause_read) => { @@ -197,8 +167,8 @@ impl Connection { let _ = writer.shutdown().await; } if let Disconnect::PeerDisconnected = disconnect_type { - peer_manager.socket_disconnected(&our_descriptor); - peer_manager.process_events(); + peer_manager.as_ref().socket_disconnected(&our_descriptor); + peer_manager.as_ref().process_events(); } } @@ -245,30 +215,17 @@ fn get_addr_from_stream(stream: &StdTcpStream) -> Option { /// The returned future will complete when the peer is disconnected and associated handling /// futures are freed, though, because all processing futures are spawned with tokio::spawn, you do /// not need to poll the provided future in order to make progress. -pub fn setup_inbound( +pub fn setup_inbound( peer_manager: PM, stream: StdTcpStream, -) -> impl std::future::Future where - PM: Deref> + 'static + Send + Sync + Clone, - CMH: Deref + 'static + Send + Sync, - RMH: Deref + 'static + Send + Sync, - OMH: Deref + 'static + Send + Sync, - L: Deref + 'static + Send + Sync, - UMH: Deref + 'static + Send + Sync, - NS: Deref + 'static + Send + Sync, - CMH::Target: ChannelMessageHandler + Send + Sync, - RMH::Target: RoutingMessageHandler + Send + Sync, - OMH::Target: OnionMessageHandler + Send + Sync, - L::Target: Logger + Send + Sync, - UMH::Target: CustomMessageHandler + Send + Sync, - NS::Target: NodeSigner + Send + Sync, -{ +) -> impl std::future::Future +where PM::Target: APeerManager { let remote_addr = get_addr_from_stream(&stream); let (reader, write_receiver, read_receiver, us) = Connection::new(stream); #[cfg(test)] let last_us = Arc::clone(&us); - let handle_opt = if peer_manager.new_inbound_connection(SocketDescriptor::new(us.clone()), remote_addr).is_ok() { + let handle_opt = if peer_manager.as_ref().new_inbound_connection(SocketDescriptor::new(us.clone()), remote_addr).is_ok() { Some(tokio::spawn(Connection::schedule_read(peer_manager, us, reader, read_receiver, write_receiver))) } else { // Note that we will skip socket_disconnected here, in accordance with the PeerManager @@ -300,30 +257,17 @@ pub fn setup_inbound( /// The returned future will complete when the peer is disconnected and associated handling /// futures are freed, though, because all processing futures are spawned with tokio::spawn, you do /// not need to poll the provided future in order to make progress. -pub fn setup_outbound( +pub fn setup_outbound( peer_manager: PM, their_node_id: PublicKey, stream: StdTcpStream, -) -> impl std::future::Future where - PM: Deref> + 'static + Send + Sync + Clone, - CMH: Deref + 'static + Send + Sync, - RMH: Deref + 'static + Send + Sync, - OMH: Deref + 'static + Send + Sync, - L: Deref + 'static + Send + Sync, - UMH: Deref + 'static + Send + Sync, - NS: Deref + 'static + Send + Sync, - CMH::Target: ChannelMessageHandler + Send + Sync, - RMH::Target: RoutingMessageHandler + Send + Sync, - OMH::Target: OnionMessageHandler + Send + Sync, - L::Target: Logger + Send + Sync, - UMH::Target: CustomMessageHandler + Send + Sync, - NS::Target: NodeSigner + Send + Sync, -{ +) -> impl std::future::Future +where PM::Target: APeerManager { let remote_addr = get_addr_from_stream(&stream); let (reader, mut write_receiver, read_receiver, us) = Connection::new(stream); #[cfg(test)] let last_us = Arc::clone(&us); - let handle_opt = if let Ok(initial_send) = peer_manager.new_outbound_connection(their_node_id, SocketDescriptor::new(us.clone()), remote_addr) { + let handle_opt = if let Ok(initial_send) = peer_manager.as_ref().new_outbound_connection(their_node_id, SocketDescriptor::new(us.clone()), remote_addr) { Some(tokio::spawn(async move { // We should essentially always have enough room in a TCP socket buffer to send the // initial 10s of bytes. However, tokio running in single-threaded mode will always @@ -342,7 +286,7 @@ pub fn setup_outbound( }, _ => { eprintln!("Failed to write first full message to socket!"); - peer_manager.socket_disconnected(&SocketDescriptor::new(Arc::clone(&us))); + peer_manager.as_ref().socket_disconnected(&SocketDescriptor::new(Arc::clone(&us))); break Err(()); } } @@ -385,25 +329,12 @@ pub fn setup_outbound( /// disconnected and associated handling futures are freed, though, because all processing in said /// futures are spawned with tokio::spawn, you do not need to poll the second future in order to /// make progress. -pub async fn connect_outbound( +pub async fn connect_outbound( peer_manager: PM, their_node_id: PublicKey, addr: SocketAddr, -) -> Option> where - PM: Deref> + 'static + Send + Sync + Clone, - CMH: Deref + 'static + Send + Sync, - RMH: Deref + 'static + Send + Sync, - OMH: Deref + 'static + Send + Sync, - L: Deref + 'static + Send + Sync, - UMH: Deref + 'static + Send + Sync, - NS: Deref + 'static + Send + Sync, - CMH::Target: ChannelMessageHandler + Send + Sync, - RMH::Target: RoutingMessageHandler + Send + Sync, - OMH::Target: OnionMessageHandler + Send + Sync, - L::Target: Logger + Send + Sync, - UMH::Target: CustomMessageHandler + Send + Sync, - NS::Target: NodeSigner + Send + Sync, -{ +) -> Option> +where PM::Target: APeerManager { if let Ok(Ok(stream)) = time::timeout(Duration::from_secs(10), async { TcpStream::connect(&addr).await.map(|s| s.into_std().unwrap()) }).await { Some(setup_outbound(peer_manager, their_node_id, stream)) } else { None } @@ -598,6 +529,17 @@ mod tests { fn handle_update_fee(&self, _their_node_id: &PublicKey, _msg: &UpdateFee) {} fn handle_announcement_signatures(&self, _their_node_id: &PublicKey, _msg: &AnnouncementSignatures) {} fn handle_channel_update(&self, _their_node_id: &PublicKey, _msg: &ChannelUpdate) {} + fn handle_open_channel_v2(&self, _their_node_id: &PublicKey, _msg: &OpenChannelV2) {} + fn handle_accept_channel_v2(&self, _their_node_id: &PublicKey, _msg: &AcceptChannelV2) {} + fn handle_tx_add_input(&self, _their_node_id: &PublicKey, _msg: &TxAddInput) {} + fn handle_tx_add_output(&self, _their_node_id: &PublicKey, _msg: &TxAddOutput) {} + fn handle_tx_remove_input(&self, _their_node_id: &PublicKey, _msg: &TxRemoveInput) {} + fn handle_tx_remove_output(&self, _their_node_id: &PublicKey, _msg: &TxRemoveOutput) {} + fn handle_tx_complete(&self, _their_node_id: &PublicKey, _msg: &TxComplete) {} + fn handle_tx_signatures(&self, _their_node_id: &PublicKey, _msg: &TxSignatures) {} + fn handle_tx_init_rbf(&self, _their_node_id: &PublicKey, _msg: &TxInitRbf) {} + fn handle_tx_ack_rbf(&self, _their_node_id: &PublicKey, _msg: &TxAckRbf) {} + fn handle_tx_abort(&self, _their_node_id: &PublicKey, _msg: &TxAbort) {} fn peer_disconnected(&self, their_node_id: &PublicKey) { if *their_node_id == self.expected_pubkey { self.disconnected_flag.store(true, Ordering::SeqCst); @@ -659,7 +601,8 @@ mod tests { chan_handler: Arc::clone(&a_handler), route_handler: Arc::clone(&a_handler), onion_message_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), - }, 0, &[1; 32], Arc::new(TestLogger()), Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), Arc::new(TestNodeSigner::new(a_key)))); + custom_message_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), + }, 0, &[1; 32], Arc::new(TestLogger()), Arc::new(TestNodeSigner::new(a_key)))); let (b_connected_sender, mut b_connected) = mpsc::channel(1); let (b_disconnected_sender, mut b_disconnected) = mpsc::channel(1); @@ -674,7 +617,8 @@ mod tests { chan_handler: Arc::clone(&b_handler), route_handler: Arc::clone(&b_handler), onion_message_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), - }, 0, &[2; 32], Arc::new(TestLogger()), Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), Arc::new(TestNodeSigner::new(b_key)))); + custom_message_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), + }, 0, &[2; 32], Arc::new(TestLogger()), Arc::new(TestNodeSigner::new(b_key)))); // We bind on localhost, hoping the environment is properly configured with a local // address. This may not always be the case in containers and the like, so if this test is @@ -727,7 +671,8 @@ mod tests { chan_handler: Arc::new(lightning::ln::peer_handler::ErroringMessageHandler::new()), onion_message_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), route_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), - }, 0, &[1; 32], Arc::new(TestLogger()), Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), Arc::new(TestNodeSigner::new(a_key)))); + custom_message_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler{}), + }, 0, &[1; 32], Arc::new(TestLogger()), Arc::new(TestNodeSigner::new(a_key)))); // Make two connections, one for an inbound and one for an outbound connection let conn_a = { diff --git a/lightning-persister/Cargo.toml b/lightning-persister/Cargo.toml index 01415f29f..88132bdcf 100644 --- a/lightning-persister/Cargo.toml +++ b/lightning-persister/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-persister" -version = "0.0.114" +version = "0.0.115" authors = ["Valentine Wallace", "Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/lightningdevkit/rust-lightning/" @@ -18,11 +18,11 @@ _bench_unstable = ["lightning/_bench_unstable"] [dependencies] bitcoin = "0.29.0" -lightning = { version = "0.0.114", path = "../lightning" } +lightning = { version = "0.0.115", path = "../lightning" } libc = "0.2" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["winbase"] } [dev-dependencies] -lightning = { version = "0.0.114", path = "../lightning", features = ["_test_utils"] } +lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] } diff --git a/lightning-persister/src/lib.rs b/lightning-persister/src/lib.rs index e6687fef7..d1a1e4a29 100644 --- a/lightning-persister/src/lib.rs +++ b/lightning-persister/src/lib.rs @@ -20,7 +20,7 @@ extern crate libc; use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::hashes::hex::FromHex; use lightning::chain::channelmonitor::ChannelMonitor; -use lightning::chain::keysinterface::{EntropySource, SignerProvider}; +use lightning::sign::{EntropySource, SignerProvider}; use lightning::util::ser::{ReadableArgs, Writeable}; use lightning::util::persist::KVStorePersister; use std::fs; @@ -136,9 +136,8 @@ mod tests { extern crate lightning; extern crate bitcoin; use crate::FilesystemPersister; - use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::hashes::hex::FromHex; - use bitcoin::{Txid, TxMerkleNode}; + use bitcoin::Txid; use lightning::chain::ChannelMonitorUpdateStatus; use lightning::chain::chainmonitor::Persist; use lightning::chain::channelmonitor::CLOSED_CHANNEL_UPDATE_ID; @@ -148,7 +147,6 @@ mod tests { use lightning::ln::functional_test_utils::*; use lightning::util::test_utils; use std::fs; - use bitcoin::hashes::Hash; #[cfg(target_os = "windows")] use { lightning::get_event_msg, @@ -247,8 +245,7 @@ mod tests { let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn.len(), 1); - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[0].clone()]}); + connect_block(&nodes[1], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![node_txn[0].clone(), node_txn[0].clone()])); check_closed_broadcast!(nodes[1], true); check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed); check_added_monitors!(nodes[1], 1); diff --git a/lightning-rapid-gossip-sync/Cargo.toml b/lightning-rapid-gossip-sync/Cargo.toml index 1f0f6f038..6673431d9 100644 --- a/lightning-rapid-gossip-sync/Cargo.toml +++ b/lightning-rapid-gossip-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-rapid-gossip-sync" -version = "0.0.114" +version = "0.0.115" authors = ["Arik Sosman "] license = "MIT OR Apache-2.0" repository = "https://github.com/lightningdevkit/rust-lightning" @@ -16,8 +16,8 @@ std = ["lightning/std"] _bench_unstable = [] [dependencies] -lightning = { version = "0.0.114", path = "../lightning", default-features = false } +lightning = { version = "0.0.115", path = "../lightning", default-features = false } bitcoin = { version = "0.29.0", default-features = false } [dev-dependencies] -lightning = { version = "0.0.114", path = "../lightning", features = ["_test_utils"] } +lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] } diff --git a/lightning-transaction-sync/Cargo.toml b/lightning-transaction-sync/Cargo.toml index 7b72a00e6..2e9e13296 100644 --- a/lightning-transaction-sync/Cargo.toml +++ b/lightning-transaction-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-transaction-sync" -version = "0.0.114" +version = "0.0.115" authors = ["Elias Rohrer"] license = "MIT OR Apache-2.0" repository = "http://github.com/lightningdevkit/rust-lightning" @@ -21,7 +21,7 @@ esplora-blocking = ["esplora-client/blocking"] async-interface = [] [dependencies] -lightning = { version = "0.0.114", path = "../lightning", default-features = false } +lightning = { version = "0.0.115", path = "../lightning", default-features = false } bitcoin = { version = "0.29.0", default-features = false } bdk-macros = "0.6" futures = { version = "0.3", optional = true } @@ -29,7 +29,7 @@ esplora-client = { version = "0.4", default-features = false, optional = true } reqwest = { version = "0.11", optional = true, default-features = false, features = ["json"] } [dev-dependencies] -lightning = { version = "0.0.114", path = "../lightning", features = ["std"] } +lightning = { version = "0.0.115", path = "../lightning", features = ["std"] } electrsd = { version = "0.22.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_23_0"] } electrum-client = "0.12.0" tokio = { version = "1.14.0", features = ["full"] } diff --git a/lightning-transaction-sync/src/lib.rs b/lightning-transaction-sync/src/lib.rs index 05b71d21b..ca3ce3f8a 100644 --- a/lightning-transaction-sync/src/lib.rs +++ b/lightning-transaction-sync/src/lib.rs @@ -13,7 +13,8 @@ //! //! ## Version Compatibility //! -//! Currently this crate is compatible with nodes that were created with LDK version 0.0.113 and above. +//! Currently this crate is compatible with LDK version 0.0.114 and above using channels which were +//! created on LDK version 0.0.113 and above. //! //! ## Usage Example: //! diff --git a/lightning/Cargo.toml b/lightning/Cargo.toml index 32755a7e4..1804be0f1 100644 --- a/lightning/Cargo.toml +++ b/lightning/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning" -version = "0.0.114" +version = "0.0.115" authors = ["Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/lightningdevkit/rust-lightning/" diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index 2cd03b8b8..97d3a408c 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -15,7 +15,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey}; -use crate::chain::keysinterface::{EntropySource, NodeSigner, Recipient}; +use crate::sign::{EntropySource, NodeSigner, Recipient}; use crate::onion_message::ControlTlvs; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index e7c2b0f18..261e5593b 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -31,7 +31,7 @@ use crate::chain::{ChannelMonitorUpdateStatus, Filter, WatchedOutput}; use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, Balance, MonitorEvent, TransactionOutputs, LATENCY_GRACE_PERIOD_BLOCKS}; use crate::chain::transaction::{OutPoint, TransactionData}; -use crate::chain::keysinterface::WriteableEcdsaChannelSigner; +use crate::sign::WriteableEcdsaChannelSigner; use crate::events; use crate::events::{Event, EventHandler}; use crate::util::atomic_counter::AtomicCounter; @@ -825,8 +825,6 @@ impl ChannelMonitorImpl { return Some(Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: htlc.amount_msat / 1000, claimable_height: htlc.cltv_expiry, + payment_hash: htlc.payment_hash, }); } - } else if self.payment_preimages.get(&htlc.payment_hash).is_some() { + } else if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) { // Otherwise (the payment was inbound), only expose it as claimable if // we know the preimage. // Note that if there is a pending claim, but it did not use the @@ -1641,12 +1650,15 @@ impl ChannelMonitorImpl { return Some(Balance::ContentiousClaimable { claimable_amount_satoshis: htlc.amount_msat / 1000, timeout_height: htlc.cltv_expiry, + payment_hash: htlc.payment_hash, + payment_preimage: *payment_preimage, }); } } else if htlc_resolved.is_none() { return Some(Balance::MaybePreimageClaimableHTLC { claimable_amount_satoshis: htlc.amount_msat / 1000, expiry_height: htlc.cltv_expiry, + payment_hash: htlc.payment_hash, }); } None @@ -1808,6 +1820,7 @@ impl ChannelMonitor { res.push(Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: htlc.amount_msat / 1000, claimable_height: htlc.cltv_expiry, + payment_hash: htlc.payment_hash, }); } else if us.payment_preimages.get(&htlc.payment_hash).is_some() { claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000; @@ -1817,6 +1830,7 @@ impl ChannelMonitor { res.push(Balance::MaybePreimageClaimableHTLC { claimable_amount_satoshis: htlc.amount_msat / 1000, expiry_height: htlc.cltv_expiry, + payment_hash: htlc.payment_hash, }); } } @@ -2325,8 +2339,16 @@ impl ChannelMonitorImpl { F::Target: FeeEstimator, L::Target: Logger, { - log_info!(logger, "Applying update to monitor {}, bringing update_id from {} to {} with {} changes.", - log_funding_info!(self), self.latest_update_id, updates.update_id, updates.updates.len()); + if self.latest_update_id == CLOSED_CHANNEL_UPDATE_ID && updates.update_id == CLOSED_CHANNEL_UPDATE_ID { + log_info!(logger, "Applying post-force-closed update to monitor {} with {} change(s).", + log_funding_info!(self), updates.updates.len()); + } else if updates.update_id == CLOSED_CHANNEL_UPDATE_ID { + log_info!(logger, "Applying force close update to monitor {} with {} change(s).", + log_funding_info!(self), updates.updates.len()); + } else { + log_info!(logger, "Applying update to monitor {}, bringing update_id from {} to {} with {} change(s).", + log_funding_info!(self), self.latest_update_id, updates.update_id, updates.updates.len()); + } // ChannelMonitor updates may be applied after force close if we receive a preimage for a // broadcasted commitment transaction HTLC output that we'd like to claim on-chain. If this // is the case, we no longer have guaranteed access to the monitor's update ID, so we use a @@ -2393,6 +2415,7 @@ impl ChannelMonitorImpl { _ => false, }).is_some(); if detected_funding_spend { + log_trace!(logger, "Avoiding commitment broadcast, already detected confirmed spend onchain"); continue; } self.broadcast_latest_holder_commitment_txn(broadcaster, logger); @@ -2408,7 +2431,7 @@ impl ChannelMonitorImpl { 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, + best_block_height, best_block_height ); self.onchain_tx_handler.update_claims_view_from_requests( vec![commitment_package], best_block_height, best_block_height, @@ -2443,7 +2466,9 @@ impl ChannelMonitorImpl { self.latest_update_id = updates.update_id; - if ret.is_ok() && self.funding_spend_seen { + // Refuse updates after we've detected a spend onchain, but only if we haven't processed a + // force closed monitor update yet. + if ret.is_ok() && self.funding_spend_seen && self.latest_update_id != CLOSED_CHANNEL_UPDATE_ID { log_error!(logger, "Refusing Channel Monitor Update as counterparty attempted to update commitment after funding was spent"); Err(()) } else { ret } @@ -2589,8 +2614,8 @@ impl ChannelMonitorImpl { // First, process non-htlc outputs (to_holder & to_counterparty) for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { - let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv); - let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, true, height); + let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv, self.onchain_tx_handler.opt_anchors()); + let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, height); claimable_outpoints.push(justice_package); to_counterparty_output_info = Some((idx.try_into().expect("Txn can't have more than 2^32 outputs"), outp.value)); @@ -2608,7 +2633,7 @@ impl ChannelMonitorImpl { to_counterparty_output_info); } let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_some()); - let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, true, height); + let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, height); claimable_outpoints.push(justice_package); } } @@ -2733,8 +2758,7 @@ impl ChannelMonitorImpl { self.counterparty_commitment_params.counterparty_htlc_base_key, 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 counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry, 0); claimable_outpoints.push(counterparty_package); } } @@ -2773,11 +2797,12 @@ impl ChannelMonitorImpl { let revk_outp = RevokedOutput::build( per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, - tx.output[idx].value, self.counterparty_commitment_params.on_counterparty_tx_csv + tx.output[idx].value, self.counterparty_commitment_params.on_counterparty_tx_csv, + false ); let justice_package = PackageTemplate::build_package( htlc_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), - height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, true, height + height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, height ); claimable_outpoints.push(justice_package); if outputs_to_watch.is_none() { @@ -2800,11 +2825,11 @@ impl ChannelMonitorImpl { for &(ref htlc, _, _) in holder_tx.htlc_outputs.iter() { if let Some(transaction_output_index) = htlc.transaction_output_index { - let (htlc_output, aggregable) = if htlc.offered { + let htlc_output = if htlc.offered { let htlc_output = HolderHTLCOutput::build_offered( htlc.amount_msat, htlc.cltv_expiry, self.onchain_tx_handler.opt_anchors() ); - (htlc_output, false) + htlc_output } else { let payment_preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) { preimage.clone() @@ -2815,12 +2840,12 @@ impl ChannelMonitorImpl { let htlc_output = HolderHTLCOutput::build_accepted( payment_preimage, htlc.amount_msat, self.onchain_tx_handler.opt_anchors() ); - (htlc_output, self.onchain_tx_handler.opt_anchors()) + htlc_output }; let htlc_package = PackageTemplate::build_package( holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), - htlc.cltv_expiry, aggregable, conf_height + htlc.cltv_expiry, conf_height ); claim_requests.push(htlc_package); } @@ -3160,7 +3185,7 @@ impl ChannelMonitorImpl { let should_broadcast = self.should_broadcast_holder_commitment_txn(logger); if should_broadcast { 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()); + 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(), 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); @@ -4059,7 +4084,6 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP #[cfg(test)] mod tests { - use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, EcdsaSighashType}; @@ -4083,7 +4107,7 @@ mod tests { use crate::chain::channelmonitor::ChannelMonitor; use crate::chain::package::{weight_offered_htlc, weight_received_htlc, weight_revoked_offered_htlc, weight_revoked_received_htlc, WEIGHT_REVOKED_OUTPUT}; use crate::chain::transaction::OutPoint; - use crate::chain::keysinterface::InMemorySigner; + use crate::sign::InMemorySigner; use crate::events::ClosureReason; use crate::ln::{PaymentPreimage, PaymentHash}; use crate::ln::chan_utils; @@ -4096,7 +4120,7 @@ mod tests { use crate::util::ser::{ReadableArgs, Writeable}; use crate::sync::{Arc, Mutex}; use crate::io; - use bitcoin::{PackedLockTime, Sequence, TxMerkleNode, Witness}; + use bitcoin::{PackedLockTime, Sequence, Witness}; use crate::prelude::*; fn do_test_funding_spend_refuses_updates(use_local_txn: bool) { @@ -4135,10 +4159,7 @@ mod tests { // Connect a commitment transaction, but only to the ChainMonitor/ChannelMonitor. The // channel is now closed, but the ChannelManager doesn't know that yet. - let new_header = BlockHeader { - version: 2, time: 0, bits: 0, nonce: 0, - prev_blockhash: nodes[0].best_block_info().0, - merkle_root: TxMerkleNode::all_zeros() }; + let new_header = create_dummy_header(nodes[0].best_block_info().0, 0); let conf_height = nodes[0].best_block_info().1 + 1; nodes[1].chain_monitor.chain_monitor.transactions_confirmed(&new_header, &[(0, broadcast_tx)], conf_height); diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs deleted file mode 100644 index b1290708b..000000000 --- a/lightning/src/chain/keysinterface.rs +++ /dev/null @@ -1,1579 +0,0 @@ -// This file is Copyright its original authors, visible in version control -// history. -// -// This file is licensed under the Apache License, Version 2.0 or the MIT license -// , at your option. -// You may not use this file except in accordance with one or both of these -// licenses. - -//! Provides keys to LDK and defines some useful objects describing spendable on-chain outputs. -//! -//! The provided output descriptors follow a custom LDK data format and are currently not fully -//! compatible with Bitcoin Core output descriptors. - -use bitcoin::blockdata::transaction::{Transaction, TxOut, TxIn, EcdsaSighashType}; -use bitcoin::blockdata::script::{Script, Builder}; -use bitcoin::blockdata::opcodes; -use bitcoin::network::constants::Network; -use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber}; -use bitcoin::util::sighash; - -use bitcoin::bech32::u5; -use bitcoin::hashes::{Hash, HashEngine}; -use bitcoin::hashes::sha256::Hash as Sha256; -use bitcoin::hashes::sha256d::Hash as Sha256dHash; -use bitcoin::hash_types::WPubkeyHash; - -use bitcoin::secp256k1::{SecretKey, PublicKey, Scalar}; -use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature, Signing}; -use bitcoin::secp256k1::ecdh::SharedSecret; -use bitcoin::secp256k1::ecdsa::RecoverableSignature; -use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; - -use crate::util::transaction_utils; -use crate::util::crypto::{hkdf_extract_expand_twice, sign, sign_with_aux_rand}; -use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs}; -use crate::chain::transaction::OutPoint; -#[cfg(anchors)] -use crate::events::bump_transaction::HTLCDescriptor; -use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; -use crate::ln::{chan_utils, PaymentPreimage}; -use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction}; -use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; -use crate::ln::script::ShutdownScript; - -use crate::prelude::*; -use core::convert::TryInto; -use core::ops::Deref; -use core::sync::atomic::{AtomicUsize, Ordering}; -use crate::io::{self, Error}; -use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; -use crate::util::atomic_counter::AtomicCounter; -use crate::util::chacha20::ChaCha20; -use crate::util::invoice::construct_invoice_preimage; - -/// Used as initial key material, to be expanded into multiple secret keys (but not to be used -/// directly). This is used within LDK to encrypt/decrypt inbound payment data. -/// -/// This is not exported to bindings users as we just use `[u8; 32]` directly -#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] -pub struct KeyMaterial(pub [u8; 32]); - -/// Information about a spendable output to a P2WSH script. -/// -/// See [`SpendableOutputDescriptor::DelayedPaymentOutput`] for more details on how to spend this. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DelayedPaymentOutputDescriptor { - /// The outpoint which is spendable. - pub outpoint: OutPoint, - /// Per commitment point to derive the delayed payment key by key holder. - pub per_commitment_point: PublicKey, - /// The `nSequence` value which must be set in the spending input to satisfy the `OP_CSV` in - /// the witness_script. - pub to_self_delay: u16, - /// The output which is referenced by the given outpoint. - pub output: TxOut, - /// The revocation point specific to the commitment transaction which was broadcast. Used to - /// derive the witnessScript for this output. - pub revocation_pubkey: PublicKey, - /// Arbitrary identification information returned by a call to [`ChannelSigner::channel_keys_id`]. - /// This may be useful in re-deriving keys used in the channel to spend the output. - pub channel_keys_id: [u8; 32], - /// The value of the channel which this output originated from, possibly indirectly. - pub channel_value_satoshis: u64, -} -impl DelayedPaymentOutputDescriptor { - /// The maximum length a well-formed witness spending one of these should have. - // Calculated as 1 byte length + 73 byte signature, 1 byte empty vec push, 1 byte length plus - // redeemscript push length. - pub const MAX_WITNESS_LENGTH: usize = 1 + 73 + 1 + chan_utils::REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH + 1; -} - -impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, { - (0, outpoint, required), - (2, per_commitment_point, required), - (4, to_self_delay, required), - (6, output, required), - (8, revocation_pubkey, required), - (10, channel_keys_id, required), - (12, channel_value_satoshis, required), -}); - -/// Information about a spendable output to our "payment key". -/// -/// See [`SpendableOutputDescriptor::StaticPaymentOutput`] for more details on how to spend this. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct StaticPaymentOutputDescriptor { - /// The outpoint which is spendable. - pub outpoint: OutPoint, - /// The output which is referenced by the given outpoint. - pub output: TxOut, - /// Arbitrary identification information returned by a call to [`ChannelSigner::channel_keys_id`]. - /// This may be useful in re-deriving keys used in the channel to spend the output. - pub channel_keys_id: [u8; 32], - /// The value of the channel which this transactions spends. - pub channel_value_satoshis: u64, -} -impl StaticPaymentOutputDescriptor { - /// The maximum length a well-formed witness spending one of these should have. - // Calculated as 1 byte legnth + 73 byte signature, 1 byte empty vec push, 1 byte length plus - // redeemscript push length. - pub const MAX_WITNESS_LENGTH: usize = 1 + 73 + 34; -} -impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, { - (0, outpoint, required), - (2, output, required), - (4, channel_keys_id, required), - (6, channel_value_satoshis, required), -}); - -/// Describes the necessary information to spend a spendable output. -/// -/// When on-chain outputs are created by LDK (which our counterparty is not able to claim at any -/// point in the future) a [`SpendableOutputs`] event is generated which you must track and be able -/// to 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. -/// -/// [`SpendableOutputs`]: crate::events::Event::SpendableOutputs -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum SpendableOutputDescriptor { - /// An output to a script which was provided via [`SignerProvider`] directly, either from - /// [`get_destination_script`] or [`get_shutdown_scriptpubkey`], thus you should already - /// know how to spend it. No secret keys are provided as LDK was never given any key. - /// These may include outputs from a transaction punishing our counterparty or claiming an HTLC - /// on-chain using the payment preimage or after it has timed out. - /// - /// [`get_shutdown_scriptpubkey`]: SignerProvider::get_shutdown_scriptpubkey - /// [`get_destination_script`]: SignerProvider::get_shutdown_scriptpubkey - StaticOutput { - /// The outpoint which is spendable. - outpoint: OutPoint, - /// The output which is referenced by the given outpoint. - output: TxOut, - }, - /// An output to a P2WSH script which can be spent with a single signature after an `OP_CSV` - /// delay. - /// - /// The witness in the spending input should be: - /// ```bitcoin - /// (MINIMALIF standard rule) - /// ``` - /// - /// Note that the `nSequence` field in the spending input must be set to - /// [`DelayedPaymentOutputDescriptor::to_self_delay`] (which means the transaction is not - /// broadcastable until at least [`DelayedPaymentOutputDescriptor::to_self_delay`] blocks after - /// the outpoint confirms, see [BIP - /// 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki)). Also note that LDK - /// won't generate a [`SpendableOutputDescriptor`] until the corresponding block height - /// is reached. - /// - /// These are generally the result of a "revocable" output to us, spendable only by us unless - /// it is an output from an old state which we broadcast (which should never happen). - /// - /// To derive the delayed payment key which is used to sign this input, you must pass the - /// holder [`InMemorySigner::delayed_payment_base_key`] (i.e., the private key which corresponds to the - /// [`ChannelPublicKeys::delayed_payment_basepoint`] in [`ChannelSigner::pubkeys`]) and the provided - /// [`DelayedPaymentOutputDescriptor::per_commitment_point`] to [`chan_utils::derive_private_key`]. The public key can be - /// generated without the secret key using [`chan_utils::derive_public_key`] and only the - /// [`ChannelPublicKeys::delayed_payment_basepoint`] which appears in [`ChannelSigner::pubkeys`]. - /// - /// To derive the [`DelayedPaymentOutputDescriptor::revocation_pubkey`] provided here (which is - /// used in the witness script generation), you must pass the counterparty - /// [`ChannelPublicKeys::revocation_basepoint`] (which appears in the call to - /// [`ChannelSigner::provide_channel_parameters`]) and the provided - /// [`DelayedPaymentOutputDescriptor::per_commitment_point`] to - /// [`chan_utils::derive_public_revocation_key`]. - /// - /// The witness script which is hashed and included in the output `script_pubkey` may be - /// regenerated by passing the [`DelayedPaymentOutputDescriptor::revocation_pubkey`] (derived - /// as explained above), our delayed payment pubkey (derived as explained above), and the - /// [`DelayedPaymentOutputDescriptor::to_self_delay`] contained here to - /// [`chan_utils::get_revokeable_redeemscript`]. - DelayedPaymentOutput(DelayedPaymentOutputDescriptor), - /// An output to a P2WPKH, spendable exclusively by our payment key (i.e., the private key - /// which corresponds to the `payment_point` in [`ChannelSigner::pubkeys`]). The witness - /// in the spending input is, thus, simply: - /// ```bitcoin - /// - /// ``` - /// - /// These are generally the result of our counterparty having broadcast the current state, - /// allowing us to claim the non-HTLC-encumbered outputs immediately. - StaticPaymentOutput(StaticPaymentOutputDescriptor), -} - -impl_writeable_tlv_based_enum!(SpendableOutputDescriptor, - (0, StaticOutput) => { - (0, outpoint, required), - (2, output, required), - }, -; - (1, DelayedPaymentOutput), - (2, StaticPaymentOutput), -); - -/// A trait to handle Lightning channel key material without concretizing the channel type or -/// the signature mechanism. -pub trait ChannelSigner { - /// Gets the per-commitment point for a specific commitment number - /// - /// Note that the commitment number starts at `(1 << 48) - 1` and counts backwards. - fn get_per_commitment_point(&self, idx: u64, secp_ctx: &Secp256k1) -> PublicKey; - - /// Gets the commitment secret for a specific commitment number as part of the revocation process - /// - /// An external signer implementation should error here if the commitment was already signed - /// and should refuse to sign it in the future. - /// - /// May be called more than once for the same index. - /// - /// Note that the commitment number starts at `(1 << 48) - 1` and counts backwards. - // TODO: return a Result so we can signal a validation error - fn release_commitment_secret(&self, idx: u64) -> [u8; 32]; - - /// Validate the counterparty's signatures on the holder commitment transaction and HTLCs. - /// - /// This is required in order for the signer to make sure that releasing a commitment - /// secret won't leave us without a broadcastable holder transaction. - /// Policy checks should be implemented in this function, including checking the amount - /// sent to us and checking the HTLCs. - /// - /// The preimages of outgoing HTLCs that were fulfilled since the last commitment are provided. - /// A validating signer should ensure that an HTLC output is removed only when the matching - /// preimage is provided, or when the value to holder is restored. - /// - /// Note that all the relevant preimages will be provided, but there may also be additional - /// irrelevant or duplicate preimages. - fn validate_holder_commitment(&self, holder_tx: &HolderCommitmentTransaction, - preimages: Vec) -> Result<(), ()>; - - /// Returns the holder's channel public keys and basepoints. - fn pubkeys(&self) -> &ChannelPublicKeys; - - /// Returns an arbitrary identifier describing the set of keys which are provided back to you in - /// some [`SpendableOutputDescriptor`] types. This should be sufficient to identify this - /// [`EcdsaChannelSigner`] object uniquely and lookup or re-derive its keys. - fn channel_keys_id(&self) -> [u8; 32]; - - /// Set the counterparty static channel data, including basepoints, - /// `counterparty_selected`/`holder_selected_contest_delay` and funding outpoint. - /// - /// This data is static, and will never change for a channel once set. For a given [`ChannelSigner`] - /// instance, LDK will call this method exactly once - either immediately after construction - /// (not including if done via [`SignerProvider::read_chan_signer`]) or when the funding - /// information has been generated. - /// - /// channel_parameters.is_populated() MUST be true. - fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); -} - -/// A trait to sign Lightning channel transactions as described in -/// [BOLT 3](https://github.com/lightning/bolts/blob/master/03-transactions.md). -/// -/// Signing services could be implemented on a hardware wallet and should implement signing -/// policies in order to be secure. Please refer to the [VLS Policy -/// Controls](https://gitlab.com/lightning-signer/validating-lightning-signer/-/blob/main/docs/policy-controls.md) -/// for an example of such policies. -pub trait EcdsaChannelSigner: ChannelSigner { - /// Create a signature for a counterparty's commitment transaction and associated HTLC transactions. - /// - /// Note that if signing fails or is rejected, the channel will be force-closed. - /// - /// Policy checks should be implemented in this function, including checking the amount - /// sent to us and checking the HTLCs. - /// - /// The preimages of outgoing HTLCs that were fulfilled since the last commitment are provided. - /// A validating signer should ensure that an HTLC output is removed only when the matching - /// preimage is provided, or when the value to holder is restored. - /// - /// Note that all the relevant preimages will be provided, but there may also be additional - /// irrelevant or duplicate preimages. - // - // TODO: Document the things someone using this interface should enforce before signing. - fn sign_counterparty_commitment(&self, commitment_tx: &CommitmentTransaction, - preimages: Vec, secp_ctx: &Secp256k1 - ) -> Result<(Signature, Vec), ()>; - /// Validate the counterparty's revocation. - /// - /// This is required in order for the signer to make sure that the state has moved - /// forward and it is safe to sign the next counterparty commitment. - fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey) -> Result<(), ()>; - /// Creates a signature for a holder's commitment transaction and its claiming HTLC transactions. - /// - /// This will be called - /// - with a non-revoked `commitment_tx`. - /// - with the latest `commitment_tx` when we initiate a force-close. - /// - with the previous `commitment_tx`, just to get claiming HTLC - /// signatures, if we are reacting to a [`ChannelMonitor`] - /// [replica](https://github.com/lightningdevkit/rust-lightning/blob/main/GLOSSARY.md#monitor-replicas) - /// that decided to broadcast before it had been updated to the latest `commitment_tx`. - /// - /// This may be called multiple times for the same transaction. - /// - /// An external signer implementation should check that the commitment has not been revoked. - /// - /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor - // TODO: Document the things someone using this interface should enforce before signing. - fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, - secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()>; - /// Same as [`sign_holder_commitment_and_htlcs`], but exists only for tests to get access to - /// holder commitment transactions which will be broadcasted later, after the channel has moved - /// on to a newer state. Thus, needs its own method as [`sign_holder_commitment_and_htlcs`] may - /// enforce that we only ever get called once. - #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] - fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, - secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()>; - /// Create a signature for the given input in a transaction spending an HTLC transaction output - /// or a commitment transaction `to_local` output when our counterparty broadcasts an old state. - /// - /// A justice transaction may claim multiple outputs at the same time if timelocks are - /// similar, but only a signature for the input at index `input` should be signed for here. - /// It may be called multiple times for same output(s) if a fee-bump is needed with regards - /// to an upcoming timelock expiration. - /// - /// Amount is value of the output spent by this input, committed to in the BIP 143 signature. - /// - /// `per_commitment_key` is revocation secret which was provided by our counterparty when they - /// revoked the state which they eventually broadcast. It's not a _holder_ secret key and does - /// not allow the spending of any funds by itself (you need our holder `revocation_secret` to do - /// so). - fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, - per_commitment_key: &SecretKey, secp_ctx: &Secp256k1 - ) -> Result; - /// Create a signature for the given input in a transaction spending a commitment transaction - /// HTLC output when our counterparty broadcasts an old state. - /// - /// A justice transaction may claim multiple outputs at the same time if timelocks are - /// similar, but only a signature for the input at index `input` should be signed for here. - /// It may be called multiple times for same output(s) if a fee-bump is needed with regards - /// to an upcoming timelock expiration. - /// - /// `amount` is the value of the output spent by this input, committed to in the BIP 143 - /// signature. - /// - /// `per_commitment_key` is revocation secret which was provided by our counterparty when they - /// revoked the state which they eventually broadcast. It's not a _holder_ secret key and does - /// not allow the spending of any funds by itself (you need our holder revocation_secret to do - /// so). - /// - /// `htlc` holds HTLC elements (hash, timelock), thus changing the format of the witness script - /// (which is committed to in the BIP 143 signatures). - fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, - per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, - secp_ctx: &Secp256k1) -> Result; - #[cfg(anchors)] - /// Computes the signature for a commitment transaction's HTLC output used as an input within - /// `htlc_tx`, which spends the commitment transaction at index `input`. The signature returned - /// must be be computed using [`EcdsaSighashType::All`]. Note that this should only be used to - /// sign HTLC transactions from channels supporting anchor outputs after all additional - /// inputs/outputs have been added to the transaction. - /// - /// [`EcdsaSighashType::All`]: bitcoin::blockdata::transaction::EcdsaSighashType::All - fn sign_holder_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, - htlc_descriptor: &HTLCDescriptor, secp_ctx: &Secp256k1 - ) -> Result; - /// Create a signature for a claiming transaction for a HTLC output on a counterparty's commitment - /// transaction, either offered or received. - /// - /// Such a transaction may claim multiples offered outputs at same time if we know the - /// preimage for each when we create it, but only the input at index `input` should be - /// signed for here. It may be called multiple times for same output(s) if a fee-bump is - /// needed with regards to an upcoming timelock expiration. - /// - /// `witness_script` is either an offered or received script as defined in BOLT3 for HTLC - /// outputs. - /// - /// `amount` is value of the output spent by this input, committed to in the BIP 143 signature. - /// - /// `per_commitment_point` is the dynamic point corresponding to the channel state - /// detected onchain. It has been generated by our counterparty and is used to derive - /// channel state keys, which are then included in the witness script and committed to in the - /// BIP 143 signature. - fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, - per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, - secp_ctx: &Secp256k1) -> Result; - /// Create a signature for a (proposed) closing transaction. - /// - /// Note that, due to rounding, there may be one "missing" satoshi, and either party may have - /// chosen to forgo their output as dust. - fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, - secp_ctx: &Secp256k1) -> Result; - /// 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: &Transaction, input: usize, secp_ctx: &Secp256k1, - ) -> Result; - /// Signs a channel announcement message with our funding key proving it comes from one of the - /// channel participants. - /// - /// Channel announcements also require a signature from each node's network key. Our node - /// signature is computed through [`NodeSigner::sign_gossip_message`]. - /// - /// Note that if this fails or is rejected, the channel will not be publicly announced and - /// our counterparty may (though likely will not) close the channel on us for violating the - /// protocol. - fn sign_channel_announcement_with_funding_key( - &self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1 - ) -> Result; -} - -/// A writeable signer. -/// -/// There will always be two instances of a signer per channel, one occupied by the -/// [`ChannelManager`] and another by the channel's [`ChannelMonitor`]. -/// -/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager -/// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor -pub trait WriteableEcdsaChannelSigner: EcdsaChannelSigner + Writeable {} - -/// Specifies the recipient of an invoice. -/// -/// This indicates to [`NodeSigner::sign_invoice`] what node secret key should be used to sign -/// the invoice. -pub enum Recipient { - /// The invoice should be signed with the local node secret key. - Node, - /// The invoice should be signed with the phantom node secret key. This secret key must be the - /// same for all nodes participating in the [phantom node payment]. - /// - /// [phantom node payment]: PhantomKeysManager - PhantomNode, -} - -/// A trait that describes a source of entropy. -pub trait EntropySource { - /// Gets a unique, cryptographically-secure, random 32-byte value. This method must return a - /// different value each time it is called. - fn get_secure_random_bytes(&self) -> [u8; 32]; -} - -/// A trait that can handle cryptographic operations at the scope level of a node. -pub trait NodeSigner { - /// Get secret key material as bytes for use in encrypting and decrypting inbound payment data. - /// - /// If the implementor of this trait supports [phantom node payments], then every node that is - /// intended to be included in the phantom invoice route hints must return the same value from - /// this method. - // This is because LDK avoids storing inbound payment data by encrypting payment data in the - // payment hash and/or payment secret, therefore for a payment to be receivable by multiple - // nodes, they must share the key that encrypts this payment data. - /// - /// This method must return the same value each time it is called. - /// - /// [phantom node payments]: PhantomKeysManager - fn get_inbound_payment_key_material(&self) -> KeyMaterial; - - /// Get node id based on the provided [`Recipient`]. - /// - /// This method must return the same value each time it is called with a given [`Recipient`] - /// parameter. - /// - /// Errors if the [`Recipient`] variant is not supported by the implementation. - fn get_node_id(&self, recipient: Recipient) -> Result; - - /// Gets the ECDH shared secret of our node secret and `other_key`, multiplying by `tweak` if - /// one is provided. Note that this tweak can be applied to `other_key` instead of our node - /// secret, though this is less efficient. - /// - /// Note that if this fails while attempting to forward an HTLC, LDK will panic. The error - /// should be resolved to allow LDK to resume forwarding HTLCs. - /// - /// Errors if the [`Recipient`] variant is not supported by the implementation. - fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result; - - /// Sign an invoice. - /// - /// By parameterizing by the raw invoice bytes instead of the hash, we allow implementors of - /// this trait to parse the invoice and make sure they're signing what they expect, rather than - /// blindly signing the hash. - /// - /// The `hrp_bytes` are ASCII bytes, while the `invoice_data` is base32. - /// - /// The secret key used to sign the invoice is dependent on the [`Recipient`]. - /// - /// Errors if the [`Recipient`] variant is not supported by the implementation. - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result; - - /// Sign a gossip message. - /// - /// Note that if this fails, LDK may panic and the message will not be broadcast to the network - /// or a possible channel counterparty. If LDK panics, the error should be resolved to allow the - /// message to be broadcast, as otherwise it may prevent one from receiving funds over the - /// corresponding channel. - fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result; -} - -/// A trait that can return signer instances for individual channels. -pub trait SignerProvider { - /// A type which implements [`WriteableEcdsaChannelSigner`] which will be returned by [`Self::derive_channel_signer`]. - type Signer : WriteableEcdsaChannelSigner; - - /// Generates a unique `channel_keys_id` that can be used to obtain a [`Self::Signer`] through - /// [`SignerProvider::derive_channel_signer`]. The `user_channel_id` is provided to allow - /// implementations of [`SignerProvider`] to maintain a mapping between itself and the generated - /// `channel_keys_id`. - /// - /// This method must return a different value each time it is called. - fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32]; - - /// Derives the private key material backing a `Signer`. - /// - /// To derive a new `Signer`, a fresh `channel_keys_id` should be obtained through - /// [`SignerProvider::generate_channel_keys_id`]. Otherwise, an existing `Signer` can be - /// re-derived from its `channel_keys_id`, which can be obtained through its trait method - /// [`ChannelSigner::channel_keys_id`]. - fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer; - - /// Reads a [`Signer`] for this [`SignerProvider`] from the given input stream. - /// This is only called during deserialization of other objects which contain - /// [`WriteableEcdsaChannelSigner`]-implementing objects (i.e., [`ChannelMonitor`]s and [`ChannelManager`]s). - /// The bytes are exactly those which `::write()` writes, and - /// contain no versioning scheme. You may wish to include your own version prefix and ensure - /// you've read all of the provided bytes to ensure no corruption occurred. - /// - /// This method is slowly being phased out -- it will only be called when reading objects - /// written by LDK versions prior to 0.0.113. - /// - /// [`Signer`]: Self::Signer - /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor - /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager - fn read_chan_signer(&self, reader: &[u8]) -> Result; - - /// Get a script pubkey which we send funds to when claiming on-chain contestable outputs. - /// - /// This method should return a different value each time it is called, to avoid linking - /// on-chain funds across channels as controlled to the same user. - fn get_destination_script(&self) -> Script; - - /// Get a script pubkey which we will send funds to when closing a channel. - /// - /// This method should return a different value each time it is called, to avoid linking - /// on-chain funds across channels as controlled to the same user. - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript; -} - -/// A simple implementation of [`WriteableEcdsaChannelSigner`] that just keeps the private keys in memory. -/// -/// This implementation performs no policy checks and is insufficient by itself as -/// a secure external signer. -pub struct InMemorySigner { - /// Holder secret key in the 2-of-2 multisig script of a channel. This key also backs the - /// holder's anchor output in a commitment transaction, if one is present. - pub funding_key: SecretKey, - /// Holder secret key for blinded revocation pubkey. - pub revocation_base_key: SecretKey, - /// Holder secret key used for our balance in counterparty-broadcasted commitment transactions. - pub payment_key: SecretKey, - /// Holder secret key used in an HTLC transaction. - pub delayed_payment_base_key: SecretKey, - /// Holder HTLC secret key used in commitment transaction HTLC outputs. - pub htlc_base_key: SecretKey, - /// Commitment seed. - pub commitment_seed: [u8; 32], - /// Holder public keys and basepoints. - pub(crate) holder_channel_pubkeys: ChannelPublicKeys, - /// Counterparty public keys and counterparty/holder `selected_contest_delay`, populated on channel acceptance. - channel_parameters: Option, - /// The total value of this channel. - channel_value_satoshis: u64, - /// Key derivation parameters. - channel_keys_id: [u8; 32], - /// Seed from which all randomness produced is derived from. - rand_bytes_unique_start: [u8; 32], - /// Tracks the number of times we've produced randomness to ensure we don't return the same - /// bytes twice. - rand_bytes_index: AtomicCounter, -} - -impl Clone for InMemorySigner { - fn clone(&self) -> Self { - Self { - funding_key: self.funding_key.clone(), - revocation_base_key: self.revocation_base_key.clone(), - payment_key: self.payment_key.clone(), - delayed_payment_base_key: self.delayed_payment_base_key.clone(), - htlc_base_key: self.htlc_base_key.clone(), - commitment_seed: self.commitment_seed.clone(), - holder_channel_pubkeys: self.holder_channel_pubkeys.clone(), - channel_parameters: self.channel_parameters.clone(), - channel_value_satoshis: self.channel_value_satoshis, - channel_keys_id: self.channel_keys_id, - rand_bytes_unique_start: self.get_secure_random_bytes(), - rand_bytes_index: AtomicCounter::new(), - } - } -} - -impl InMemorySigner { - /// Creates a new [`InMemorySigner`]. - pub fn new( - secp_ctx: &Secp256k1, - funding_key: SecretKey, - revocation_base_key: SecretKey, - payment_key: SecretKey, - delayed_payment_base_key: SecretKey, - htlc_base_key: SecretKey, - commitment_seed: [u8; 32], - channel_value_satoshis: u64, - channel_keys_id: [u8; 32], - rand_bytes_unique_start: [u8; 32], - ) -> InMemorySigner { - let holder_channel_pubkeys = - InMemorySigner::make_holder_keys(secp_ctx, &funding_key, &revocation_base_key, - &payment_key, &delayed_payment_base_key, - &htlc_base_key); - InMemorySigner { - funding_key, - revocation_base_key, - payment_key, - delayed_payment_base_key, - htlc_base_key, - commitment_seed, - channel_value_satoshis, - holder_channel_pubkeys, - channel_parameters: None, - channel_keys_id, - rand_bytes_unique_start, - rand_bytes_index: AtomicCounter::new(), - } - } - - fn make_holder_keys(secp_ctx: &Secp256k1, - funding_key: &SecretKey, - revocation_base_key: &SecretKey, - payment_key: &SecretKey, - delayed_payment_base_key: &SecretKey, - htlc_base_key: &SecretKey) -> ChannelPublicKeys { - let from_secret = |s: &SecretKey| PublicKey::from_secret_key(secp_ctx, s); - ChannelPublicKeys { - funding_pubkey: from_secret(&funding_key), - revocation_basepoint: from_secret(&revocation_base_key), - payment_point: from_secret(&payment_key), - delayed_payment_basepoint: from_secret(&delayed_payment_base_key), - htlc_basepoint: from_secret(&htlc_base_key), - } - } - - /// Returns the counterparty's pubkeys. - /// - /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn counterparty_pubkeys(&self) -> &ChannelPublicKeys { &self.get_channel_parameters().counterparty_parameters.as_ref().unwrap().pubkeys } - /// Returns the `contest_delay` value specified by our counterparty and applied on holder-broadcastable - /// transactions, i.e., the amount of time that we have to wait to recover our funds if we - /// broadcast a transaction. - /// - /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn counterparty_selected_contest_delay(&self) -> u16 { self.get_channel_parameters().counterparty_parameters.as_ref().unwrap().selected_contest_delay } - /// Returns the `contest_delay` value specified by us and applied on transactions broadcastable - /// by our counterparty, i.e., the amount of time that they have to wait to recover their funds - /// if they broadcast a transaction. - /// - /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn holder_selected_contest_delay(&self) -> u16 { self.get_channel_parameters().holder_selected_contest_delay } - /// Returns whether the holder is the initiator. - /// - /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn is_outbound(&self) -> bool { self.get_channel_parameters().is_outbound_from_holder } - /// Funding outpoint - /// - /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn funding_outpoint(&self) -> &OutPoint { self.get_channel_parameters().funding_outpoint.as_ref().unwrap() } - /// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or - /// building transactions. - /// - /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn get_channel_parameters(&self) -> &ChannelTransactionParameters { - self.channel_parameters.as_ref().unwrap() - } - /// Returns whether anchors should be used. - /// - /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn opt_anchors(&self) -> bool { - self.get_channel_parameters().opt_anchors.is_some() - } - /// Sign the single input of `spend_tx` at index `input_idx`, which spends the output described - /// by `descriptor`, returning the witness stack for the input. - /// - /// Returns an error if the input at `input_idx` does not exist, has a non-empty `script_sig`, - /// is not spending the outpoint described by [`descriptor.outpoint`], - /// or if an output descriptor `script_pubkey` does not match the one we can spend. - /// - /// [`descriptor.outpoint`]: StaticPaymentOutputDescriptor::outpoint - pub fn sign_counterparty_payment_input(&self, spend_tx: &Transaction, input_idx: usize, descriptor: &StaticPaymentOutputDescriptor, secp_ctx: &Secp256k1) -> Result>, ()> { - // TODO: We really should be taking the SigHashCache as a parameter here instead of - // spend_tx, but ideally the SigHashCache would expose the transaction's inputs read-only - // so that we can check them. This requires upstream rust-bitcoin changes (as well as - // bindings updates to support SigHashCache objects). - if spend_tx.input.len() <= input_idx { return Err(()); } - if !spend_tx.input[input_idx].script_sig.is_empty() { return Err(()); } - if spend_tx.input[input_idx].previous_output != descriptor.outpoint.into_bitcoin_outpoint() { return Err(()); } - - let remotepubkey = self.pubkeys().payment_point; - let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Testnet).script_pubkey(); - let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]); - let remotesig = sign_with_aux_rand(secp_ctx, &sighash, &self.payment_key, &self); - let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey(); - - if payment_script != descriptor.output.script_pubkey { return Err(()); } - - let mut witness = Vec::with_capacity(2); - witness.push(remotesig.serialize_der().to_vec()); - witness[0].push(EcdsaSighashType::All as u8); - witness.push(remotepubkey.serialize().to_vec()); - Ok(witness) - } - - /// Sign the single input of `spend_tx` at index `input_idx` which spends the output - /// described by `descriptor`, returning the witness stack for the input. - /// - /// Returns an error if the input at `input_idx` does not exist, has a non-empty `script_sig`, - /// is not spending the outpoint described by [`descriptor.outpoint`], does not have a - /// sequence set to [`descriptor.to_self_delay`], or if an output descriptor - /// `script_pubkey` does not match the one we can spend. - /// - /// [`descriptor.outpoint`]: DelayedPaymentOutputDescriptor::outpoint - /// [`descriptor.to_self_delay`]: DelayedPaymentOutputDescriptor::to_self_delay - pub fn sign_dynamic_p2wsh_input(&self, spend_tx: &Transaction, input_idx: usize, descriptor: &DelayedPaymentOutputDescriptor, secp_ctx: &Secp256k1) -> Result>, ()> { - // TODO: We really should be taking the SigHashCache as a parameter here instead of - // spend_tx, but ideally the SigHashCache would expose the transaction's inputs read-only - // so that we can check them. This requires upstream rust-bitcoin changes (as well as - // bindings updates to support SigHashCache objects). - if spend_tx.input.len() <= input_idx { return Err(()); } - if !spend_tx.input[input_idx].script_sig.is_empty() { return Err(()); } - if spend_tx.input[input_idx].previous_output != descriptor.outpoint.into_bitcoin_outpoint() { return Err(()); } - if spend_tx.input[input_idx].sequence.0 != descriptor.to_self_delay as u32 { return Err(()); } - - let delayed_payment_key = chan_utils::derive_private_key(&secp_ctx, &descriptor.per_commitment_point, &self.delayed_payment_base_key); - let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key); - let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey); - let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]); - let local_delayedsig = sign_with_aux_rand(secp_ctx, &sighash, &delayed_payment_key, &self); - let payment_script = bitcoin::Address::p2wsh(&witness_script, Network::Bitcoin).script_pubkey(); - - if descriptor.output.script_pubkey != payment_script { return Err(()); } - - let mut witness = Vec::with_capacity(3); - witness.push(local_delayedsig.serialize_der().to_vec()); - witness[0].push(EcdsaSighashType::All as u8); - witness.push(vec!()); //MINIMALIF - witness.push(witness_script.clone().into_bytes()); - Ok(witness) - } -} - -impl EntropySource for InMemorySigner { - fn get_secure_random_bytes(&self) -> [u8; 32] { - let index = self.rand_bytes_index.get_increment(); - let mut nonce = [0u8; 16]; - nonce[..8].copy_from_slice(&index.to_be_bytes()); - ChaCha20::get_single_block(&self.rand_bytes_unique_start, &nonce) - } -} - -impl ChannelSigner for InMemorySigner { - fn get_per_commitment_point(&self, idx: u64, secp_ctx: &Secp256k1) -> PublicKey { - let commitment_secret = SecretKey::from_slice(&chan_utils::build_commitment_secret(&self.commitment_seed, idx)).unwrap(); - PublicKey::from_secret_key(secp_ctx, &commitment_secret) - } - - fn release_commitment_secret(&self, idx: u64) -> [u8; 32] { - chan_utils::build_commitment_secret(&self.commitment_seed, idx) - } - - fn validate_holder_commitment(&self, _holder_tx: &HolderCommitmentTransaction, _preimages: Vec) -> Result<(), ()> { - Ok(()) - } - - fn pubkeys(&self) -> &ChannelPublicKeys { &self.holder_channel_pubkeys } - - fn channel_keys_id(&self) -> [u8; 32] { self.channel_keys_id } - - fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { - assert!(self.channel_parameters.is_none() || self.channel_parameters.as_ref().unwrap() == channel_parameters); - if self.channel_parameters.is_some() { - // The channel parameters were already set and they match, return early. - return; - } - assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); - self.channel_parameters = Some(channel_parameters.clone()); - } -} - -impl EcdsaChannelSigner for InMemorySigner { - fn sign_counterparty_commitment(&self, commitment_tx: &CommitmentTransaction, _preimages: Vec, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()> { - let trusted_tx = commitment_tx.trust(); - let keys = trusted_tx.keys(); - - let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey); - - let built_tx = trusted_tx.built_transaction(); - let commitment_sig = built_tx.sign_counterparty_commitment(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx); - let commitment_txid = built_tx.txid; - - let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len()); - for htlc in commitment_tx.htlcs() { - let channel_parameters = self.get_channel_parameters(); - let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, self.opt_anchors(), channel_parameters.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys); - let htlc_sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; - let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]); - let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key); - htlc_sigs.push(sign(secp_ctx, &htlc_sighash, &holder_htlc_key)); - } - - Ok((commitment_sig, htlc_sigs)) - } - - fn validate_counterparty_revocation(&self, _idx: u64, _secret: &SecretKey) -> Result<(), ()> { - Ok(()) - } - - fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()> { - let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey); - let trusted_tx = commitment_tx.trust(); - let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx); - let channel_parameters = self.get_channel_parameters(); - let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?; - Ok((sig, htlc_sigs)) - } - - #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] - fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()> { - let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey); - let trusted_tx = commitment_tx.trust(); - let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx); - let channel_parameters = self.get_channel_parameters(); - let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?; - Ok((sig, htlc_sigs)) - } - - fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1) -> Result { - let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key); - let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); - let witness_script = { - let counterparty_delayedpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().delayed_payment_basepoint); - chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.holder_selected_contest_delay(), &counterparty_delayedpubkey) - }; - let mut sighash_parts = sighash::SighashCache::new(justice_tx); - let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); - return Ok(sign_with_aux_rand(secp_ctx, &sighash, &revocation_key, &self)) - } - - fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { - let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key); - let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); - let witness_script = { - let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint); - let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); - chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey) - }; - let mut sighash_parts = sighash::SighashCache::new(justice_tx); - let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); - return Ok(sign_with_aux_rand(secp_ctx, &sighash, &revocation_key, &self)) - } - - #[cfg(anchors)] - fn sign_holder_htlc_transaction( - &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, - secp_ctx: &Secp256k1 - ) -> Result { - let per_commitment_point = self.get_per_commitment_point( - htlc_descriptor.per_commitment_number, &secp_ctx - ); - let witness_script = htlc_descriptor.witness_script(&per_commitment_point, secp_ctx); - let sighash = &sighash::SighashCache::new(&*htlc_tx).segwit_signature_hash( - input, &witness_script, htlc_descriptor.htlc.amount_msat / 1000, EcdsaSighashType::All - ).map_err(|_| ())?; - let our_htlc_private_key = chan_utils::derive_private_key( - &secp_ctx, &per_commitment_point, &self.htlc_base_key - ); - Ok(sign_with_aux_rand(&secp_ctx, &hash_to_message!(sighash), &our_htlc_private_key, &self)) - } - - fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { - let htlc_key = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); - let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint); - let htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey); - let mut sighash_parts = sighash::SighashCache::new(htlc_tx); - let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); - Ok(sign_with_aux_rand(secp_ctx, &sighash, &htlc_key, &self)) - } - - fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1) -> Result { - let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey); - 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: &Transaction, input: usize, secp_ctx: &Secp256k1, - ) -> Result { - 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_with_aux_rand(secp_ctx, &hash_to_message!(&sighash[..]), &self.funding_key, &self)) - } - - fn sign_channel_announcement_with_funding_key( - &self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1 - ) -> Result { - let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); - Ok(secp_ctx.sign_ecdsa(&msghash, &self.funding_key)) - } -} - -const SERIALIZATION_VERSION: u8 = 1; - -const MIN_SERIALIZATION_VERSION: u8 = 1; - -impl WriteableEcdsaChannelSigner for InMemorySigner {} - -impl Writeable for InMemorySigner { - fn write(&self, writer: &mut W) -> Result<(), Error> { - write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); - - self.funding_key.write(writer)?; - self.revocation_base_key.write(writer)?; - self.payment_key.write(writer)?; - self.delayed_payment_base_key.write(writer)?; - self.htlc_base_key.write(writer)?; - self.commitment_seed.write(writer)?; - self.channel_parameters.write(writer)?; - self.channel_value_satoshis.write(writer)?; - self.channel_keys_id.write(writer)?; - - write_tlv_fields!(writer, {}); - - Ok(()) - } -} - -impl ReadableArgs for InMemorySigner where ES::Target: EntropySource { - fn read(reader: &mut R, entropy_source: ES) -> Result { - let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); - - let funding_key = Readable::read(reader)?; - let revocation_base_key = Readable::read(reader)?; - let payment_key = Readable::read(reader)?; - let delayed_payment_base_key = Readable::read(reader)?; - let htlc_base_key = Readable::read(reader)?; - let commitment_seed = Readable::read(reader)?; - let counterparty_channel_data = Readable::read(reader)?; - let channel_value_satoshis = Readable::read(reader)?; - let secp_ctx = Secp256k1::signing_only(); - let holder_channel_pubkeys = - InMemorySigner::make_holder_keys(&secp_ctx, &funding_key, &revocation_base_key, - &payment_key, &delayed_payment_base_key, &htlc_base_key); - let keys_id = Readable::read(reader)?; - - read_tlv_fields!(reader, {}); - - Ok(InMemorySigner { - funding_key, - revocation_base_key, - payment_key, - delayed_payment_base_key, - htlc_base_key, - commitment_seed, - channel_value_satoshis, - holder_channel_pubkeys, - channel_parameters: counterparty_channel_data, - channel_keys_id: keys_id, - rand_bytes_unique_start: entropy_source.get_secure_random_bytes(), - rand_bytes_index: AtomicCounter::new(), - }) - } -} - -/// Simple implementation of [`EntropySource`], [`NodeSigner`], and [`SignerProvider`] that takes a -/// 32-byte seed for use as a BIP 32 extended key and derives keys from that. -/// -/// Your `node_id` is seed/0'. -/// Unilateral closes may use seed/1'. -/// Cooperative closes may use seed/2'. -/// The two close keys may be needed to claim on-chain funds! -/// -/// This struct cannot be used for nodes that wish to support receiving phantom payments; -/// [`PhantomKeysManager`] must be used instead. -/// -/// Note that switching between this struct and [`PhantomKeysManager`] will invalidate any -/// previously issued invoices and attempts to pay previous invoices will fail. -pub struct KeysManager { - secp_ctx: Secp256k1, - node_secret: SecretKey, - node_id: PublicKey, - inbound_payment_key: KeyMaterial, - destination_script: Script, - shutdown_pubkey: PublicKey, - channel_master_key: ExtendedPrivKey, - channel_child_index: AtomicUsize, - - rand_bytes_unique_start: [u8; 32], - rand_bytes_index: AtomicCounter, - - seed: [u8; 32], - starting_time_secs: u64, - starting_time_nanos: u32, -} - -impl KeysManager { - /// Constructs a [`KeysManager`] from a 32-byte seed. If the seed is in some way biased (e.g., - /// your CSRNG is busted) this may panic (but more importantly, you will possibly lose funds). - /// `starting_time` isn't strictly required to actually be a time, but it must absolutely, - /// without a doubt, be unique to this instance. ie if you start multiple times with the same - /// `seed`, `starting_time` must be unique to each run. Thus, the easiest way to achieve this - /// is to simply use the current time (with very high precision). - /// - /// The `seed` MUST be backed up safely prior to use so that the keys can be re-created, however, - /// obviously, `starting_time` should be unique every time you reload the library - it is only - /// used to generate new ephemeral key data (which will be stored by the individual channel if - /// necessary). - /// - /// Note that the seed is required to recover certain on-chain funds independent of - /// [`ChannelMonitor`] data, though a current copy of [`ChannelMonitor`] data is also required - /// for any channel, and some on-chain during-closing funds. - /// - /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor - pub fn new(seed: &[u8; 32], starting_time_secs: u64, starting_time_nanos: u32) -> Self { - let secp_ctx = Secp256k1::new(); - // Note that when we aren't serializing the key, network doesn't matter - match ExtendedPrivKey::new_master(Network::Testnet, seed) { - Ok(master_key) => { - let node_secret = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(0).unwrap()).expect("Your RNG is busted").private_key; - let node_id = PublicKey::from_secret_key(&secp_ctx, &node_secret); - let destination_script = match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(1).unwrap()) { - Ok(destination_key) => { - let wpubkey_hash = WPubkeyHash::hash(&ExtendedPubKey::from_priv(&secp_ctx, &destination_key).to_pub().to_bytes()); - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0) - .push_slice(&wpubkey_hash.into_inner()) - .into_script() - }, - Err(_) => panic!("Your RNG is busted"), - }; - let shutdown_pubkey = match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(2).unwrap()) { - Ok(shutdown_key) => ExtendedPubKey::from_priv(&secp_ctx, &shutdown_key).public_key, - Err(_) => panic!("Your RNG is busted"), - }; - let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3).unwrap()).expect("Your RNG is busted"); - let inbound_payment_key: SecretKey = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5).unwrap()).expect("Your RNG is busted").private_key; - let mut inbound_pmt_key_bytes = [0; 32]; - inbound_pmt_key_bytes.copy_from_slice(&inbound_payment_key[..]); - - let mut rand_bytes_engine = Sha256::engine(); - rand_bytes_engine.input(&starting_time_secs.to_be_bytes()); - rand_bytes_engine.input(&starting_time_nanos.to_be_bytes()); - rand_bytes_engine.input(seed); - rand_bytes_engine.input(b"LDK PRNG Seed"); - let rand_bytes_unique_start = Sha256::from_engine(rand_bytes_engine).into_inner(); - - let mut res = KeysManager { - secp_ctx, - node_secret, - node_id, - inbound_payment_key: KeyMaterial(inbound_pmt_key_bytes), - - destination_script, - shutdown_pubkey, - - channel_master_key, - channel_child_index: AtomicUsize::new(0), - - rand_bytes_unique_start, - rand_bytes_index: AtomicCounter::new(), - - seed: *seed, - starting_time_secs, - starting_time_nanos, - }; - let secp_seed = res.get_secure_random_bytes(); - res.secp_ctx.seeded_randomize(&secp_seed); - res - }, - Err(_) => panic!("Your rng is busted"), - } - } - - /// Gets the "node_id" secret key used to sign gossip announcements, decode onion data, etc. - pub fn get_node_secret_key(&self) -> SecretKey { - self.node_secret - } - - /// Derive an old [`WriteableEcdsaChannelSigner`] containing per-channel secrets based on a key derivation parameters. - pub fn derive_channel_keys(&self, channel_value_satoshis: u64, params: &[u8; 32]) -> InMemorySigner { - let chan_id = u64::from_be_bytes(params[0..8].try_into().unwrap()); - let mut unique_start = Sha256::engine(); - unique_start.input(params); - unique_start.input(&self.seed); - - // We only seriously intend to rely on the channel_master_key for true secure - // entropy, everything else just ensures uniqueness. We rely on the unique_start (ie - // starting_time provided in the constructor) to be unique. - let child_privkey = self.channel_master_key.ckd_priv(&self.secp_ctx, - ChildNumber::from_hardened_idx((chan_id as u32) % (1 << 31)).expect("key space exhausted") - ).expect("Your RNG is busted"); - unique_start.input(&child_privkey.private_key[..]); - - let seed = Sha256::from_engine(unique_start).into_inner(); - - let commitment_seed = { - let mut sha = Sha256::engine(); - sha.input(&seed); - sha.input(&b"commitment seed"[..]); - Sha256::from_engine(sha).into_inner() - }; - macro_rules! key_step { - ($info: expr, $prev_key: expr) => {{ - let mut sha = Sha256::engine(); - sha.input(&seed); - sha.input(&$prev_key[..]); - sha.input(&$info[..]); - SecretKey::from_slice(&Sha256::from_engine(sha).into_inner()).expect("SHA-256 is busted") - }} - } - let funding_key = key_step!(b"funding key", commitment_seed); - let revocation_base_key = key_step!(b"revocation base key", funding_key); - let payment_key = key_step!(b"payment key", revocation_base_key); - let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_key); - let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key); - let prng_seed = self.get_secure_random_bytes(); - - InMemorySigner::new( - &self.secp_ctx, - funding_key, - revocation_base_key, - payment_key, - delayed_payment_base_key, - htlc_base_key, - commitment_seed, - channel_value_satoshis, - params.clone(), - prng_seed, - ) - } - - /// Creates a [`Transaction`] which spends the given descriptors to the given outputs, plus an - /// output to the given change destination (if sufficient change value remains). The - /// transaction will have a feerate, at least, of the given value. - /// - /// Returns `Err(())` if the output value is greater than the input value minus required fee, - /// if a descriptor was duplicated, or if an output descriptor `script_pubkey` - /// does not match the one we can spend. - /// - /// We do not enforce that outputs meet the dust limit or that any output scripts are standard. - /// - /// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used - /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`]. - pub fn spend_spendable_outputs(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: Script, feerate_sat_per_1000_weight: u32, secp_ctx: &Secp256k1) -> Result { - let mut input = Vec::new(); - let mut input_value = 0; - let mut witness_weight = 0; - let mut output_set = HashSet::with_capacity(descriptors.len()); - for outp in descriptors { - match outp { - SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => { - input.push(TxIn { - previous_output: descriptor.outpoint.into_bitcoin_outpoint(), - script_sig: Script::new(), - sequence: Sequence::ZERO, - witness: Witness::new(), - }); - witness_weight += StaticPaymentOutputDescriptor::MAX_WITNESS_LENGTH; - input_value += descriptor.output.value; - if !output_set.insert(descriptor.outpoint) { return Err(()); } - }, - SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => { - input.push(TxIn { - previous_output: descriptor.outpoint.into_bitcoin_outpoint(), - script_sig: Script::new(), - sequence: Sequence(descriptor.to_self_delay as u32), - witness: Witness::new(), - }); - witness_weight += DelayedPaymentOutputDescriptor::MAX_WITNESS_LENGTH; - input_value += descriptor.output.value; - if !output_set.insert(descriptor.outpoint) { return Err(()); } - }, - SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => { - input.push(TxIn { - previous_output: outpoint.into_bitcoin_outpoint(), - script_sig: Script::new(), - sequence: Sequence::ZERO, - witness: Witness::new(), - }); - witness_weight += 1 + 73 + 34; - input_value += output.value; - if !output_set.insert(*outpoint) { return Err(()); } - } - } - if input_value > MAX_VALUE_MSAT / 1000 { return Err(()); } - } - let mut spend_tx = Transaction { - version: 2, - lock_time: PackedLockTime(0), - input, - output: outputs, - }; - let expected_max_weight = - transaction_utils::maybe_add_change_output(&mut spend_tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?; - - let mut keys_cache: Option<(InMemorySigner, [u8; 32])> = None; - let mut input_idx = 0; - for outp in descriptors { - match outp { - SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => { - if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id { - keys_cache = Some(( - self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id), - descriptor.channel_keys_id)); - } - spend_tx.input[input_idx].witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?); - }, - SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => { - if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id { - keys_cache = Some(( - self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id), - descriptor.channel_keys_id)); - } - spend_tx.input[input_idx].witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_dynamic_p2wsh_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?); - }, - SpendableOutputDescriptor::StaticOutput { ref output, .. } => { - let derivation_idx = if output.script_pubkey == self.destination_script { - 1 - } else { - 2 - }; - let secret = { - // Note that when we aren't serializing the key, network doesn't matter - match ExtendedPrivKey::new_master(Network::Testnet, &self.seed) { - Ok(master_key) => { - match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(derivation_idx).expect("key space exhausted")) { - Ok(key) => key, - Err(_) => panic!("Your RNG is busted"), - } - } - Err(_) => panic!("Your rng is busted"), - } - }; - let pubkey = ExtendedPubKey::from_priv(&secp_ctx, &secret).to_pub(); - if derivation_idx == 2 { - assert_eq!(pubkey.inner, self.shutdown_pubkey); - } - let witness_script = bitcoin::Address::p2pkh(&pubkey, Network::Testnet).script_pubkey(); - let payment_script = bitcoin::Address::p2wpkh(&pubkey, Network::Testnet).expect("uncompressed key found").script_pubkey(); - - if payment_script != output.script_pubkey { return Err(()); }; - - let sighash = hash_to_message!(&sighash::SighashCache::new(&spend_tx).segwit_signature_hash(input_idx, &witness_script, output.value, EcdsaSighashType::All).unwrap()[..]); - let sig = sign_with_aux_rand(secp_ctx, &sighash, &secret.private_key, &self); - let mut sig_ser = sig.serialize_der().to_vec(); - sig_ser.push(EcdsaSighashType::All as u8); - spend_tx.input[input_idx].witness.push(sig_ser); - spend_tx.input[input_idx].witness.push(pubkey.inner.serialize().to_vec()); - }, - } - input_idx += 1; - } - - debug_assert!(expected_max_weight >= spend_tx.weight()); - // Note that witnesses with a signature vary somewhat in size, so allow - // `expected_max_weight` to overshoot by up to 3 bytes per input. - debug_assert!(expected_max_weight <= spend_tx.weight() + descriptors.len() * 3); - - Ok(spend_tx) - } -} - -impl EntropySource for KeysManager { - fn get_secure_random_bytes(&self) -> [u8; 32] { - let index = self.rand_bytes_index.get_increment(); - let mut nonce = [0u8; 16]; - nonce[..8].copy_from_slice(&index.to_be_bytes()); - ChaCha20::get_single_block(&self.rand_bytes_unique_start, &nonce) - } -} - -impl NodeSigner for KeysManager { - fn get_node_id(&self, recipient: Recipient) -> Result { - match recipient { - Recipient::Node => Ok(self.node_id.clone()), - Recipient::PhantomNode => Err(()) - } - } - - fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { - let mut node_secret = match recipient { - Recipient::Node => Ok(self.node_secret.clone()), - Recipient::PhantomNode => Err(()) - }?; - if let Some(tweak) = tweak { - node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; - } - Ok(SharedSecret::new(other_key, &node_secret)) - } - - fn get_inbound_payment_key_material(&self) -> KeyMaterial { - self.inbound_payment_key.clone() - } - - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { - let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); - let secret = match recipient { - Recipient::Node => Ok(&self.node_secret), - Recipient::PhantomNode => Err(()) - }?; - Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), secret)) - } - - fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result { - let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); - Ok(self.secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret)) - } -} - -impl SignerProvider for KeysManager { - type Signer = InMemorySigner; - - fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { - let child_idx = self.channel_child_index.fetch_add(1, Ordering::AcqRel); - // `child_idx` is the only thing guaranteed to make each channel unique without a restart - // (though `user_channel_id` should help, depending on user behavior). If it manages to - // roll over, we may generate duplicate keys for two different channels, which could result - // in loss of funds. Because we only support 32-bit+ systems, assert that our `AtomicUsize` - // doesn't reach `u32::MAX`. - assert!(child_idx < core::u32::MAX as usize, "2^32 channels opened without restart"); - let mut id = [0; 32]; - id[0..4].copy_from_slice(&(child_idx as u32).to_be_bytes()); - id[4..8].copy_from_slice(&self.starting_time_nanos.to_be_bytes()); - id[8..16].copy_from_slice(&self.starting_time_secs.to_be_bytes()); - id[16..32].copy_from_slice(&user_channel_id.to_be_bytes()); - id - } - - fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer { - self.derive_channel_keys(channel_value_satoshis, &channel_keys_id) - } - - fn read_chan_signer(&self, reader: &[u8]) -> Result { - InMemorySigner::read(&mut io::Cursor::new(reader), self) - } - - fn get_destination_script(&self) -> Script { - self.destination_script.clone() - } - - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone()) - } -} - -/// Similar to [`KeysManager`], but allows the node using this struct to receive phantom node -/// payments. -/// -/// A phantom node payment is a payment made to a phantom invoice, which is an invoice that can be -/// paid to one of multiple nodes. This works because we encode the invoice route hints such that -/// LDK will recognize an incoming payment as destined for a phantom node, and collect the payment -/// itself without ever needing to forward to this fake node. -/// -/// Phantom node payments are useful for load balancing between multiple LDK nodes. They also -/// provide some fault tolerance, because payers will automatically retry paying other provided -/// nodes in the case that one node goes down. -/// -/// Note that multi-path payments are not supported in phantom invoices for security reasons. -// In the hypothetical case that we did support MPP phantom payments, there would be no way for -// nodes to know when the full payment has been received (and the preimage can be released) without -// significantly compromising on our safety guarantees. I.e., if we expose the ability for the user -// to tell LDK when the preimage can be released, we open ourselves to attacks where the preimage -// is released too early. -// -/// Switching between this struct and [`KeysManager`] will invalidate any previously issued -/// invoices and attempts to pay previous invoices will fail. -pub struct PhantomKeysManager { - inner: KeysManager, - inbound_payment_key: KeyMaterial, - phantom_secret: SecretKey, - phantom_node_id: PublicKey, -} - -impl EntropySource for PhantomKeysManager { - fn get_secure_random_bytes(&self) -> [u8; 32] { - self.inner.get_secure_random_bytes() - } -} - -impl NodeSigner for PhantomKeysManager { - fn get_node_id(&self, recipient: Recipient) -> Result { - match recipient { - Recipient::Node => self.inner.get_node_id(Recipient::Node), - Recipient::PhantomNode => Ok(self.phantom_node_id.clone()), - } - } - - fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { - let mut node_secret = match recipient { - Recipient::Node => self.inner.node_secret.clone(), - Recipient::PhantomNode => self.phantom_secret.clone(), - }; - if let Some(tweak) = tweak { - node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; - } - Ok(SharedSecret::new(other_key, &node_secret)) - } - - fn get_inbound_payment_key_material(&self) -> KeyMaterial { - self.inbound_payment_key.clone() - } - - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { - let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); - let secret = match recipient { - Recipient::Node => &self.inner.node_secret, - Recipient::PhantomNode => &self.phantom_secret, - }; - Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), secret)) - } - - fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result { - self.inner.sign_gossip_message(msg) - } -} - -impl SignerProvider for PhantomKeysManager { - type Signer = InMemorySigner; - - fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { - self.inner.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) - } - - fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer { - self.inner.derive_channel_signer(channel_value_satoshis, channel_keys_id) - } - - fn read_chan_signer(&self, reader: &[u8]) -> Result { - self.inner.read_chan_signer(reader) - } - - fn get_destination_script(&self) -> Script { - self.inner.get_destination_script() - } - - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - self.inner.get_shutdown_scriptpubkey() - } -} - -impl PhantomKeysManager { - /// Constructs a [`PhantomKeysManager`] given a 32-byte seed and an additional `cross_node_seed` - /// that is shared across all nodes that intend to participate in [phantom node payments] - /// together. - /// - /// See [`KeysManager::new`] for more information on `seed`, `starting_time_secs`, and - /// `starting_time_nanos`. - /// - /// `cross_node_seed` must be the same across all phantom payment-receiving nodes and also the - /// same across restarts, or else inbound payments may fail. - /// - /// [phantom node payments]: PhantomKeysManager - pub fn new(seed: &[u8; 32], starting_time_secs: u64, starting_time_nanos: u32, cross_node_seed: &[u8; 32]) -> Self { - let inner = KeysManager::new(seed, starting_time_secs, starting_time_nanos); - let (inbound_key, phantom_key) = hkdf_extract_expand_twice(b"LDK Inbound and Phantom Payment Key Expansion", cross_node_seed); - let phantom_secret = SecretKey::from_slice(&phantom_key).unwrap(); - let phantom_node_id = PublicKey::from_secret_key(&inner.secp_ctx, &phantom_secret); - Self { - inner, - inbound_payment_key: KeyMaterial(inbound_key), - phantom_secret, - phantom_node_id, - } - } - - /// See [`KeysManager::spend_spendable_outputs`] for documentation on this method. - pub fn spend_spendable_outputs(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: Script, feerate_sat_per_1000_weight: u32, secp_ctx: &Secp256k1) -> Result { - self.inner.spend_spendable_outputs(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, secp_ctx) - } - - /// See [`KeysManager::derive_channel_keys`] for documentation on this method. - pub fn derive_channel_keys(&self, channel_value_satoshis: u64, params: &[u8; 32]) -> InMemorySigner { - self.inner.derive_channel_keys(channel_value_satoshis, params) - } - - /// Gets the "node_id" secret key used to sign gossip announcements, decode onion data, etc. - pub fn get_node_secret_key(&self) -> SecretKey { - self.inner.get_node_secret_key() - } - - /// Gets the "node_id" secret key of the phantom node used to sign invoices, decode the - /// last-hop onion data, etc. - pub fn get_phantom_node_secret_key(&self) -> SecretKey { - self.phantom_secret - } -} - -// Ensure that EcdsaChannelSigner can have a vtable -#[test] -pub fn dyn_sign() { - let _signer: Box; -} - -#[cfg(all(test, feature = "_bench_unstable", not(feature = "no-std")))] -mod benches { - use std::sync::{Arc, mpsc}; - use std::sync::mpsc::TryRecvError; - use std::thread; - use std::time::Duration; - use bitcoin::blockdata::constants::genesis_block; - use bitcoin::Network; - use crate::chain::keysinterface::{EntropySource, KeysManager}; - - use test::Bencher; - - #[bench] - fn bench_get_secure_random_bytes(bench: &mut Bencher) { - let seed = [0u8; 32]; - let now = Duration::from_secs(genesis_block(Network::Testnet).header.time as u64); - let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_micros())); - - let mut handles = Vec::new(); - let mut stops = Vec::new(); - for _ in 1..5 { - let keys_manager_clone = Arc::clone(&keys_manager); - let (stop_sender, stop_receiver) = mpsc::channel(); - let handle = thread::spawn(move || { - loop { - keys_manager_clone.get_secure_random_bytes(); - match stop_receiver.try_recv() { - Ok(_) | Err(TryRecvError::Disconnected) => { - println!("Terminating."); - break; - } - Err(TryRecvError::Empty) => {} - } - } - }); - handles.push(handle); - stops.push(stop_sender); - } - - bench.iter(|| { - for _ in 1..100 { - keys_manager.get_secure_random_bytes(); - } - }); - - for stop in stops { - let _ = stop.send(()); - } - for handle in handles { - handle.join().unwrap(); - } - } - -} diff --git a/lightning/src/chain/mod.rs b/lightning/src/chain/mod.rs index a6ed856ae..abd888b3c 100644 --- a/lightning/src/chain/mod.rs +++ b/lightning/src/chain/mod.rs @@ -17,7 +17,7 @@ use bitcoin::network::constants::Network; use bitcoin::secp256k1::PublicKey; use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, MonitorEvent}; -use crate::chain::keysinterface::WriteableEcdsaChannelSigner; +use crate::sign::WriteableEcdsaChannelSigner; use crate::chain::transaction::{OutPoint, TransactionData}; use crate::prelude::*; @@ -26,7 +26,6 @@ pub mod chaininterface; pub mod chainmonitor; pub mod channelmonitor; pub mod transaction; -pub mod keysinterface; pub(crate) mod onchaintx; pub(crate) mod package; diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index 2d5c85cd4..21b4717e1 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -23,7 +23,7 @@ use bitcoin::hash_types::{Txid, BlockHash}; use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; use bitcoin::secp256k1; -use crate::chain::keysinterface::{ChannelSigner, EntropySource, SignerProvider}; +use crate::sign::{ChannelSigner, EntropySource, SignerProvider}; use crate::ln::msgs::DecodeError; use crate::ln::PaymentPreimage; #[cfg(anchors)] @@ -33,7 +33,7 @@ use crate::ln::chan_utils::{ChannelTransactionParameters, HolderCommitmentTransa use crate::chain::chaininterface::ConfirmationTarget; use crate::chain::chaininterface::{FeeEstimator, BroadcasterInterface, LowerBoundedFeeEstimator}; use crate::chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER}; -use crate::chain::keysinterface::WriteableEcdsaChannelSigner; +use crate::sign::WriteableEcdsaChannelSigner; #[cfg(anchors)] use crate::chain::package::PackageSolvingData; use crate::chain::package::PackageTemplate; diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index 7ea61dc24..4604a164c 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -25,7 +25,7 @@ use crate::ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment}; use crate::ln::chan_utils; use crate::ln::msgs::DecodeError; use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; -use crate::chain::keysinterface::WriteableEcdsaChannelSigner; +use crate::sign::WriteableEcdsaChannelSigner; #[cfg(anchors)] use crate::chain::onchaintx::ExternalHTLCClaim; use crate::chain::onchaintx::OnchainTxHandler; @@ -98,10 +98,11 @@ pub(crate) struct RevokedOutput { weight: u64, amount: u64, on_counterparty_tx_csv: u16, + is_counterparty_balance_on_anchors: Option<()>, } impl RevokedOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, on_counterparty_tx_csv: u16) -> Self { + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, on_counterparty_tx_csv: u16, is_counterparty_balance_on_anchors: bool) -> Self { RevokedOutput { per_commitment_point, counterparty_delayed_payment_base_key, @@ -109,7 +110,8 @@ impl RevokedOutput { per_commitment_key, weight: WEIGHT_REVOKED_OUTPUT, amount, - on_counterparty_tx_csv + on_counterparty_tx_csv, + is_counterparty_balance_on_anchors: if is_counterparty_balance_on_anchors { Some(()) } else { None } } } } @@ -122,6 +124,7 @@ impl_writeable_tlv_based!(RevokedOutput, { (8, weight, required), (10, amount, required), (12, on_counterparty_tx_csv, required), + (14, is_counterparty_balance_on_anchors, option) }); /// A struct to describe a revoked offered output and corresponding information to generate a @@ -479,6 +482,24 @@ impl PackageSolvingData { }; absolute_timelock } + + fn map_output_type_flags(&self) -> (PackageMalleability, bool) { + // Post-anchor, aggregation of outputs of different types is unsafe. See https://github.com/lightning/bolts/pull/803. + let (malleability, aggregable) = match self { + PackageSolvingData::RevokedOutput(RevokedOutput { is_counterparty_balance_on_anchors: Some(()), .. }) => { (PackageMalleability::Malleable, false) }, + PackageSolvingData::RevokedOutput(RevokedOutput { is_counterparty_balance_on_anchors: None, .. }) => { (PackageMalleability::Malleable, true) }, + PackageSolvingData::RevokedHTLCOutput(..) => { (PackageMalleability::Malleable, true) }, + PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { (PackageMalleability::Malleable, true) }, + PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { (PackageMalleability::Malleable, false) }, + PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.opt_anchors() { + (PackageMalleability::Malleable, outp.preimage.is_some()) + } else { + (PackageMalleability::Untractable, false) + }, + PackageSolvingData::HolderFundingOutput(..) => { (PackageMalleability::Untractable, false) }, + }; + (malleability, aggregable) + } } impl_writeable_tlv_based_enum!(PackageSolvingData, ; @@ -491,8 +512,7 @@ impl_writeable_tlv_based_enum!(PackageSolvingData, ; ); /// 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. +/// A untractable package has been counter-signed and aggregable will break cached counterparty signatures. #[derive(Clone, PartialEq, Eq)] pub(crate) enum PackageMalleability { Malleable, @@ -826,19 +846,8 @@ impl PackageTemplate { }).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(ref outp) => if outp.opt_anchors() { - PackageMalleability::Malleable - } else { - PackageMalleability::Untractable - }, - PackageSolvingData::HolderFundingOutput(..) => PackageMalleability::Untractable, - }; + pub (crate) fn build_package(txid: Txid, vout: u32, input_solving_data: PackageSolvingData, soonest_conf_deadline: u32, height_original: u32) -> Self { + let (malleability, aggregable) = PackageSolvingData::map_output_type_flags(&input_solving_data); let mut inputs = Vec::with_capacity(1); inputs.push((BitcoinOutPoint { txid, vout }, input_solving_data)); PackageTemplate { @@ -880,18 +889,7 @@ impl Readable for PackageTemplate { inputs.push((outpoint, rev_outp)); } let (malleability, aggregable) = if let Some((_, lead_input)) = inputs.first() { - match lead_input { - PackageSolvingData::RevokedOutput(..) => { (PackageMalleability::Malleable, true) }, - PackageSolvingData::RevokedHTLCOutput(..) => { (PackageMalleability::Malleable, true) }, - PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { (PackageMalleability::Malleable, true) }, - PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { (PackageMalleability::Malleable, false) }, - PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.opt_anchors() { - (PackageMalleability::Malleable, outp.preimage.is_some()) - } else { - (PackageMalleability::Untractable, false) - }, - PackageSolvingData::HolderFundingOutput(..) => { (PackageMalleability::Untractable, false) }, - } + PackageSolvingData::map_output_type_flags(&lead_input) } else { return Err(DecodeError::InvalidValue); }; let mut soonest_conf_deadline = 0; let mut feerate_previous = 0; @@ -1029,11 +1027,11 @@ mod tests { use bitcoin::secp256k1::Secp256k1; macro_rules! dumb_revk_output { - ($secp_ctx: expr) => { + ($secp_ctx: expr, $is_counterparty_balance_on_anchors: expr) => { { let dumb_scalar = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap(); let dumb_point = PublicKey::from_secret_key(&$secp_ctx, &dumb_scalar); - PackageSolvingData::RevokedOutput(RevokedOutput::build(dumb_point, dumb_point, dumb_point, dumb_scalar, 0, 0)) + PackageSolvingData::RevokedOutput(RevokedOutput::build(dumb_point, dumb_point, dumb_point, dumb_scalar, 0, 0, $is_counterparty_balance_on_anchors)) } } } @@ -1077,10 +1075,10 @@ mod tests { fn test_package_differing_heights() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); - let mut package_one_hundred = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); - let package_two_hundred = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 200); + let mut package_one_hundred = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100); + let package_two_hundred = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 200); package_one_hundred.merge_package(package_two_hundred); } @@ -1089,11 +1087,11 @@ mod tests { fn test_package_untractable_merge_to() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); let htlc_outp = dumb_htlc_output!(); - let mut untractable_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); - let malleable_package = PackageTemplate::build_package(txid, 1, htlc_outp.clone(), 1000, true, 100); + let mut untractable_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100); + let malleable_package = PackageTemplate::build_package(txid, 1, htlc_outp.clone(), 1000, 100); untractable_package.merge_package(malleable_package); } @@ -1103,10 +1101,10 @@ mod tests { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); let htlc_outp = dumb_htlc_output!(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); - let mut malleable_package = PackageTemplate::build_package(txid, 0, htlc_outp.clone(), 1000, true, 100); - let untractable_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100); + let mut malleable_package = PackageTemplate::build_package(txid, 0, htlc_outp.clone(), 1000, 100); + let untractable_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 100); malleable_package.merge_package(untractable_package); } @@ -1115,10 +1113,11 @@ mod tests { fn test_package_noaggregation_to() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); + let revk_outp_counterparty_balance = dumb_revk_output!(secp_ctx, true); - let mut noaggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, false, 100); - let aggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100); + let mut noaggregation_package = PackageTemplate::build_package(txid, 0, revk_outp_counterparty_balance.clone(), 1000, 100); + let aggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 100); noaggregation_package.merge_package(aggregation_package); } @@ -1127,10 +1126,11 @@ mod tests { fn test_package_noaggregation_from() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); + let revk_outp_counterparty_balance = dumb_revk_output!(secp_ctx, true); - let mut aggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); - let noaggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, false, 100); + let mut aggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100); + let noaggregation_package = PackageTemplate::build_package(txid, 1, revk_outp_counterparty_balance.clone(), 1000, 100); aggregation_package.merge_package(noaggregation_package); } @@ -1139,11 +1139,11 @@ mod tests { fn test_package_empty() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); - let mut empty_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); + let mut empty_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100); empty_package.inputs = vec![]; - let package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100); + let package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 100); empty_package.merge_package(package); } @@ -1152,11 +1152,11 @@ mod tests { fn test_package_differing_categories() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); 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); + let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, 100); + let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, 100); revoked_package.merge_package(counterparty_package); } @@ -1164,13 +1164,13 @@ mod tests { fn test_package_split_malleable() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp_one = dumb_revk_output!(secp_ctx); - let revk_outp_two = dumb_revk_output!(secp_ctx); - let revk_outp_three = dumb_revk_output!(secp_ctx); + let revk_outp_one = dumb_revk_output!(secp_ctx, false); + let revk_outp_two = dumb_revk_output!(secp_ctx, false); + let revk_outp_three = dumb_revk_output!(secp_ctx, false); - let mut package_one = PackageTemplate::build_package(txid, 0, revk_outp_one, 1000, true, 100); - let package_two = PackageTemplate::build_package(txid, 1, revk_outp_two, 1000, true, 100); - let package_three = PackageTemplate::build_package(txid, 2, revk_outp_three, 1000, true, 100); + let mut package_one = PackageTemplate::build_package(txid, 0, revk_outp_one, 1000, 100); + let package_two = PackageTemplate::build_package(txid, 1, revk_outp_two, 1000, 100); + let package_three = PackageTemplate::build_package(txid, 2, revk_outp_three, 1000, 100); package_one.merge_package(package_two); package_one.merge_package(package_three); @@ -1193,7 +1193,7 @@ mod tests { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let htlc_outp_one = dumb_htlc_output!(); - let mut package_one = PackageTemplate::build_package(txid, 0, htlc_outp_one, 1000, true, 100); + let mut package_one = PackageTemplate::build_package(txid, 0, htlc_outp_one, 1000, 100); let ret_split = package_one.split_package(&BitcoinOutPoint { txid, vout: 0}); assert!(ret_split.is_none()); } @@ -1202,9 +1202,9 @@ mod tests { fn test_package_timer() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); + let revk_outp = dumb_revk_output!(secp_ctx, false); - let mut package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100); + let mut package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, 100); assert_eq!(package.timer(), 100); package.set_timer(101); assert_eq!(package.timer(), 101); @@ -1216,7 +1216,7 @@ mod tests { let secp_ctx = Secp256k1::new(); let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, false); - let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100); + let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100); assert_eq!(package.package_amount(), 1000); } @@ -1229,15 +1229,15 @@ mod tests { let weight_sans_output = (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2; { - let revk_outp = dumb_revk_output!(secp_ctx); - let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100); + let revk_outp = dumb_revk_output!(secp_ctx, false); + let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, 100); assert_eq!(package.package_weight(&Script::new()), weight_sans_output + WEIGHT_REVOKED_OUTPUT as usize); } { for &opt_anchors in [false, true].iter() { 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); + let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100); assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_received_htlc(opt_anchors) as usize); } } @@ -1245,7 +1245,7 @@ mod tests { { for &opt_anchors in [false, true].iter() { 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); + let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100); assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_offered_htlc(opt_anchors) as usize); } } diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 6a3360a4d..950a31af3 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -24,13 +24,13 @@ 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 + /// [`InMemorySigner`]: crate::sign::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 + /// [`InMemorySigner`]: crate::sign::InMemorySigner pub channel_value_satoshis: u64, /// The transaction input's outpoint corresponding to the commitment transaction's anchor /// output. @@ -43,19 +43,19 @@ pub struct HTLCDescriptor { /// A unique identifier used along with `channel_value_satoshis` to re-derive the /// [`InMemorySigner`] required to sign `input`. /// - /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner + /// [`InMemorySigner`]: crate::sign::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 + /// [`InMemorySigner`]: crate::sign::InMemorySigner pub channel_value_satoshis: u64, /// The necessary channel parameters that need to be provided to the re-derived /// [`InMemorySigner`] through [`ChannelSigner::provide_channel_parameters`]. /// - /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner - /// [`ChannelSigner::provide_channel_parameters`]: crate::chain::keysinterface::ChannelSigner::provide_channel_parameters + /// [`InMemorySigner`]: crate::sign::InMemorySigner + /// [`ChannelSigner::provide_channel_parameters`]: crate::sign::ChannelSigner::provide_channel_parameters pub channel_parameters: ChannelTransactionParameters, /// The txid of the commitment transaction in which the HTLC output lives. pub commitment_txid: Txid, @@ -168,9 +168,9 @@ pub enum BumpTransactionEvent { /// 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 - /// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::chain::keysinterface::EcdsaChannelSigner::sign_holder_anchor_input + /// [`InMemorySigner`]: crate::sign::InMemorySigner + /// [`KeysManager::derive_channel_keys`]: crate::sign::KeysManager::derive_channel_keys + /// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input /// [`build_anchor_input_witness`]: crate::ln::chan_utils::build_anchor_input_witness ChannelClose { /// The target feerate that the transaction package, which consists of the commitment @@ -217,9 +217,9 @@ pub enum BumpTransactionEvent { /// longer able to commit external confirmed funds to the HTLC transaction or the fee committed /// to the HTLC transaction is greater in value than the HTLCs being claimed. /// - /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner - /// [`KeysManager::derive_channel_keys`]: crate::chain::keysinterface::KeysManager::derive_channel_keys - /// [`EcdsaChannelSigner::sign_holder_htlc_transaction`]: crate::chain::keysinterface::EcdsaChannelSigner::sign_holder_htlc_transaction + /// [`InMemorySigner`]: crate::sign::InMemorySigner + /// [`KeysManager::derive_channel_keys`]: crate::sign::KeysManager::derive_channel_keys + /// [`EcdsaChannelSigner::sign_holder_htlc_transaction`]: crate::sign::EcdsaChannelSigner::sign_holder_htlc_transaction /// [`HTLCDescriptor::tx_input_witness`]: HTLCDescriptor::tx_input_witness HTLCResolution { /// The target feerate that the resulting HTLC transaction must meet. diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 110d56cfe..76a7f884a 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -20,7 +20,7 @@ pub mod bump_transaction; #[cfg(anchors)] pub use bump_transaction::BumpTransactionEvent; -use crate::chain::keysinterface::SpendableOutputDescriptor; +use crate::sign::SpendableOutputDescriptor; use crate::ln::channelmanager::{InterceptId, PaymentId, RecipientOnionFields}; use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS; use crate::ln::features::ChannelTypeFeatures; @@ -129,7 +129,7 @@ pub enum ClosureReason { /// Be careful about printing the peer_msg, a well-crafted message could exploit /// a security vulnerability in the terminal emulator or the logging subsystem. /// To be safe, use `Display` on `UntrustedString` - /// + /// /// [`UntrustedString`]: crate::util::string::UntrustedString peer_msg: UntrustedString, }, @@ -377,7 +377,7 @@ pub enum Event { /// This field will always be filled in when the event was generated by LDK versions /// 0.0.113 and above. /// - /// [phantom nodes]: crate::chain::keysinterface::PhantomKeysManager + /// [phantom nodes]: crate::sign::PhantomKeysManager receiver_node_id: Option, /// The hash for which the preimage should be handed to the ChannelManager. Note that LDK will /// not stop you from registering duplicate payment hashes for inbound payments. @@ -425,7 +425,7 @@ pub enum Event { /// This field will always be filled in when the event was generated by LDK versions /// 0.0.113 and above. /// - /// [phantom nodes]: crate::chain::keysinterface::PhantomKeysManager + /// [phantom nodes]: crate::sign::PhantomKeysManager receiver_node_id: Option, /// The payment hash of the claimed payment. Note that LDK will not stop you from /// registering duplicate payment hashes for inbound payments. @@ -498,6 +498,8 @@ pub enum Event { payment_id: PaymentId, /// The hash that was given to [`ChannelManager::send_payment`]. /// + /// This will be `Some` for all payments which completed on LDK 0.0.104 or later. + /// /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment payment_hash: Option, /// The payment path that was successful. @@ -518,6 +520,8 @@ pub enum Event { PaymentPathFailed { /// The `payment_id` passed to [`ChannelManager::send_payment`]. /// + /// This will be `Some` for all payment paths which failed on LDK 0.0.103 or later. + /// /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment payment_id: Option, @@ -1436,6 +1440,14 @@ pub enum MessageSendEvent { /// The message which should be sent. msg: msgs::AcceptChannel, }, + /// Used to indicate that we've accepted a V2 channel open and should send the accept_channel2 + /// message provided to the given peer. + SendAcceptChannelV2 { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::AcceptChannelV2, + }, /// Used to indicate that we've initiated a channel open and should send the open_channel /// message provided to the given peer. SendOpenChannel { @@ -1444,6 +1456,14 @@ pub enum MessageSendEvent { /// The message which should be sent. msg: msgs::OpenChannel, }, + /// Used to indicate that we've initiated a V2 channel open and should send the open_channel2 + /// message provided to the given peer. + SendOpenChannelV2 { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::OpenChannelV2, + }, /// Used to indicate that a funding_created message should be sent to the peer with the given node_id. SendFundingCreated { /// The node_id of the node which should receive this message @@ -1458,6 +1478,69 @@ pub enum MessageSendEvent { /// The message which should be sent. msg: msgs::FundingSigned, }, + /// Used to indicate that a tx_add_input message should be sent to the peer with the given node_id. + SendTxAddInput { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxAddInput, + }, + /// Used to indicate that a tx_add_output message should be sent to the peer with the given node_id. + SendTxAddOutput { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxAddOutput, + }, + /// Used to indicate that a tx_remove_input message should be sent to the peer with the given node_id. + SendTxRemoveInput { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxRemoveInput, + }, + /// Used to indicate that a tx_remove_output message should be sent to the peer with the given node_id. + SendTxRemoveOutput { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxRemoveOutput, + }, + /// Used to indicate that a tx_complete message should be sent to the peer with the given node_id. + SendTxComplete { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxComplete, + }, + /// Used to indicate that a tx_signatures message should be sent to the peer with the given node_id. + SendTxSignatures { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxSignatures, + }, + /// Used to indicate that a tx_init_rbf message should be sent to the peer with the given node_id. + SendTxInitRbf { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxInitRbf, + }, + /// Used to indicate that a tx_ack_rbf message should be sent to the peer with the given node_id. + SendTxAckRbf { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxAckRbf, + }, + /// Used to indicate that a tx_abort message should be sent to the peer with the given node_id. + SendTxAbort { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::TxAddInput, + }, /// Used to indicate that a channel_ready message should be sent to the peer with the given node_id. SendChannelReady { /// The node_id of the node which should receive these message(s) diff --git a/lightning/src/lib.rs b/lightning/src/lib.rs index 668f752e6..e7e7e0ede 100644 --- a/lightning/src/lib.rs +++ b/lightning/src/lib.rs @@ -80,6 +80,7 @@ pub mod chain; pub mod ln; pub mod offers; pub mod routing; +pub mod sign; pub mod onion_message; pub mod blinded_path; pub mod events; diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 9699cc78a..b3b871467 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -8,7 +8,7 @@ // licenses. //! Various utilities for building scripts and deriving keys related to channels. These are -//! largely of interest for those implementing the traits on [`chain::keysinterface`] by hand. +//! largely of interest for those implementing the traits on [`crate::sign`] by hand. use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; @@ -21,7 +21,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::ripemd160::Hash as Ripemd160; use bitcoin::hash_types::{Txid, PubkeyHash}; -use crate::chain::keysinterface::EntropySource; +use crate::sign::EntropySource; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::msgs::DecodeError; use crate::util::ser::{Readable, Writeable, Writer}; @@ -1655,7 +1655,7 @@ mod tests { use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment}; use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1}; use crate::util::test_utils; - use crate::chain::keysinterface::{ChannelSigner, SignerProvider}; + use crate::sign::{ChannelSigner, SignerProvider}; use bitcoin::{Network, Txid}; use bitcoin::hashes::Hash; use crate::ln::PaymentHash; diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index 3f210cb46..e59cf47f1 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -12,7 +12,6 @@ //! 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::blockdata::block::{Block, BlockHeader}; use bitcoin::blockdata::constants::genesis_block; use bitcoin::hash_types::BlockHash; use bitcoin::network::constants::Network; @@ -35,7 +34,6 @@ use crate::util::test_utils; use crate::io; use bitcoin::hashes::Hash; -use bitcoin::TxMerkleNode; use crate::prelude::*; use crate::sync::{Arc, Mutex}; @@ -121,15 +119,7 @@ fn test_monitor_and_persister_update_fail() { assert_eq!(chain_mon.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed); chain_mon }; - let header = BlockHeader { - version: 0x20000000, - prev_blockhash: BlockHash::all_zeros(), - merkle_root: TxMerkleNode::all_zeros(), - time: 42, - bits: 42, - nonce: 42 - }; - chain_mon.chain_monitor.block_connected(&Block { header, txdata: vec![] }, 200); + chain_mon.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()), 200); // Set the persister's return value to be a InProgress. persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress); @@ -146,7 +136,7 @@ fn test_monitor_and_persister_update_fail() { let mut node_0_per_peer_lock; let mut node_0_peer_state_lock; let mut channel = get_channel_ref!(nodes[0], nodes[1], node_0_per_peer_lock, node_0_peer_state_lock, chan.2); - if let Ok(update) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { + if let Ok(Some(update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { // 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. diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 8b5e89d94..11f0261d6 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -25,7 +25,7 @@ use bitcoin::secp256k1; use crate::ln::{PaymentPreimage, PaymentHash}; use crate::ln::features::{ChannelTypeFeatures, InitFeatures}; use crate::ln::msgs; -use crate::ln::msgs::{DecodeError, OptionalField, DataLossProtect}; +use crate::ln::msgs::DecodeError; use crate::ln::script::{self, ShutdownScript}; use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT}; use crate::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}; @@ -35,7 +35,7 @@ use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator}; use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID}; use crate::chain::transaction::{OutPoint, TransactionData}; -use crate::chain::keysinterface::{WriteableEcdsaChannelSigner, EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient}; +use crate::sign::{WriteableEcdsaChannelSigner, EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient}; use crate::events::ClosureReason; use crate::routing::gossip::NodeId; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter}; @@ -479,6 +479,21 @@ pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4; /// * `EXPIRE_PREV_CONFIG_TICKS` = convergence_delay / tick_interval pub(crate) const EXPIRE_PREV_CONFIG_TICKS: usize = 5; +struct PendingChannelMonitorUpdate { + update: ChannelMonitorUpdate, + /// In some cases we need to delay letting the [`ChannelMonitorUpdate`] go until after an + /// `Event` is processed by the user. This bool indicates the [`ChannelMonitorUpdate`] is + /// blocked on some external event and the [`ChannelManager`] will update us when we're ready. + /// + /// [`ChannelManager`]: super::channelmanager::ChannelManager + blocked: bool, +} + +impl_writeable_tlv_based!(PendingChannelMonitorUpdate, { + (0, update, required), + (2, blocked, required), +}); + // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking // has been completed, and then turn into a Channel to get compiler-time enforcement of things like // calling channel_id() before we're set up or things like get_outbound_funding_signed on an @@ -744,7 +759,7 @@ pub(super) struct Channel { /// If we then persist the [`channelmanager::ChannelManager`] and crash before the persistence /// completes we still need to be able to complete the persistence. Thus, we have to keep a /// copy of the [`ChannelMonitorUpdate`] here until it is complete. - pending_monitor_updates: Vec, + pending_monitor_updates: Vec, } #[cfg(any(test, fuzzing))] @@ -986,7 +1001,10 @@ impl Channel { secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey { - Some(signer_provider.get_shutdown_scriptpubkey()) + match signer_provider.get_shutdown_scriptpubkey() { + Ok(scriptpubkey) => Some(scriptpubkey), + Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get shutdown scriptpubkey".to_owned()}), + } } else { None }; if let Some(shutdown_scriptpubkey) = &shutdown_scriptpubkey { @@ -995,6 +1013,11 @@ impl Channel { } } + let destination_script = match signer_provider.get_destination_script() { + Ok(script) => script, + Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}), + }; + let temporary_channel_id = entropy_source.get_secure_random_bytes(); Ok(Channel { @@ -1021,7 +1044,7 @@ impl Channel { holder_signer, shutdown_scriptpubkey, - destination_script: signer_provider.get_destination_script(), + destination_script, cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, @@ -1314,7 +1337,7 @@ impl Channel { let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { match &msg.shutdown_scriptpubkey { - &OptionalField::Present(ref script) => { + &Some(ref script) => { // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything if script.len() == 0 { None @@ -1326,14 +1349,17 @@ impl Channel { } }, // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel - &OptionalField::Absent => { + &None => { return Err(ChannelError::Close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned())); } } } else { None }; let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey { - Some(signer_provider.get_shutdown_scriptpubkey()) + match signer_provider.get_shutdown_scriptpubkey() { + Ok(scriptpubkey) => Some(scriptpubkey), + Err(_) => return Err(ChannelError::Close("Failed to get upfront shutdown scriptpubkey".to_owned())), + } } else { None }; if let Some(shutdown_scriptpubkey) = &shutdown_scriptpubkey { @@ -1342,6 +1368,11 @@ impl Channel { } } + let destination_script = match signer_provider.get_destination_script() { + Ok(script) => script, + Err(_) => return Err(ChannelError::Close("Failed to get destination script".to_owned())), + }; + let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); @@ -1368,7 +1399,7 @@ impl Channel { holder_signer, shutdown_scriptpubkey, - destination_script: signer_provider.get_destination_script(), + destination_script, cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, @@ -1979,28 +2010,52 @@ impl Channel { } pub fn get_update_fulfill_htlc_and_commit(&mut self, htlc_id: u64, payment_preimage: PaymentPreimage, logger: &L) -> UpdateFulfillCommitFetch where L::Target: Logger { + let release_cs_monitor = self.pending_monitor_updates.iter().all(|upd| !upd.blocked); match self.get_update_fulfill_htlc(htlc_id, payment_preimage, logger) { - UpdateFulfillFetch::NewClaim { mut monitor_update, htlc_value_msat, msg: Some(_) } => { - let mut additional_update = self.build_commitment_no_status_check(logger); - // build_commitment_no_status_check may bump latest_monitor_id but we want them to be - // strictly increasing by one, so decrement it here. - self.latest_monitor_update_id = monitor_update.update_id; - monitor_update.updates.append(&mut additional_update.updates); - self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new()); - self.pending_monitor_updates.push(monitor_update); + UpdateFulfillFetch::NewClaim { mut monitor_update, htlc_value_msat, msg } => { + // Even if we aren't supposed to let new monitor updates with commitment state + // updates run, we still need to push the preimage ChannelMonitorUpdateStep no + // matter what. Sadly, to push a new monitor update which flies before others + // already queued, we have to insert it into the pending queue and update the + // update_ids of all the following monitors. + let unblocked_update_pos = if release_cs_monitor && msg.is_some() { + let mut additional_update = self.build_commitment_no_status_check(logger); + // build_commitment_no_status_check may bump latest_monitor_id but we want them + // to be strictly increasing by one, so decrement it here. + self.latest_monitor_update_id = monitor_update.update_id; + monitor_update.updates.append(&mut additional_update.updates); + self.pending_monitor_updates.push(PendingChannelMonitorUpdate { + update: monitor_update, blocked: false, + }); + self.pending_monitor_updates.len() - 1 + } else { + let insert_pos = self.pending_monitor_updates.iter().position(|upd| upd.blocked) + .unwrap_or(self.pending_monitor_updates.len()); + let new_mon_id = self.pending_monitor_updates.get(insert_pos) + .map(|upd| upd.update.update_id).unwrap_or(monitor_update.update_id); + monitor_update.update_id = new_mon_id; + self.pending_monitor_updates.insert(insert_pos, PendingChannelMonitorUpdate { + update: monitor_update, blocked: false, + }); + for held_update in self.pending_monitor_updates.iter_mut().skip(insert_pos + 1) { + held_update.update.update_id += 1; + } + if msg.is_some() { + debug_assert!(false, "If there is a pending blocked monitor we should have MonitorUpdateInProgress set"); + let update = self.build_commitment_no_status_check(logger); + self.pending_monitor_updates.push(PendingChannelMonitorUpdate { + update, blocked: true, + }); + } + insert_pos + }; + self.monitor_updating_paused(false, msg.is_some(), false, Vec::new(), Vec::new(), Vec::new()); UpdateFulfillCommitFetch::NewClaim { - monitor_update: self.pending_monitor_updates.last().unwrap(), + monitor_update: &self.pending_monitor_updates.get(unblocked_update_pos) + .expect("We just pushed the monitor update").update, htlc_value_msat, } }, - UpdateFulfillFetch::NewClaim { monitor_update, htlc_value_msat, msg: None } => { - self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new()); - self.pending_monitor_updates.push(monitor_update); - UpdateFulfillCommitFetch::NewClaim { - monitor_update: self.pending_monitor_updates.last().unwrap(), - htlc_value_msat, - } - } UpdateFulfillFetch::DuplicateClaim {} => UpdateFulfillCommitFetch::DuplicateClaim {}, } } @@ -2191,7 +2246,7 @@ impl Channel { let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { match &msg.shutdown_scriptpubkey { - &OptionalField::Present(ref script) => { + &Some(ref script) => { // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything if script.len() == 0 { None @@ -2203,7 +2258,7 @@ impl Channel { } }, // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel - &OptionalField::Absent => { + &None => { return Err(ChannelError::Close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned())); } } @@ -3068,7 +3123,7 @@ impl Channel { Ok(()) } - pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<&ChannelMonitorUpdate, ChannelError> + pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result, ChannelError> where L::Target: Logger { if (self.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) { @@ -3268,8 +3323,7 @@ impl Channel { } log_debug!(logger, "Received valid commitment_signed from peer in channel {}, updated HTLC state but awaiting a monitor update resolution to reply.", log_bytes!(self.channel_id)); - self.pending_monitor_updates.push(monitor_update); - return Ok(self.pending_monitor_updates.last().unwrap()); + return Ok(self.push_ret_blockable_mon_update(monitor_update)); } let need_commitment_signed = if need_commitment && (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 { @@ -3286,9 +3340,8 @@ impl Channel { log_debug!(logger, "Received valid commitment_signed from peer in channel {}, updating HTLC state and responding with{} a revoke_and_ack.", log_bytes!(self.channel_id()), if need_commitment_signed { " our own commitment_signed and" } else { "" }); - self.pending_monitor_updates.push(monitor_update); self.monitor_updating_paused(true, need_commitment_signed, false, Vec::new(), Vec::new(), Vec::new()); - return Ok(self.pending_monitor_updates.last().unwrap()); + return Ok(self.push_ret_blockable_mon_update(monitor_update)); } /// Public version of the below, checking relevant preconditions first. @@ -3403,8 +3456,7 @@ impl Channel { update_add_htlcs.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len()); self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new()); - self.pending_monitor_updates.push(monitor_update); - (Some(self.pending_monitor_updates.last().unwrap()), htlcs_to_fail) + (self.push_ret_blockable_mon_update(monitor_update), htlcs_to_fail) } else { (None, Vec::new()) } @@ -3415,7 +3467,7 @@ impl Channel { /// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail, /// generating an appropriate error *after* the channel state has been updated based on the /// revoke_and_ack message. - pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK, logger: &L) -> Result<(Vec<(HTLCSource, PaymentHash)>, &ChannelMonitorUpdate), ChannelError> + pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK, logger: &L) -> Result<(Vec<(HTLCSource, PaymentHash)>, Option<&ChannelMonitorUpdate>), ChannelError> where L::Target: Logger, { if (self.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) { @@ -3612,21 +3664,19 @@ impl Channel { self.monitor_pending_failures.append(&mut revoked_htlcs); self.monitor_pending_finalized_fulfills.append(&mut finalized_claimed_htlcs); log_debug!(logger, "Received a valid revoke_and_ack for channel {} but awaiting a monitor update resolution to reply.", log_bytes!(self.channel_id())); - self.pending_monitor_updates.push(monitor_update); - return Ok((Vec::new(), self.pending_monitor_updates.last().unwrap())); + return Ok((Vec::new(), self.push_ret_blockable_mon_update(monitor_update))); } match self.free_holding_cell_htlcs(logger) { (Some(_), htlcs_to_fail) => { - let mut additional_update = self.pending_monitor_updates.pop().unwrap(); + let mut additional_update = self.pending_monitor_updates.pop().unwrap().update; // free_holding_cell_htlcs may bump latest_monitor_id multiple times but we want them to be // strictly increasing by one, so decrement it here. self.latest_monitor_update_id = monitor_update.update_id; monitor_update.updates.append(&mut additional_update.updates); self.monitor_updating_paused(false, true, false, to_forward_infos, revoked_htlcs, finalized_claimed_htlcs); - self.pending_monitor_updates.push(monitor_update); - Ok((htlcs_to_fail, self.pending_monitor_updates.last().unwrap())) + Ok((htlcs_to_fail, self.push_ret_blockable_mon_update(monitor_update))) }, (None, htlcs_to_fail) => { if require_commitment { @@ -3640,13 +3690,11 @@ impl Channel { log_debug!(logger, "Received a valid revoke_and_ack for channel {}. Responding with a commitment update with {} HTLCs failed.", log_bytes!(self.channel_id()), update_fail_htlcs.len() + update_fail_malformed_htlcs.len()); self.monitor_updating_paused(false, true, false, to_forward_infos, revoked_htlcs, finalized_claimed_htlcs); - self.pending_monitor_updates.push(monitor_update); - Ok((htlcs_to_fail, self.pending_monitor_updates.last().unwrap())) + Ok((htlcs_to_fail, self.push_ret_blockable_mon_update(monitor_update))) } else { log_debug!(logger, "Received a valid revoke_and_ack for channel {} with no reply necessary.", log_bytes!(self.channel_id())); self.monitor_updating_paused(false, false, false, to_forward_infos, revoked_htlcs, finalized_claimed_htlcs); - self.pending_monitor_updates.push(monitor_update); - Ok((htlcs_to_fail, self.pending_monitor_updates.last().unwrap())) + Ok((htlcs_to_fail, self.push_ret_blockable_mon_update(monitor_update))) } } } @@ -3835,7 +3883,12 @@ impl Channel { { assert_eq!(self.channel_state & ChannelState::MonitorUpdateInProgress as u32, ChannelState::MonitorUpdateInProgress as u32); self.channel_state &= !(ChannelState::MonitorUpdateInProgress as u32); - self.pending_monitor_updates.clear(); + let mut found_blocked = false; + self.pending_monitor_updates.retain(|upd| { + if found_blocked { debug_assert!(upd.blocked, "No mons may be unblocked after a blocked one"); } + if upd.blocked { found_blocked = true; } + upd.blocked + }); // If we're past (or at) the FundingSent stage on an outbound channel, try to // (re-)broadcast the funding transaction as we may have declined to broadcast it when we @@ -4039,36 +4092,31 @@ impl Channel { if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_local_commitment_number == 0 { - return Err(ChannelError::Close("Peer sent a garbage channel_reestablish".to_owned())); + return Err(ChannelError::Close("Peer sent a garbage channel_reestablish (usually an lnd node with lost state asking us to force-close for them)".to_owned())); } if msg.next_remote_commitment_number > 0 { - match msg.data_loss_protect { - OptionalField::Present(ref data_loss) => { - let expected_point = self.holder_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - msg.next_remote_commitment_number + 1, &self.secp_ctx); - let given_secret = SecretKey::from_slice(&data_loss.your_last_per_commitment_secret) - .map_err(|_| ChannelError::Close("Peer sent a garbage channel_reestablish with unparseable secret key".to_owned()))?; - if expected_point != PublicKey::from_secret_key(&self.secp_ctx, &given_secret) { - return Err(ChannelError::Close("Peer sent a garbage channel_reestablish with secret key not matching the commitment height provided".to_owned())); + let expected_point = self.holder_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - msg.next_remote_commitment_number + 1, &self.secp_ctx); + let given_secret = SecretKey::from_slice(&msg.your_last_per_commitment_secret) + .map_err(|_| ChannelError::Close("Peer sent a garbage channel_reestablish with unparseable secret key".to_owned()))?; + if expected_point != PublicKey::from_secret_key(&self.secp_ctx, &given_secret) { + return Err(ChannelError::Close("Peer sent a garbage channel_reestablish with secret key not matching the commitment height provided".to_owned())); + } + if msg.next_remote_commitment_number > INITIAL_COMMITMENT_NUMBER - self.cur_holder_commitment_transaction_number { + macro_rules! log_and_panic { + ($err_msg: expr) => { + log_error!(logger, $err_msg, log_bytes!(self.channel_id), log_pubkey!(self.counterparty_node_id)); + panic!($err_msg, log_bytes!(self.channel_id), log_pubkey!(self.counterparty_node_id)); } - if msg.next_remote_commitment_number > INITIAL_COMMITMENT_NUMBER - self.cur_holder_commitment_transaction_number { - macro_rules! log_and_panic { - ($err_msg: expr) => { - log_error!(logger, $err_msg, log_bytes!(self.channel_id), log_pubkey!(self.counterparty_node_id)); - panic!($err_msg, log_bytes!(self.channel_id), log_pubkey!(self.counterparty_node_id)); - } - } - log_and_panic!("We have fallen behind - we have received proof that if we broadcast our counterparty is going to claim all our funds.\n\ - This implies you have restarted with lost ChannelMonitor and ChannelManager state, the first of which is a violation of the LDK chain::Watch requirements.\n\ - More specifically, this means you have a bug in your implementation that can cause loss of funds, or you are running with an old backup, which is unsafe.\n\ - If you have restored from an old backup and wish to force-close channels and return to operation, you should start up, call\n\ - ChannelManager::force_close_without_broadcasting_txn on channel {} with counterparty {} or\n\ - ChannelManager::force_close_all_channels_without_broadcasting_txn, then reconnect to peer(s).\n\ - Note that due to a long-standing bug in lnd you may have to reach out to peers running lnd-based nodes to ask them to manually force-close channels\n\ - See https://github.com/lightningdevkit/rust-lightning/issues/1565 for more info."); - } - }, - OptionalField::Absent => {} + } + log_and_panic!("We have fallen behind - we have received proof that if we broadcast our counterparty is going to claim all our funds.\n\ + This implies you have restarted with lost ChannelMonitor and ChannelManager state, the first of which is a violation of the LDK chain::Watch requirements.\n\ + More specifically, this means you have a bug in your implementation that can cause loss of funds, or you are running with an old backup, which is unsafe.\n\ + If you have restored from an old backup and wish to force-close channels and return to operation, you should start up, call\n\ + ChannelManager::force_close_without_broadcasting_txn on channel {} with counterparty {} or\n\ + ChannelManager::force_close_all_channels_without_broadcasting_txn, then reconnect to peer(s).\n\ + Note that due to a long-standing bug in lnd you may have to reach out to peers running lnd-based nodes to ask them to manually force-close channels\n\ + See https://github.com/lightningdevkit/rust-lightning/issues/1565 for more info."); } } @@ -4355,7 +4403,10 @@ impl Channel { Some(_) => false, None => { assert!(send_shutdown); - let shutdown_scriptpubkey = signer_provider.get_shutdown_scriptpubkey(); + let shutdown_scriptpubkey = match signer_provider.get_shutdown_scriptpubkey() { + Ok(scriptpubkey) => scriptpubkey, + Err(_) => return Err(ChannelError::Close("Failed to get shutdown scriptpubkey".to_owned())), + }; if !shutdown_scriptpubkey.is_compatible(their_features) { return Err(ChannelError::Close(format!("Provided a scriptpubkey format not accepted by peer: {}", shutdown_scriptpubkey))); } @@ -4378,8 +4429,9 @@ impl Channel { }], }; self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new()); - self.pending_monitor_updates.push(monitor_update); - Some(self.pending_monitor_updates.last().unwrap()) + if self.push_blockable_mon_update(monitor_update) { + self.pending_monitor_updates.last().map(|upd| &upd.update) + } else { None } } else { None }; let shutdown = if send_shutdown { Some(msgs::Shutdown { @@ -4951,8 +5003,49 @@ impl Channel { (self.channel_state & ChannelState::MonitorUpdateInProgress as u32) != 0 } - pub fn get_next_monitor_update(&self) -> Option<&ChannelMonitorUpdate> { - self.pending_monitor_updates.first() + pub fn get_latest_complete_monitor_update_id(&self) -> u64 { + if self.pending_monitor_updates.is_empty() { return self.get_latest_monitor_update_id(); } + self.pending_monitor_updates[0].update.update_id - 1 + } + + /// Returns the next blocked monitor update, if one exists, and a bool which indicates a + /// further blocked monitor update exists after the next. + pub fn unblock_next_blocked_monitor_update(&mut self) -> Option<(&ChannelMonitorUpdate, bool)> { + for i in 0..self.pending_monitor_updates.len() { + if self.pending_monitor_updates[i].blocked { + self.pending_monitor_updates[i].blocked = false; + return Some((&self.pending_monitor_updates[i].update, + self.pending_monitor_updates.len() > i + 1)); + } + } + None + } + + /// Pushes a new monitor update into our monitor update queue, returning whether it should be + /// immediately given to the user for persisting or if it should be held as blocked. + fn push_blockable_mon_update(&mut self, update: ChannelMonitorUpdate) -> bool { + let release_monitor = self.pending_monitor_updates.iter().all(|upd| !upd.blocked); + self.pending_monitor_updates.push(PendingChannelMonitorUpdate { + update, blocked: !release_monitor + }); + release_monitor + } + + /// Pushes a new monitor update into our monitor update queue, returning a reference to it if + /// it should be immediately given to the user for persisting or `None` if it should be held as + /// blocked. + fn push_ret_blockable_mon_update(&mut self, update: ChannelMonitorUpdate) + -> Option<&ChannelMonitorUpdate> { + let release_monitor = self.push_blockable_mon_update(update); + if release_monitor { self.pending_monitor_updates.last().map(|upd| &upd.update) } else { None } + } + + pub fn no_monitor_updates_pending(&self) -> bool { + self.pending_monitor_updates.is_empty() + } + + pub fn complete_one_mon_update(&mut self, update_id: u64) { + self.pending_monitor_updates.retain(|upd| upd.update.update_id != update_id); } /// Returns true if funding_created was sent/received. @@ -5323,7 +5416,7 @@ impl Channel { htlc_basepoint: keys.htlc_basepoint, first_per_commitment_point, channel_flags: if self.config.announced_channel {1} else {0}, - shutdown_scriptpubkey: OptionalField::Present(match &self.shutdown_scriptpubkey { + shutdown_scriptpubkey: Some(match &self.shutdown_scriptpubkey { Some(script) => script.clone().into_inner(), None => Builder::new().into_script(), }), @@ -5389,7 +5482,7 @@ impl Channel { delayed_payment_basepoint: keys.delayed_payment_basepoint, htlc_basepoint: keys.htlc_basepoint, first_per_commitment_point, - shutdown_scriptpubkey: OptionalField::Present(match &self.shutdown_scriptpubkey { + shutdown_scriptpubkey: Some(match &self.shutdown_scriptpubkey { Some(script) => script.clone().into_inner(), None => Builder::new().into_script(), }), @@ -5651,19 +5744,13 @@ impl Channel { // valid, and valid in fuzzing mode's arbitrary validity criteria: let mut pk = [2; 33]; pk[1] = 0xff; let dummy_pubkey = PublicKey::from_slice(&pk).unwrap(); - let data_loss_protect = if self.cur_counterparty_commitment_transaction_number + 1 < INITIAL_COMMITMENT_NUMBER { + let remote_last_secret = if self.cur_counterparty_commitment_transaction_number + 1 < INITIAL_COMMITMENT_NUMBER { let remote_last_secret = self.commitment_secrets.get_secret(self.cur_counterparty_commitment_transaction_number + 2).unwrap(); log_trace!(logger, "Enough info to generate a Data Loss Protect with per_commitment_secret {} for channel {}", log_bytes!(remote_last_secret), log_bytes!(self.channel_id())); - OptionalField::Present(DataLossProtect { - your_last_per_commitment_secret: remote_last_secret, - my_current_per_commitment_point: dummy_pubkey - }) + remote_last_secret } else { log_info!(logger, "Sending a data_loss_protect with no previous remote per_commitment_secret for channel {}", log_bytes!(self.channel_id())); - OptionalField::Present(DataLossProtect { - your_last_per_commitment_secret: [0;32], - my_current_per_commitment_point: dummy_pubkey, - }) + [0;32] }; msgs::ChannelReestablish { channel_id: self.channel_id(), @@ -5685,7 +5772,12 @@ impl Channel { // dropped this channel on disconnect as it hasn't yet reached FundingSent so we can't // overflow here. next_remote_commitment_number: INITIAL_COMMITMENT_NUMBER - self.cur_counterparty_commitment_transaction_number - 1, - data_loss_protect, + your_last_per_commitment_secret: remote_last_secret, + my_current_per_commitment_point: dummy_pubkey, + // TODO(dual_funding): If we've sent `commtiment_signed` for an interactive transaction + // construction but have not received `tx_signatures` we MUST set `next_funding_txid` to the + // txid of that interactive transaction, else we MUST NOT set it. + next_funding_txid: None, } } @@ -6000,8 +6092,7 @@ impl Channel { Some(_) => { let monitor_update = self.build_commitment_no_status_check(logger); self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new()); - self.pending_monitor_updates.push(monitor_update); - Ok(Some(self.pending_monitor_updates.last().unwrap())) + Ok(self.push_ret_blockable_mon_update(monitor_update)) }, None => Ok(None) } @@ -6031,7 +6122,7 @@ impl Channel { /// May jump to the channel being fully shutdown (see [`Self::is_shutdown`]) in which case no /// [`ChannelMonitorUpdate`] will be returned). pub fn get_shutdown(&mut self, signer_provider: &SP, their_features: &InitFeatures, - target_feerate_sats_per_kw: Option) + target_feerate_sats_per_kw: Option, override_shutdown_script: Option) -> Result<(msgs::Shutdown, Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), APIError> where SP::Target: SignerProvider { for htlc in self.pending_outbound_htlcs.iter() { @@ -6047,6 +6138,9 @@ impl Channel { return Err(APIError::ChannelUnavailable{err: "Shutdown already in progress by remote".to_owned()}); } } + if self.shutdown_scriptpubkey.is_some() && override_shutdown_script.is_some() { + return Err(APIError::APIMisuseError{err: "Cannot override shutdown script for a channel with one already set".to_owned()}); + } assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0); if self.channel_state & (ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32) != 0 { return Err(APIError::ChannelUnavailable{err: "Cannot begin shutdown while peer is disconnected or we're waiting on a monitor update, maybe force-close instead?".to_owned()}); @@ -6062,7 +6156,17 @@ impl Channel { let update_shutdown_script = match self.shutdown_scriptpubkey { Some(_) => false, None if !chan_closed => { - let shutdown_scriptpubkey = signer_provider.get_shutdown_scriptpubkey(); + // use override shutdown script if provided + let shutdown_scriptpubkey = match override_shutdown_script { + Some(script) => script, + None => { + // otherwise, use the shutdown scriptpubkey provided by the signer + match signer_provider.get_shutdown_scriptpubkey() { + Ok(scriptpubkey) => scriptpubkey, + Err(_) => return Err(APIError::ChannelUnavailable{err: "Failed to get shutdown scriptpubkey".to_owned()}), + } + }, + }; if !shutdown_scriptpubkey.is_compatible(their_features) { return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() }); } @@ -6090,8 +6194,9 @@ impl Channel { }], }; self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new()); - self.pending_monitor_updates.push(monitor_update); - Some(self.pending_monitor_updates.last().unwrap()) + if self.push_blockable_mon_update(monitor_update) { + self.pending_monitor_updates.last().map(|upd| &upd.update) + } else { None } } else { None }; let shutdown = msgs::Shutdown { channel_id: self.channel_id, @@ -6528,6 +6633,7 @@ impl Writeable for Channel { (28, holder_max_accepted_htlcs, option), (29, self.temporary_channel_id, option), (31, channel_pending_event_emitted, option), + (33, self.pending_monitor_updates, vec_type), }); Ok(()) @@ -6804,6 +6910,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch let mut temporary_channel_id: Option<[u8; 32]> = None; let mut holder_max_accepted_htlcs: Option = None; + let mut pending_monitor_updates = Some(Vec::new()); + read_tlv_fields!(reader, { (0, announcement_sigs, option), (1, minimum_depth, option), @@ -6826,6 +6934,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch (28, holder_max_accepted_htlcs, option), (29, temporary_channel_id, option), (31, channel_pending_event_emitted, option), + (33, pending_monitor_updates, vec_type), }); let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id { @@ -6995,7 +7104,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch channel_type: channel_type.unwrap(), channel_keys_id, - pending_monitor_updates: Vec::new(), + pending_monitor_updates: pending_monitor_updates.unwrap(), }) } } @@ -7016,13 +7125,13 @@ mod tests { use crate::ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator}; use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS}; use crate::ln::features::ChannelTypeFeatures; - use crate::ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate, MAX_VALUE_MSAT}; + use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; use crate::ln::script::ShutdownScript; use crate::ln::chan_utils; use crate::ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight}; use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, LowerBoundedFeeEstimator, ConfirmationTarget}; - use crate::chain::keysinterface::{ChannelSigner, InMemorySigner, EntropySource, SignerProvider}; + use crate::sign::{ChannelSigner, InMemorySigner, EntropySource, SignerProvider}; use crate::chain::transaction::OutPoint; use crate::routing::router::Path; use crate::util::config::UserConfig; @@ -7087,17 +7196,17 @@ mod tests { fn read_chan_signer(&self, _data: &[u8]) -> Result { panic!(); } - fn get_destination_script(&self) -> Script { + fn get_destination_script(&self) -> Result { let secp_ctx = Secp256k1::signing_only(); let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); let channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&channel_monitor_claim_key_hash[..]).into_script() + Ok(Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&channel_monitor_claim_key_hash[..]).into_script()) } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + fn get_shutdown_scriptpubkey(&self) -> Result { let secp_ctx = Secp256k1::signing_only(); let channel_close_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); - ShutdownScript::new_p2wpkh_from_pubkey(PublicKey::from_secret_key(&secp_ctx, &channel_close_key)) + Ok(ShutdownScript::new_p2wpkh_from_pubkey(PublicKey::from_secret_key(&secp_ctx, &channel_close_key))) } } @@ -7317,12 +7426,7 @@ mod tests { let msg = node_b_chan.get_channel_reestablish(&&logger); assert_eq!(msg.next_local_commitment_number, 1); // now called next_commitment_number assert_eq!(msg.next_remote_commitment_number, 0); // now called next_revocation_number - match msg.data_loss_protect { - OptionalField::Present(DataLossProtect { your_last_per_commitment_secret, .. }) => { - assert_eq!(your_last_per_commitment_secret, [0; 32]); - }, - _ => panic!() - } + assert_eq!(msg.your_last_per_commitment_secret, [0; 32]); // Check that the commitment point in Node A's channel_reestablish message // is sane. @@ -7330,12 +7434,7 @@ mod tests { let msg = node_a_chan.get_channel_reestablish(&&logger); assert_eq!(msg.next_local_commitment_number, 1); // now called next_commitment_number assert_eq!(msg.next_remote_commitment_number, 0); // now called next_revocation_number - match msg.data_loss_protect { - OptionalField::Present(DataLossProtect { your_last_per_commitment_secret, .. }) => { - assert_eq!(your_last_per_commitment_secret, [0; 32]); - }, - _ => panic!() - } + assert_eq!(msg.your_last_per_commitment_secret, [0; 32]); } #[test] @@ -7526,7 +7625,7 @@ mod tests { use bitcoin::hashes::hex::FromHex; use bitcoin::hash_types::Txid; use bitcoin::secp256k1::Message; - use crate::chain::keysinterface::EcdsaChannelSigner; + use crate::sign::EcdsaChannelSigner; use crate::ln::PaymentPreimage; use crate::ln::channel::{HTLCOutputInCommitment ,TxCreationKeys}; use crate::ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 498813de7..f6cb81376 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -45,8 +45,8 @@ use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, No #[cfg(any(feature = "_test_utils", test))] use crate::ln::features::InvoiceFeatures; use crate::routing::gossip::NetworkGraph; -use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, Router}; -use crate::routing::scoring::ProbabilisticScorer; +use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteHop, RouteParameters, Router}; +use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters}; use crate::ln::msgs; use crate::ln::onion_utils; use crate::ln::onion_utils::HTLCFailReason; @@ -55,7 +55,7 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VA use crate::ln::outbound_payment; use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment}; use crate::ln::wire::Encode; -use crate::chain::keysinterface::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner}; +use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner}; use crate::util::config::{UserConfig, ChannelConfig}; use crate::util::wakers::{Future, Notifier}; use crate::util::scid_utils::fake_scid; @@ -78,6 +78,7 @@ use core::ops::Deref; // Re-export this for use in the public API. pub use crate::ln::outbound_payment::{PaymentSendFailure, Retry, RetryableSendFailure, RecipientOnionFields}; +use crate::ln::script::ShutdownScript; // We hold various information about HTLC relay in the HTLC objects in Channel itself: // @@ -500,9 +501,11 @@ struct ClaimablePayments { /// for some reason. They are handled in timer_tick_occurred, so may be processed with /// quite some time lag. enum BackgroundEvent { - /// Handle a ChannelMonitorUpdate that closes a channel, broadcasting its current latest holder - /// commitment transaction. - ClosingMonitorUpdate((OutPoint, ChannelMonitorUpdate)), + /// Handle a ChannelMonitorUpdate + /// + /// Note that any such events are lost on shutdown, so in general they must be updates which + /// are regenerated on startup. + MonitorUpdateRegeneratedOnStartup((OutPoint, ChannelMonitorUpdate)), } #[derive(Debug)] @@ -521,6 +524,20 @@ impl_writeable_tlv_based_enum_upgradable!(MonitorUpdateCompletionAction, (2, EmitEvent) => { (0, event, upgradable_required) }, ); +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum EventCompletionAction { + ReleaseRAAChannelMonitorUpdate { + counterparty_node_id: PublicKey, + channel_funding_outpoint: OutPoint, + }, +} +impl_writeable_tlv_based_enum!(EventCompletionAction, + (0, ReleaseRAAChannelMonitorUpdate) => { + (0, channel_funding_outpoint, required), + (2, counterparty_node_id, required), + }; +); + /// State we hold per-peer. pub(super) struct PeerState { /// `temporary_channel_id` or `channel_id` -> `channel`. @@ -608,7 +625,9 @@ pub type SimpleArcChannelManager = ChannelManager< Arc>>, Arc, - Arc>>, Arc>>> + Arc>>, Arc>>>, + ProbabilisticScoringFeeParameters, + ProbabilisticScorer>>, Arc>, >>, Arc >; @@ -624,7 +643,7 @@ pub type SimpleArcChannelManager = ChannelManager< /// of [`KeysManager`] and [`DefaultRouter`]. /// /// This is not exported to bindings users as Arcs don't make sense in bindings -pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> = ChannelManager<&'a M, &'b T, &'c KeysManager, &'c KeysManager, &'c KeysManager, &'d F, &'e DefaultRouter<&'f NetworkGraph<&'g L>, &'g L, &'h Mutex, &'g L>>>, &'g L>; +pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> = ChannelManager<&'a M, &'b T, &'c KeysManager, &'c KeysManager, &'c KeysManager, &'d F, &'e DefaultRouter<&'f NetworkGraph<&'g L>, &'g L, &'h Mutex, &'g L>>, ProbabilisticScoringFeeParameters, ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, &'g L>; /// A trivial trait which describes any [`ChannelManager`] used in testing. #[cfg(any(test, feature = "_test_utils"))] @@ -932,8 +951,17 @@ where #[cfg(any(test, feature = "_test_utils"))] pub(super) per_peer_state: FairRwLock::Signer>>>>, + /// The set of events which we need to give to the user to handle. In some cases an event may + /// require some further action after the user handles it (currently only blocking a monitor + /// update from being handed to the user to ensure the included changes to the channel state + /// are handled by the user before they're persisted durably to disk). In that case, the second + /// element in the tuple is set to `Some` with further details of the action. + /// + /// Note that events MUST NOT be removed from pending_events after deserialization, as they + /// could be in the middle of being processed without the direct mutex held. + /// /// See `ChannelManager` struct-level documentation for lock order requirements. - pending_events: Mutex>, + pending_events: Mutex)>>, /// A simple atomic flag to ensure only one task at a time can be processing events asynchronously. pending_events_processor: AtomicBool, /// See `ChannelManager` struct-level documentation for lock order requirements. @@ -1414,7 +1442,7 @@ pub enum RecentPaymentDetails { /// Route hints used in constructing invoices for [phantom node payents]. /// -/// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager +/// [phantom node payments]: crate::sign::PhantomKeysManager #[derive(Clone)] pub struct PhantomRouteHints { /// The list of channels to be included in the invoice route hints. @@ -1446,10 +1474,10 @@ macro_rules! handle_error { }); } if let Some((channel_id, user_channel_id)) = chan_id { - $self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { + $self.pending_events.lock().unwrap().push_back((events::Event::ChannelClosed { channel_id, user_channel_id, reason: ClosureReason::ProcessingError { err: err.err.clone() } - }); + }, None)); } } @@ -1581,13 +1609,13 @@ macro_rules! send_channel_ready { macro_rules! emit_channel_pending_event { ($locked_events: expr, $channel: expr) => { if $channel.should_emit_channel_pending_event() { - $locked_events.push(events::Event::ChannelPending { + $locked_events.push_back((events::Event::ChannelPending { channel_id: $channel.channel_id(), former_temporary_channel_id: $channel.temporary_channel_id(), counterparty_node_id: $channel.get_counterparty_node_id(), user_channel_id: $channel.get_user_id(), funding_txo: $channel.get_funding_txo().unwrap().into_bitcoin_outpoint(), - }); + }, None)); $channel.set_channel_pending_event_emitted(); } } @@ -1597,12 +1625,12 @@ macro_rules! emit_channel_ready_event { ($locked_events: expr, $channel: expr) => { if $channel.should_emit_channel_ready_event() { debug_assert!($channel.channel_pending_event_emitted()); - $locked_events.push(events::Event::ChannelReady { + $locked_events.push_back((events::Event::ChannelReady { channel_id: $channel.channel_id(), user_channel_id: $channel.get_user_id(), counterparty_node_id: $channel.get_counterparty_node_id(), channel_type: $channel.get_channel_type().clone(), - }); + }, None)); $channel.set_channel_ready_event_emitted(); } } @@ -1680,11 +1708,8 @@ macro_rules! handle_new_monitor_update { res }, ChannelMonitorUpdateStatus::Completed => { - if ($update_id == 0 || $chan.get_next_monitor_update() - .expect("We can't be processing a monitor update if it isn't queued") - .update_id == $update_id) && - $chan.get_latest_monitor_update_id() == $update_id - { + $chan.complete_one_mon_update($update_id); + if $chan.no_monitor_updates_pending() { handle_monitor_update_completion!($self, $update_id, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan); } Ok(()) @@ -1724,9 +1749,14 @@ macro_rules! process_events_body { result = NotifyOption::DoPersist; } - for event in pending_events { + let mut post_event_actions = Vec::new(); + + for (event, action_opt) in pending_events { $event_to_handle = event; $handle_event; + if let Some(action) = action_opt { + post_event_actions.push(action); + } } { @@ -1736,6 +1766,12 @@ macro_rules! process_events_body { $self.pending_events_processor.store(false, Ordering::Release); } + if !post_event_actions.is_empty() { + $self.handle_post_event_actions(post_event_actions); + // If we had some actions, go around again as we may have more events now + processed_all_events = false; + } + if result == NotifyOption::DoPersist { $self.persistence_notifier.notify(); } @@ -1805,7 +1841,7 @@ where per_peer_state: FairRwLock::new(HashMap::new()), - pending_events: Mutex::new(Vec::new()), + pending_events: Mutex::new(VecDeque::new()), pending_events_processor: AtomicBool::new(false), pending_background_events: Mutex::new(Vec::new()), total_consistency_lock: RwLock::new(()), @@ -1854,6 +1890,10 @@ where /// Raises [`APIError::APIMisuseError`] when `channel_value_satoshis` > 2**24 or `push_msat` is /// greater than `channel_value_satoshis * 1k` or `channel_value_satoshis < 1000`. /// + /// Raises [`APIError::ChannelUnavailable`] if the channel cannot be opened due to failing to + /// generate a shutdown scriptpubkey or destination script set by + /// [`SignerProvider::get_shutdown_scriptpubkey`] or [`SignerProvider::get_destination_script`]. + /// /// Note that we do not check if you are currently connected to the given peer. If no /// connection is available, the outbound `open_channel` message may fail to send, resulting in /// the channel eventually being silently forgotten (dropped on reload). @@ -2013,18 +2053,20 @@ where let mut pending_events_lock = self.pending_events.lock().unwrap(); match channel.unbroadcasted_funding() { Some(transaction) => { - pending_events_lock.push(events::Event::DiscardFunding { channel_id: channel.channel_id(), transaction }) + pending_events_lock.push_back((events::Event::DiscardFunding { + channel_id: channel.channel_id(), transaction + }, None)); }, None => {}, } - pending_events_lock.push(events::Event::ChannelClosed { + pending_events_lock.push_back((events::Event::ChannelClosed { channel_id: channel.channel_id(), user_channel_id: channel.get_user_id(), reason: closure_reason - }); + }, None)); } - fn close_channel_internal(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option) -> Result<(), APIError> { + fn close_channel_internal(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option, override_shutdown_script: Option) -> Result<(), APIError> { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); let mut failed_htlcs: Vec<(HTLCSource, PaymentHash)>; @@ -2041,7 +2083,7 @@ where let funding_txo_opt = chan_entry.get().get_funding_txo(); let their_features = &peer_state.latest_features; let (shutdown_msg, mut monitor_update_opt, htlcs) = chan_entry.get_mut() - .get_shutdown(&self.signer_provider, their_features, target_feerate_sats_per_1000_weight)?; + .get_shutdown(&self.signer_provider, their_features, target_feerate_sats_per_1000_weight, override_shutdown_script)?; failed_htlcs = htlcs; // We can send the `shutdown` message before updating the `ChannelMonitor` @@ -2098,12 +2140,17 @@ where /// /// May generate a [`SendShutdown`] message event on success, which should be relayed. /// + /// Raises [`APIError::ChannelUnavailable`] if the channel cannot be closed due to failing to + /// generate a shutdown scriptpubkey or destination script set by + /// [`SignerProvider::get_shutdown_scriptpubkey`]. A force-closure may be needed to close the + /// channel. + /// /// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`]: crate::util::config::ChannelConfig::force_close_avoidance_max_fee_satoshis /// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background /// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal /// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown pub fn close_channel(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey) -> Result<(), APIError> { - self.close_channel_internal(channel_id, counterparty_node_id, None) + self.close_channel_internal(channel_id, counterparty_node_id, None, None) } /// Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs @@ -2120,14 +2167,24 @@ where /// transaction feerate below `target_feerate_sat_per_1000_weight` (or the feerate which /// will appear on a force-closure transaction, whichever is lower). /// + /// The `shutdown_script` provided will be used as the `scriptPubKey` for the closing transaction. + /// Will fail if a shutdown script has already been set for this channel by + /// ['ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`]. The given shutdown script must + /// also be compatible with our and the counterparty's features. + /// /// May generate a [`SendShutdown`] message event on success, which should be relayed. /// + /// Raises [`APIError::ChannelUnavailable`] if the channel cannot be closed due to failing to + /// generate a shutdown scriptpubkey or destination script set by + /// [`SignerProvider::get_shutdown_scriptpubkey`]. A force-closure may be needed to close the + /// channel. + /// /// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`]: crate::util::config::ChannelConfig::force_close_avoidance_max_fee_satoshis /// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background /// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal /// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown - pub fn close_channel_with_target_feerate(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: u32) -> Result<(), APIError> { - self.close_channel_internal(channel_id, counterparty_node_id, Some(target_feerate_sats_per_1000_weight)) + pub fn close_channel_with_feerate_and_script(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option, shutdown_script: Option) -> Result<(), APIError> { + self.close_channel_internal(channel_id, counterparty_node_id, target_feerate_sats_per_1000_weight, shutdown_script) } #[inline] @@ -2675,10 +2732,9 @@ where let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv) .map_err(|_| APIError::InvalidRoute{err: "Pubkey along hop was maliciously selected".to_owned()})?; let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, recipient_onion, cur_height, keysend_preimage)?; - if onion_utils::route_size_insane(&onion_payloads) { - return Err(APIError::InvalidRoute{err: "Route size too large considering onion data".to_owned()}); - } - let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash); + + let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash) + .map_err(|_| APIError::InvalidRoute { err: "Route size too large considering onion data".to_owned()})?; let err: Result<(), _> = loop { let (counterparty_node_id, id) = match self.short_to_chan_info.read().unwrap().get(&path.hops.first().unwrap().short_channel_id) { @@ -3037,6 +3093,12 @@ where } } self.funding_transaction_generated_intern(temporary_channel_id, counterparty_node_id, funding_transaction, |chan, tx| { + if tx.output.len() > u16::max_value() as usize { + return Err(APIError::APIMisuseError { + err: "Transaction had more than 2^16 outputs, which is not supported".to_owned() + }); + } + let mut output_index = None; let expected_spk = chan.get_funding_redeemscript().to_v0_p2wsh(); for (idx, outp) in tx.output.iter().enumerate() { @@ -3046,11 +3108,6 @@ where err: "Multiple outputs matched the expected script and value".to_owned() }); } - if idx > u16::max_value() as usize { - return Err(APIError::APIMisuseError { - err: "Transaction had more than 2^16 outputs, which is not supported".to_owned() - }); - } output_index = Some(idx as u16); } } @@ -3236,7 +3293,7 @@ where pub fn process_pending_htlc_forwards(&self) { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); - let mut new_events = Vec::new(); + let mut new_events = VecDeque::new(); let mut failed_forwards = Vec::new(); let mut phantom_receives: Vec<(u64, OutPoint, u128, Vec<(PendingHTLCInfo, u64)>)> = Vec::new(); { @@ -3562,7 +3619,7 @@ where htlcs.push(claimable_htlc); let amount_msat = htlcs.iter().map(|htlc| htlc.value).sum(); htlcs.iter_mut().for_each(|htlc| htlc.total_value_received = Some(amount_msat)); - new_events.push(events::Event::PaymentClaimable { + new_events.push_back((events::Event::PaymentClaimable { receiver_node_id: Some(receiver_node_id), payment_hash, purpose: purpose(), @@ -3571,7 +3628,7 @@ where via_user_channel_id: Some(prev_user_channel_id), claim_deadline: Some(earliest_expiry - HTLC_FAIL_BACK_BUFFER), onion_fields: claimable_payment.onion_fields.clone(), - }); + }, None)); payment_claimable_generated = true; } else { // Nothing to do - we haven't reached the total @@ -3632,7 +3689,7 @@ where htlcs: vec![claimable_htlc], }); let prev_channel_id = prev_funding_outpoint.to_channel_id(); - new_events.push(events::Event::PaymentClaimable { + new_events.push_back((events::Event::PaymentClaimable { receiver_node_id: Some(receiver_node_id), payment_hash, amount_msat, @@ -3641,7 +3698,7 @@ where via_user_channel_id: Some(prev_user_channel_id), claim_deadline, onion_fields: Some(onion_fields), - }); + }, None)); }, hash_map::Entry::Occupied(_) => { log_trace!(self.logger, "Failing new keysend HTLC with payment_hash {} for a duplicative payment hash", log_bytes!(payment_hash.0)); @@ -3720,7 +3777,7 @@ where for event in background_events.drain(..) { match event { - BackgroundEvent::ClosingMonitorUpdate((funding_txo, update)) => { + BackgroundEvent::MonitorUpdateRegeneratedOnStartup((funding_txo, update)) => { // The channel has already been closed, so no use bothering to care about the // monitor updating completing. let _ = self.chain_monitor.update_channel(funding_txo, &update); @@ -4119,10 +4176,10 @@ where mem::drop(forward_htlcs); if push_forward_ev { self.push_pending_forwards_ev(); } let mut pending_events = self.pending_events.lock().unwrap(); - pending_events.push(events::Event::HTLCHandlingFailed { + pending_events.push_back((events::Event::HTLCHandlingFailed { prev_channel_id: outpoint.to_channel_id(), failed_next_destination: destination, - }); + }, None)); }, } } @@ -4385,13 +4442,13 @@ where MonitorUpdateCompletionAction::PaymentClaimed { payment_hash } => { let payment = self.claimable_payments.lock().unwrap().pending_claiming_payments.remove(&payment_hash); if let Some(ClaimingPayment { amount_msat, payment_purpose: purpose, receiver_node_id }) = payment { - self.pending_events.lock().unwrap().push(events::Event::PaymentClaimed { + self.pending_events.lock().unwrap().push_back((events::Event::PaymentClaimed { payment_hash, purpose, amount_msat, receiver_node_id: Some(receiver_node_id), - }); + }, None)); } }, MonitorUpdateCompletionAction::EmitEvent { event } => { - self.pending_events.lock().unwrap().push(event); + self.pending_events.lock().unwrap().push_back((event, None)); }, } } @@ -4715,15 +4772,13 @@ where }); } else { let mut pending_events = self.pending_events.lock().unwrap(); - pending_events.push( - events::Event::OpenChannelRequest { - temporary_channel_id: msg.temporary_channel_id.clone(), - counterparty_node_id: counterparty_node_id.clone(), - funding_satoshis: msg.funding_satoshis, - push_msat: msg.push_msat, - channel_type: channel.get_channel_type().clone(), - } - ); + pending_events.push_back((events::Event::OpenChannelRequest { + temporary_channel_id: msg.temporary_channel_id.clone(), + counterparty_node_id: counterparty_node_id.clone(), + funding_satoshis: msg.funding_satoshis, + push_msat: msg.push_msat, + channel_type: channel.get_channel_type().clone(), + }, None)); } entry.insert(channel); @@ -4751,13 +4806,13 @@ where } }; let mut pending_events = self.pending_events.lock().unwrap(); - pending_events.push(events::Event::FundingGenerationReady { + pending_events.push_back((events::Event::FundingGenerationReady { temporary_channel_id: msg.temporary_channel_id, counterparty_node_id: *counterparty_node_id, channel_value_satoshis: value, output_script, user_channel_id: user_id, - }); + }, None)); Ok(()) } @@ -5131,11 +5186,13 @@ where match peer_state.channel_by_id.entry(msg.channel_id) { hash_map::Entry::Occupied(mut chan) => { let funding_txo = chan.get().get_funding_txo(); - let monitor_update = try_chan_entry!(self, chan.get_mut().commitment_signed(&msg, &self.logger), chan); - let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update); - let update_id = monitor_update.update_id; - handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, - peer_state, per_peer_state, chan) + let monitor_update_opt = try_chan_entry!(self, chan.get_mut().commitment_signed(&msg, &self.logger), chan); + if let Some(monitor_update) = monitor_update_opt { + let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update); + let update_id = monitor_update.update_id; + handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, + peer_state, per_peer_state, chan) + } else { Ok(()) } }, hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id)) } @@ -5145,7 +5202,7 @@ where fn forward_htlcs(&self, per_source_pending_forwards: &mut [(u64, OutPoint, u128, Vec<(PendingHTLCInfo, u64)>)]) { for &mut (prev_short_channel_id, prev_funding_outpoint, prev_user_channel_id, ref mut pending_forwards) in per_source_pending_forwards { let mut push_forward_event = false; - let mut new_intercept_events = Vec::new(); + let mut new_intercept_events = VecDeque::new(); let mut failed_intercept_forwards = Vec::new(); if !pending_forwards.is_empty() { for (forward_info, prev_htlc_id) in pending_forwards.drain(..) { @@ -5172,13 +5229,13 @@ where let mut pending_intercepts = self.pending_intercepted_htlcs.lock().unwrap(); match pending_intercepts.entry(intercept_id) { hash_map::Entry::Vacant(entry) => { - new_intercept_events.push(events::Event::HTLCIntercepted { + new_intercept_events.push_back((events::Event::HTLCIntercepted { requested_next_hop_scid: scid, payment_hash: forward_info.payment_hash, inbound_amount_msat: forward_info.incoming_amt_msat.unwrap(), expected_outbound_amount_msat: forward_info.outgoing_amt_msat, intercept_id - }); + }, None)); entry.insert(PendingAddHTLCInfo { prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info }); }, @@ -5228,13 +5285,13 @@ where fn push_pending_forwards_ev(&self) { let mut pending_events = self.pending_events.lock().unwrap(); let forward_ev_exists = pending_events.iter() - .find(|ev| if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false }) + .find(|(ev, _)| if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false }) .is_some(); if !forward_ev_exists { - pending_events.push(events::Event::PendingHTLCsForwardable { + pending_events.push_back((events::Event::PendingHTLCsForwardable { time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS), - }); + }, None)); } } @@ -5250,11 +5307,13 @@ where match peer_state.channel_by_id.entry(msg.channel_id) { hash_map::Entry::Occupied(mut chan) => { let funding_txo = chan.get().get_funding_txo(); - let (htlcs_to_fail, monitor_update) = try_chan_entry!(self, chan.get_mut().revoke_and_ack(&msg, &self.logger), chan); - let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update); - let update_id = monitor_update.update_id; - let res = handle_new_monitor_update!(self, update_res, update_id, - peer_state_lock, peer_state, per_peer_state, chan); + let (htlcs_to_fail, monitor_update_opt) = try_chan_entry!(self, chan.get_mut().revoke_and_ack(&msg, &self.logger), chan); + let res = if let Some(monitor_update) = monitor_update_opt { + let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update); + let update_id = monitor_update.update_id; + handle_new_monitor_update!(self, update_res, update_id, + peer_state_lock, peer_state, per_peer_state, chan) + } else { Ok(()) }; (htlcs_to_fail, res) }, hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id)) @@ -5638,7 +5697,7 @@ where if let ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } = update.updates[0] { assert!(should_broadcast); } else { unreachable!(); } - self.pending_background_events.lock().unwrap().push(BackgroundEvent::ClosingMonitorUpdate((funding_txo, update))); + self.pending_background_events.lock().unwrap().push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup((funding_txo, update))); } self.finish_force_close_channel(failure); } @@ -5809,7 +5868,7 @@ where /// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids /// are used when constructing the phantom invoice's route hints. /// - /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager + /// [phantom node payments]: crate::sign::PhantomKeysManager pub fn get_phantom_scid(&self) -> u64 { let best_block_height = self.best_block.read().unwrap().height(); let short_to_chan_info = self.short_to_chan_info.read().unwrap(); @@ -5825,7 +5884,7 @@ where /// Gets route hints for use in receiving [phantom node payments]. /// - /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager + /// [phantom node payments]: crate::sign::PhantomKeysManager pub fn get_phantom_route_hints(&self) -> PhantomRouteHints { PhantomRouteHints { channels: self.list_usable_channels(), @@ -5883,13 +5942,13 @@ where #[cfg(feature = "_test_utils")] pub fn push_pending_event(&self, event: events::Event) { let mut events = self.pending_events.lock().unwrap(); - events.push(event); + events.push_back((event, None)); } #[cfg(test)] pub fn pop_pending_event(&self) -> Option { let mut events = self.pending_events.lock().unwrap(); - if events.is_empty() { None } else { Some(events.remove(0)) } + events.pop_front().map(|(e, _)| e) } #[cfg(test)] @@ -5902,6 +5961,72 @@ where self.pending_outbound_payments.clear_pending_payments() } + fn handle_monitor_update_release(&self, counterparty_node_id: PublicKey, channel_funding_outpoint: OutPoint) { + let mut errors = Vec::new(); + loop { + let per_peer_state = self.per_peer_state.read().unwrap(); + if let Some(peer_state_mtx) = per_peer_state.get(&counterparty_node_id) { + let mut peer_state_lck = peer_state_mtx.lock().unwrap(); + let peer_state = &mut *peer_state_lck; + if self.pending_events.lock().unwrap().iter() + .any(|(_ev, action_opt)| action_opt == &Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate { + channel_funding_outpoint, counterparty_node_id + })) + { + // Check that, while holding the peer lock, we don't have another event + // blocking any monitor updates for this channel. If we do, let those + // events be the ones that ultimately release the monitor update(s). + log_trace!(self.logger, "Delaying monitor unlock for channel {} as another event is pending", + log_bytes!(&channel_funding_outpoint.to_channel_id()[..])); + break; + } + if let hash_map::Entry::Occupied(mut chan) = peer_state.channel_by_id.entry(channel_funding_outpoint.to_channel_id()) { + debug_assert_eq!(chan.get().get_funding_txo().unwrap(), channel_funding_outpoint); + if let Some((monitor_update, further_update_exists)) = chan.get_mut().unblock_next_blocked_monitor_update() { + log_debug!(self.logger, "Unlocking monitor updating for channel {} and updating monitor", + log_bytes!(&channel_funding_outpoint.to_channel_id()[..])); + let update_res = self.chain_monitor.update_channel(channel_funding_outpoint, monitor_update); + let update_id = monitor_update.update_id; + if let Err(e) = handle_new_monitor_update!(self, update_res, update_id, + peer_state_lck, peer_state, per_peer_state, chan) + { + errors.push((e, counterparty_node_id)); + } + if further_update_exists { + // If there are more `ChannelMonitorUpdate`s to process, restart at the + // top of the loop. + continue; + } + } else { + log_trace!(self.logger, "Unlocked monitor updating for channel {} without monitors to update", + log_bytes!(&channel_funding_outpoint.to_channel_id()[..])); + } + } + } else { + log_debug!(self.logger, + "Got a release post-RAA monitor update for peer {} but the channel is gone", + log_pubkey!(counterparty_node_id)); + } + break; + } + for (err, counterparty_node_id) in errors { + let res = Err::<(), _>(err); + let _ = handle_error!(self, res, counterparty_node_id); + } + } + + fn handle_post_event_actions(&self, actions: Vec) { + for action in actions { + match action { + EventCompletionAction::ReleaseRAAChannelMonitorUpdate { + channel_funding_outpoint, counterparty_node_id + } => { + self.handle_monitor_update_release(counterparty_node_id, channel_funding_outpoint); + } + } + } + } + /// Processes any events asynchronously in the order they were generated since the last call /// using the given event handler. /// @@ -6367,11 +6492,23 @@ where let _ = handle_error!(self, self.internal_open_channel(counterparty_node_id, msg), *counterparty_node_id); } + fn handle_open_channel_v2(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannelV2) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.temporary_channel_id.clone())), *counterparty_node_id); + } + fn handle_accept_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannel) { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); let _ = handle_error!(self, self.internal_accept_channel(counterparty_node_id, msg), *counterparty_node_id); } + fn handle_accept_channel_v2(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannelV2) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.temporary_channel_id.clone())), *counterparty_node_id); + } + fn handle_funding_created(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingCreated) { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); let _ = handle_error!(self, self.internal_funding_created(counterparty_node_id, msg), *counterparty_node_id); @@ -6474,23 +6611,40 @@ where }); pending_msg_events.retain(|msg| { match msg { + // V1 Channel Establishment &events::MessageSendEvent::SendAcceptChannel { .. } => false, &events::MessageSendEvent::SendOpenChannel { .. } => false, &events::MessageSendEvent::SendFundingCreated { .. } => false, &events::MessageSendEvent::SendFundingSigned { .. } => false, + // V2 Channel Establishment + &events::MessageSendEvent::SendAcceptChannelV2 { .. } => false, + &events::MessageSendEvent::SendOpenChannelV2 { .. } => false, + // Common Channel Establishment &events::MessageSendEvent::SendChannelReady { .. } => false, &events::MessageSendEvent::SendAnnouncementSignatures { .. } => false, + // Interactive Transaction Construction + &events::MessageSendEvent::SendTxAddInput { .. } => false, + &events::MessageSendEvent::SendTxAddOutput { .. } => false, + &events::MessageSendEvent::SendTxRemoveInput { .. } => false, + &events::MessageSendEvent::SendTxRemoveOutput { .. } => false, + &events::MessageSendEvent::SendTxComplete { .. } => false, + &events::MessageSendEvent::SendTxSignatures { .. } => false, + &events::MessageSendEvent::SendTxInitRbf { .. } => false, + &events::MessageSendEvent::SendTxAckRbf { .. } => false, + &events::MessageSendEvent::SendTxAbort { .. } => false, + // Channel Operations &events::MessageSendEvent::UpdateHTLCs { .. } => false, &events::MessageSendEvent::SendRevokeAndACK { .. } => false, &events::MessageSendEvent::SendClosingSigned { .. } => false, &events::MessageSendEvent::SendShutdown { .. } => false, &events::MessageSendEvent::SendChannelReestablish { .. } => false, + &events::MessageSendEvent::HandleError { .. } => false, + // Gossip &events::MessageSendEvent::SendChannelAnnouncement { .. } => false, &events::MessageSendEvent::BroadcastChannelAnnouncement { .. } => true, &events::MessageSendEvent::BroadcastChannelUpdate { .. } => true, &events::MessageSendEvent::BroadcastNodeAnnouncement { .. } => true, &events::MessageSendEvent::SendChannelUpdate { .. } => false, - &events::MessageSendEvent::HandleError { .. } => false, &events::MessageSendEvent::SendChannelRangeQuery { .. } => false, &events::MessageSendEvent::SendShortIdsQuery { .. } => false, &events::MessageSendEvent::SendReplyChannelRange { .. } => false, @@ -6647,6 +6801,60 @@ where fn provided_init_features(&self, _their_init_features: &PublicKey) -> InitFeatures { provided_init_features(&self.default_configuration) } + + fn handle_tx_add_input(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAddInput) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_add_output(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAddOutput) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_remove_input(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxRemoveInput) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_remove_output(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxRemoveOutput) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_complete(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxComplete) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_signatures(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxSignatures) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_init_rbf(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxInitRbf) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_ack_rbf(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAckRbf) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } + + fn handle_tx_abort(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAbort) { + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.channel_id.clone())), *counterparty_node_id); + } } /// Fetches the set of [`NodeFeatures`] flags which are provided by or required by @@ -6684,7 +6892,7 @@ pub fn provided_init_features(_config: &UserConfig) -> InitFeatures { // 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_data_loss_protect_required(); features.set_upfront_shutdown_script_optional(); features.set_variable_length_onion_required(); features.set_static_remote_key_required(); @@ -7047,8 +7255,10 @@ impl Readable for HTLCSource { return Err(DecodeError::InvalidValue); } if let Some(params) = payment_params.as_mut() { - if params.final_cltv_expiry_delta == 0 { - params.final_cltv_expiry_delta = path.final_cltv_expiry_delta().ok_or(DecodeError::InvalidValue)?; + if let Payee::Clear { ref mut final_cltv_expiry_delta, .. } = params.payee { + if final_cltv_expiry_delta == &0 { + *final_cltv_expiry_delta = path.final_cltv_expiry_delta().ok_or(DecodeError::InvalidValue)?; + } } } Ok(HTLCSource::OutboundRoute { @@ -7226,23 +7436,28 @@ where } let events = self.pending_events.lock().unwrap(); - (events.len() as u64).write(writer)?; - for event in events.iter() { - event.write(writer)?; - } - - let background_events = self.pending_background_events.lock().unwrap(); - (background_events.len() as u64).write(writer)?; - for event in background_events.iter() { - match event { - BackgroundEvent::ClosingMonitorUpdate((funding_txo, monitor_update)) => { - 0u8.write(writer)?; - funding_txo.write(writer)?; - monitor_update.write(writer)?; - }, + // LDK versions prior to 0.0.115 don't support post-event actions, thus if there's no + // actions at all, skip writing the required TLV. Otherwise, pre-0.0.115 versions will + // refuse to read the new ChannelManager. + let events_not_backwards_compatible = events.iter().any(|(_, action)| action.is_some()); + if events_not_backwards_compatible { + // If we're gonna write a even TLV that will overwrite our events anyway we might as + // well save the space and not write any events here. + 0u64.write(writer)?; + } else { + (events.len() as u64).write(writer)?; + for (event, _) in events.iter() { + event.write(writer)?; } } + // LDK versions prior to 0.0.116 wrote the `pending_background_events` + // `MonitorUpdateRegeneratedOnStartup`s here, however there was never a reason to do so - + // the closing monitor updates were always effectively replayed on startup (either directly + // by calling `broadcast_latest_holder_commitment_txn` on a `ChannelMonitor` during + // deserialization or, in 0.0.115, by regenerating the monitor update itself). + 0u64.write(writer)?; + // Prior to 0.0.111 we tracked node_announcement serials here, however that now happens in // `PeerManager`, and thus we simply write the `highest_seen_timestamp` twice, which is // likely to be identical. @@ -7309,6 +7524,7 @@ where (5, self.our_network_pubkey, required), (6, monitor_update_blocked_actions_per_peer, option), (7, self.fake_scid_rand_bytes, required), + (8, if events_not_backwards_compatible { Some(&*events) } else { None }, option), (9, htlc_purposes, vec_type), (11, self.probing_cookie_secret, required), (13, htlc_onion_fields, optional_vec), @@ -7318,6 +7534,47 @@ where } } +impl Writeable for VecDeque<(Event, Option)> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + (self.len() as u64).write(w)?; + for (event, action) in self.iter() { + event.write(w)?; + action.write(w)?; + #[cfg(debug_assertions)] { + // Events are MaybeReadable, in some cases indicating that they shouldn't actually + // be persisted and are regenerated on restart. However, if such an event has a + // post-event-handling action we'll write nothing for the event and would have to + // either forget the action or fail on deserialization (which we do below). Thus, + // check that the event is sane here. + let event_encoded = event.encode(); + let event_read: Option = + MaybeReadable::read(&mut &event_encoded[..]).unwrap(); + if action.is_some() { assert!(event_read.is_some()); } + } + } + Ok(()) + } +} +impl Readable for VecDeque<(Event, Option)> { + fn read(reader: &mut R) -> Result { + let len: u64 = Readable::read(reader)?; + const MAX_ALLOC_SIZE: u64 = 1024 * 16; + let mut events: Self = VecDeque::with_capacity(cmp::min( + MAX_ALLOC_SIZE/mem::size_of::<(events::Event, Option)>() as u64, + len) as usize); + for _ in 0..len { + let ev_opt = MaybeReadable::read(reader)?; + let action = Readable::read(reader)?; + if let Some(ev) = ev_opt { + events.push_back((ev, action)); + } else if action.is_some() { + return Err(DecodeError::InvalidValue); + } + } + Ok(events) + } +} + /// Arguments for the creation of a ChannelManager that are not deserialized. /// /// At a high-level, the process for deserializing a ChannelManager and resuming normal operation @@ -7484,7 +7741,7 @@ where let mut peer_channels: HashMap::Signer>>> = HashMap::with_capacity(cmp::min(channel_count as usize, 128)); let mut id_to_peer = HashMap::with_capacity(cmp::min(channel_count as usize, 128)); let mut short_to_chan_info = HashMap::with_capacity(cmp::min(channel_count as usize, 128)); - let mut channel_closures = Vec::new(); + let mut channel_closures = VecDeque::new(); let mut pending_background_events = Vec::new(); for _ in 0..channel_count { let mut channel: Channel<::Signer> = Channel::read(reader, ( @@ -7493,14 +7750,11 @@ where let funding_txo = channel.get_funding_txo().ok_or(DecodeError::InvalidValue)?; funding_txo_set.insert(funding_txo.clone()); if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) { - if channel.get_cur_holder_commitment_transaction_number() < monitor.get_cur_holder_commitment_number() || - channel.get_revoked_counterparty_commitment_transaction_number() < monitor.get_min_seen_secret() || - channel.get_cur_counterparty_commitment_transaction_number() < monitor.get_cur_counterparty_commitment_number() || - channel.get_latest_monitor_update_id() > monitor.get_latest_update_id() { + if channel.get_latest_complete_monitor_update_id() > monitor.get_latest_update_id() { // If the channel is ahead of the monitor, return InvalidValue: log_error!(args.logger, "A ChannelMonitor is stale compared to the current ChannelManager! This indicates a potentially-critical violation of the chain::Watch API!"); log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} but the ChannelManager is at update_id {}.", - log_bytes!(channel.channel_id()), monitor.get_latest_update_id(), channel.get_latest_monitor_update_id()); + log_bytes!(channel.channel_id()), monitor.get_latest_update_id(), channel.get_latest_complete_monitor_update_id()); log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,"); log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!"); log_error!(args.logger, " Without the latest ChannelMonitor we cannot continue without risking funds."); @@ -7517,14 +7771,14 @@ where log_bytes!(channel.channel_id()), monitor.get_latest_update_id(), channel.get_latest_monitor_update_id()); let (monitor_update, mut new_failed_htlcs) = channel.force_shutdown(true); if let Some(monitor_update) = monitor_update { - pending_background_events.push(BackgroundEvent::ClosingMonitorUpdate(monitor_update)); + pending_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup(monitor_update)); } failed_htlcs.append(&mut new_failed_htlcs); - channel_closures.push(events::Event::ChannelClosed { + channel_closures.push_back((events::Event::ChannelClosed { channel_id: channel.channel_id(), user_channel_id: channel.get_user_id(), reason: ClosureReason::OutdatedChannelManager - }); + }, None)); for (channel_htlc_source, payment_hash) in channel.inflight_htlc_sources() { let mut found_htlc = false; for (monitor_htlc_source, _) in monitor.get_all_current_outbound_htlcs() { @@ -7569,11 +7823,11 @@ where // was in-progress, we never broadcasted the funding transaction and can still // safely discard the channel. let _ = channel.force_shutdown(false); - channel_closures.push(events::Event::ChannelClosed { + channel_closures.push_back((events::Event::ChannelClosed { channel_id: channel.channel_id(), user_channel_id: channel.get_user_id(), reason: ClosureReason::DisconnectedPeer, - }); + }, None)); } else { log_error!(args.logger, "Missing ChannelMonitor for channel {} needed by ChannelManager.", log_bytes!(channel.channel_id())); log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,"); @@ -7586,11 +7840,13 @@ where for (funding_txo, _) in args.channel_monitors.iter() { if !funding_txo_set.contains(funding_txo) { + log_info!(args.logger, "Queueing monitor update to ensure missing channel {} is force closed", + log_bytes!(funding_txo.to_channel_id())); let monitor_update = ChannelMonitorUpdate { update_id: CLOSED_CHANNEL_UPDATE_ID, updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast: true }], }; - pending_background_events.push(BackgroundEvent::ClosingMonitorUpdate((*funding_txo, monitor_update))); + pending_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup((*funding_txo, monitor_update))); } } @@ -7634,10 +7890,11 @@ where } let event_count: u64 = Readable::read(reader)?; - let mut pending_events_read: Vec = Vec::with_capacity(cmp::min(event_count as usize, MAX_ALLOC_SIZE/mem::size_of::())); + let mut pending_events_read: VecDeque<(events::Event, Option)> = + VecDeque::with_capacity(cmp::min(event_count as usize, MAX_ALLOC_SIZE/mem::size_of::<(events::Event, Option)>())); for _ in 0..event_count { match MaybeReadable::read(reader)? { - Some(event) => pending_events_read.push(event), + Some(event) => pending_events_read.push_back((event, None)), None => continue, } } @@ -7646,13 +7903,11 @@ where for _ in 0..background_event_count { match ::read(reader)? { 0 => { - let (funding_txo, monitor_update): (OutPoint, ChannelMonitorUpdate) = (Readable::read(reader)?, Readable::read(reader)?); - if pending_background_events.iter().find(|e| { - let BackgroundEvent::ClosingMonitorUpdate((pending_funding_txo, pending_monitor_update)) = e; - *pending_funding_txo == funding_txo && *pending_monitor_update == monitor_update - }).is_none() { - pending_background_events.push(BackgroundEvent::ClosingMonitorUpdate((funding_txo, monitor_update))); - } + // LDK versions prior to 0.0.116 wrote pending `MonitorUpdateRegeneratedOnStartup`s here, + // however we really don't (and never did) need them - we regenerate all + // on-startup monitor updates. + let _: OutPoint = Readable::read(reader)?; + let _: ChannelMonitorUpdate = Readable::read(reader)?; } _ => return Err(DecodeError::InvalidValue), } @@ -7693,6 +7948,7 @@ where let mut claimable_htlc_onion_fields = None; let mut pending_claiming_payments = Some(HashMap::new()); let mut monitor_update_blocked_actions_per_peer = Some(Vec::new()); + let mut events_override = None; read_tlv_fields!(reader, { (1, pending_outbound_payments_no_retry, option), (2, pending_intercepted_htlcs, option), @@ -7701,6 +7957,7 @@ where (5, received_network_pubkey, option), (6, monitor_update_blocked_actions_per_peer, option), (7, fake_scid_rand_bytes, option), + (8, events_override, option), (9, claimable_htlc_purposes, vec_type), (11, probing_cookie_secret, option), (13, claimable_htlc_onion_fields, optional_vec), @@ -7713,6 +7970,10 @@ where probing_cookie_secret = Some(args.entropy_source.get_secure_random_bytes()); } + if let Some(events) = events_override { + pending_events_read = events; + } + if !channel_closures.is_empty() { pending_events_read.append(&mut channel_closures); } @@ -7808,7 +8069,7 @@ where if pending_forward_matches_htlc(&htlc_info) { log_info!(args.logger, "Removing pending intercepted HTLC with hash {} as it was forwarded to the closed channel {}", log_bytes!(htlc.payment_hash.0), log_bytes!(monitor.get_funding_txo().0.to_channel_id())); - pending_events_read.retain(|event| { + pending_events_read.retain(|(event, _)| { if let Event::HTLCIntercepted { intercept_id: ev_id, .. } = event { intercepted_id != ev_id } else { true } @@ -7844,9 +8105,9 @@ where // shut down before the timer hit. Either way, set the time_forwardable to a small // constant as enough time has likely passed that we should simply handle the forwards // now, or at least after the user gets a chance to reconnect to our peers. - pending_events_read.push(events::Event::PendingHTLCsForwardable { + pending_events_read.push_back((events::Event::PendingHTLCsForwardable { time_forwardable: Duration::from_secs(2), - }); + }, None)); } let inbound_pmt_key_material = args.node_signer.get_inbound_payment_key_material(); @@ -8000,12 +8261,12 @@ where previous_hop_monitor.provide_payment_preimage(&payment_hash, &payment_preimage, &args.tx_broadcaster, &bounded_fee_estimator, &args.logger); } } - pending_events_read.push(events::Event::PaymentClaimed { + pending_events_read.push_back((events::Event::PaymentClaimed { receiver_node_id, payment_hash, purpose: payment.purpose, amount_msat: claimable_amt_msat, - }); + }, None)); } } } @@ -8093,7 +8354,7 @@ mod tests { use crate::util::errors::APIError; use crate::util::test_utils; use crate::util::config::ChannelConfig; - use crate::chain::keysinterface::EntropySource; + use crate::sign::EntropySource; #[test] fn test_notify_limits() { @@ -8324,7 +8585,7 @@ mod tests { }; let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph, - None, nodes[0].logger, &scorer, &random_seed_bytes + None, nodes[0].logger, &scorer, &(), &random_seed_bytes ).unwrap(); nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage), RecipientOnionFields::spontaneous_empty(), PaymentId(payment_preimage.0)).unwrap(); @@ -8358,7 +8619,7 @@ mod tests { let payment_preimage = PaymentPreimage([42; 32]); let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph, - None, nodes[0].logger, &scorer, &random_seed_bytes + None, nodes[0].logger, &scorer, &(), &random_seed_bytes ).unwrap(); let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage), RecipientOnionFields::spontaneous_empty(), PaymentId(payment_preimage.0)).unwrap(); @@ -8421,7 +8682,7 @@ mod tests { let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::>()), - nodes[0].logger, &scorer, &random_seed_bytes + nodes[0].logger, &scorer, &(), &random_seed_bytes ).unwrap(); let test_preimage = PaymentPreimage([42; 32]); @@ -8465,7 +8726,7 @@ mod tests { let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::>()), - nodes[0].logger, &scorer, &random_seed_bytes + nodes[0].logger, &scorer, &(), &random_seed_bytes ).unwrap(); let test_preimage = PaymentPreimage([42; 32]); @@ -9009,7 +9270,7 @@ mod tests { pub mod bench { use crate::chain::Listen; use crate::chain::chainmonitor::{ChainMonitor, Persist}; - use crate::chain::keysinterface::{KeysManager, InMemorySigner}; + use crate::sign::{KeysManager, InMemorySigner}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider}; use crate::ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentId, RecipientOnionFields, Retry}; use crate::ln::functional_test_utils::*; @@ -9122,10 +9383,7 @@ pub mod bench { assert_eq!(&tx_broadcaster.txn_broadcasted.lock().unwrap()[..], &[tx.clone()]); - let block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: BestBlock::from_network(network).block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }, - txdata: vec![tx], - }; + let block = create_dummy_block(BestBlock::from_network(network).block_hash(), 42, vec![tx]); Listen::block_connected(&node_a, &block, 1); Listen::block_connected(&node_b, &block, 1); @@ -9166,7 +9424,7 @@ pub mod bench { macro_rules! send_payment { ($node_a: expr, $node_b: expr) => { let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id(), TEST_FINAL_CLTV) - .with_features($node_b.invoice_features()); + .with_bolt11_features($node_b.invoice_features()).unwrap(); let mut payment_preimage = PaymentPreimage([0; 32]); payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes()); payment_count += 1; diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index cf375603b..b8087546c 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -422,8 +422,10 @@ pub struct Features { mark: PhantomData, } -impl Features { - pub(crate) fn or(mut self, o: Self) -> Self { +impl core::ops::BitOr for Features { + type Output = Self; + + fn bitor(mut self, o: Self) -> Self { let total_feature_len = cmp::max(self.flags.len(), o.flags.len()); self.flags.resize(total_feature_len, 0u8); for (byte, o_byte) in self.flags.iter_mut().zip(o.flags.iter()) { @@ -451,6 +453,16 @@ impl PartialEq for Features { self.flags.eq(&o.flags) } } +impl PartialOrd for Features { + fn partial_cmp(&self, other: &Self) -> Option { + self.flags.partial_cmp(&other.flags) + } +} +impl Ord for Features { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.flags.cmp(&other.flags) + } +} impl fmt::Debug for Features { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.flags.fmt(fmt) @@ -532,6 +544,14 @@ impl InvoiceFeatures { } } +impl Bolt12InvoiceFeatures { + /// Converts `Bolt12InvoiceFeatures` to `Features`. Only known `Bolt12InvoiceFeatures` relevant + /// to context `C` are included in the result. + pub(crate) fn to_context(&self) -> Features { + self.to_context_internal() + } +} + impl ChannelTypeFeatures { // Maps the relevant `InitFeatures` to `ChannelTypeFeatures`. Any unknown features to // `ChannelTypeFeatures` are not included in the result. @@ -677,6 +697,25 @@ impl Features { self.flags.iter().any(|&byte| (byte & 0b10_10_10_10) != 0) } + /// Returns true if this `Features` object contains required features unknown by `other`. + pub fn requires_unknown_bits_from(&self, other: &Features) -> bool { + // Bitwise AND-ing with all even bits set except for known features will select required + // unknown features. + self.flags.iter().enumerate().any(|(i, &byte)| { + const REQUIRED_FEATURES: u8 = 0b01_01_01_01; + const OPTIONAL_FEATURES: u8 = 0b10_10_10_10; + let unknown_features = if i < other.flags.len() { + // Form a mask similar to !T::KNOWN_FEATURE_MASK only for `other` + !(other.flags[i] + | ((other.flags[i] >> 1) & REQUIRED_FEATURES) + | ((other.flags[i] << 1) & OPTIONAL_FEATURES)) + } else { + 0b11_11_11_11 + }; + (byte & (REQUIRED_FEATURES & unknown_features)) != 0 + }) + } + /// Returns true if this `Features` object contains unknown feature flags which are set as /// "required". pub fn requires_unknown_bits(&self) -> bool { @@ -725,6 +764,50 @@ impl Features { } true } + + /// Sets a required custom feature bit. Errors if `bit` is outside the custom range as defined + /// by [bLIP 2] or if it is a known `T` feature. + /// + /// Note: Required bits are even. If an odd bit is given, then the corresponding even bit will + /// be set instead (i.e., `bit - 1`). + /// + /// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits + pub fn set_required_custom_bit(&mut self, bit: usize) -> Result<(), ()> { + self.set_custom_bit(bit - (bit % 2)) + } + + /// Sets an optional custom feature bit. Errors if `bit` is outside the custom range as defined + /// by [bLIP 2] or if it is a known `T` feature. + /// + /// Note: Optional bits are odd. If an even bit is given, then the corresponding odd bit will be + /// set instead (i.e., `bit + 1`). + /// + /// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits + pub fn set_optional_custom_bit(&mut self, bit: usize) -> Result<(), ()> { + self.set_custom_bit(bit + (1 - (bit % 2))) + } + + fn set_custom_bit(&mut self, bit: usize) -> Result<(), ()> { + if bit < 256 { + return Err(()); + } + + let byte_offset = bit / 8; + let mask = 1 << (bit - 8 * byte_offset); + if byte_offset < T::KNOWN_FEATURE_MASK.len() { + if (T::KNOWN_FEATURE_MASK[byte_offset] & mask) != 0 { + return Err(()); + } + } + + if self.flags.len() <= byte_offset { + self.flags.resize(byte_offset + 1, 0u8); + } + + self.flags[byte_offset] |= mask; + + Ok(()) + } } impl Features { @@ -791,6 +874,7 @@ impl_feature_len_prefixed_write!(InitFeatures); impl_feature_len_prefixed_write!(ChannelFeatures); impl_feature_len_prefixed_write!(NodeFeatures); impl_feature_len_prefixed_write!(InvoiceFeatures); +impl_feature_len_prefixed_write!(Bolt12InvoiceFeatures); impl_feature_len_prefixed_write!(BlindedHopFeatures); // Some features only appear inside of TLVs, so they don't have a length prefix when serialized. @@ -850,24 +934,61 @@ mod tests { assert!(features.supports_unknown_bits()); } + #[test] + fn requires_unknown_bits_from() { + let mut features1 = InitFeatures::empty(); + let mut features2 = InitFeatures::empty(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features1.set_data_loss_protect_required(); + assert!(features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features2.set_data_loss_protect_optional(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features2.set_gossip_queries_required(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(features2.requires_unknown_bits_from(&features1)); + + features1.set_gossip_queries_optional(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features1.set_variable_length_onion_required(); + assert!(features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features2.set_variable_length_onion_optional(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features1.set_basic_mpp_required(); + features2.set_wumbo_required(); + assert!(features1.requires_unknown_bits_from(&features2)); + assert!(features2.requires_unknown_bits_from(&features1)); + } + #[test] fn convert_to_context_with_relevant_flags() { 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_data_loss_protect_required(); 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_anchors_zero_fee_htlc_tx_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(); - init_features.set_anchors_zero_fee_htlc_tx_optional(); assert!(init_features.initial_routing_sync()); assert!(!init_features.supports_upfront_shutdown_script()); @@ -876,15 +997,15 @@ mod tests { let node_features: NodeFeatures = init_features.to_context(); { // Check that the flags are as expected: - // - option_data_loss_protect + // - option_data_loss_protect (req) // - var_onion_optin (req) | static_remote_key (req) | payment_secret(req) - // - basic_mpp | wumbo + // - basic_mpp | wumbo | anchors_zero_fee_htlc_tx // - opt_shutdown_anysegwit // - onion_messages // - option_channel_type | option_scid_alias // - option_zeroconf assert_eq!(node_features.flags.len(), 7); - assert_eq!(node_features.flags[0], 0b00000010); + assert_eq!(node_features.flags[0], 0b00000001); assert_eq!(node_features.flags[1], 0b01010001); assert_eq!(node_features.flags[2], 0b10001010); assert_eq!(node_features.flags[3], 0b00001000); @@ -926,6 +1047,36 @@ mod tests { assert!(features.supports_payment_secret()); } + #[test] + fn set_custom_bits() { + let mut features = InvoiceFeatures::empty(); + features.set_variable_length_onion_optional(); + assert_eq!(features.flags[1], 0b00000010); + + assert!(features.set_optional_custom_bit(255).is_err()); + assert!(features.set_required_custom_bit(256).is_ok()); + assert!(features.set_required_custom_bit(258).is_ok()); + assert_eq!(features.flags[31], 0b00000000); + assert_eq!(features.flags[32], 0b00000101); + + let known_bit = ::EVEN_BIT; + let byte_offset = ::BYTE_OFFSET; + assert_eq!(byte_offset, 1); + assert_eq!(features.flags[byte_offset], 0b00000010); + assert!(features.set_required_custom_bit(known_bit).is_err()); + assert_eq!(features.flags[byte_offset], 0b00000010); + + let mut features = InvoiceFeatures::empty(); + assert!(features.set_optional_custom_bit(256).is_ok()); + assert!(features.set_optional_custom_bit(259).is_ok()); + assert_eq!(features.flags[32], 0b00001010); + + let mut features = InvoiceFeatures::empty(); + assert!(features.set_required_custom_bit(257).is_ok()); + assert!(features.set_required_custom_bit(258).is_ok()); + assert_eq!(features.flags[32], 0b00000101); + } + #[test] fn encodes_features_without_length() { let features = OfferFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 50aed2c5b..fa8bdcc58 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -10,7 +10,8 @@ //! A bunch of useful utilities for building networks of nodes and exchanging messages between //! nodes for functional tests. -use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, keysinterface::EntropySource}; +use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch}; +use crate::sign::EntropySource; use crate::chain::channelmonitor::ChannelMonitor; use crate::chain::transaction::OutPoint; use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason}; @@ -84,16 +85,14 @@ pub fn confirm_transactions_at<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn: if conf_height > first_connect_height { connect_blocks(node, conf_height - first_connect_height); } - let mut block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: node.best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: conf_height, bits: 42, nonce: 42 }, - txdata: Vec::new(), - }; + let mut txdata = Vec::new(); for _ in 0..*node.network_chan_count.borrow() { // Make sure we don't end up with channels at the same short id by offsetting by chan_count - block.txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }); + txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }); } for tx in txn { - block.txdata.push((*tx).clone()); + txdata.push((*tx).clone()); } + let block = create_dummy_block(node.best_block_hash(), conf_height, txdata); connect_block(node, &block); scid_utils::scid_from_parts(conf_height as u64, block.txdata.len() as u64 - 1, 0).unwrap() } @@ -190,22 +189,31 @@ impl ConnectStyle { } } +pub fn create_dummy_header(prev_blockhash: BlockHash, time: u32) -> BlockHeader { + BlockHeader { + version: 0x2000_0000, + prev_blockhash, + merkle_root: TxMerkleNode::all_zeros(), + time, + bits: 42, + nonce: 42, + } +} + +pub fn create_dummy_block(prev_blockhash: BlockHash, time: u32, txdata: Vec) -> Block { + Block { header: create_dummy_header(prev_blockhash, time), txdata } +} + pub fn connect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, depth: u32) -> BlockHash { let skip_intermediaries = node.connect_style.borrow().skips_blocks(); let height = node.best_block_info().1 + 1; - let mut block = Block { - header: BlockHeader { version: 0x2000000, prev_blockhash: node.best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: height, bits: 42, nonce: 42 }, - txdata: vec![], - }; + let mut block = create_dummy_block(node.best_block_hash(), height, Vec::new()); assert!(depth >= 1); for i in 1..depth { let prev_blockhash = block.header.block_hash(); do_connect_block(node, block, skip_intermediaries); - block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash, merkle_root: TxMerkleNode::all_zeros(), time: height + i, bits: 42, nonce: 42 }, - txdata: vec![], - }; + block = create_dummy_block(prev_blockhash, height + i, Vec::new()); } let hash = block.header.block_hash(); do_connect_block(node, block, false); @@ -723,6 +731,39 @@ pub fn remove_first_msg_event_to_node(msg_node_id: &PublicKey, msg_events: &mut MessageSendEvent::SendGossipTimestampFilter { node_id, .. } => { node_id == msg_node_id }, + MessageSendEvent::SendAcceptChannelV2 { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendOpenChannelV2 { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAddInput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAddOutput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxRemoveInput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxRemoveOutput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxComplete { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxSignatures { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxInitRbf { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAckRbf { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAbort { node_id, .. } => { + node_id == msg_node_id + }, }}); if ev_index.is_some() { msg_events.remove(ev_index.unwrap()) @@ -1697,14 +1738,14 @@ macro_rules! get_payment_preimage_hash { } /// Gets a route from the given sender to the node described in `payment_params`. -pub fn get_route(send_node: &Node, payment_params: &PaymentParameters, recv_value: u64, final_cltv_expiry_delta: u32) -> Result { +pub fn get_route(send_node: &Node, payment_params: &PaymentParameters, recv_value: u64) -> Result { let scorer = TestScorer::new(); let keys_manager = TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); router::get_route( &send_node.node.get_our_node_id(), payment_params, &send_node.network_graph.read_only(), Some(&send_node.node.list_usable_channels().iter().collect::>()), - recv_value, final_cltv_expiry_delta, send_node.logger, &scorer, &random_seed_bytes + recv_value, send_node.logger, &scorer, &(), &random_seed_bytes ) } @@ -1713,8 +1754,8 @@ pub fn get_route(send_node: &Node, payment_params: &PaymentParameters, recv_valu /// Don't use this, use the identically-named function instead. #[macro_export] macro_rules! get_route { - ($send_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => { - $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value, $cltv) + ($send_node: expr, $payment_params: expr, $recv_value: expr) => { + $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value) } } @@ -1723,13 +1764,13 @@ macro_rules! get_route { 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(), TEST_FINAL_CLTV) - .with_features($recv_node.node.invoice_features()); - $crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value, TEST_FINAL_CLTV) + .with_bolt11_features($recv_node.node.invoice_features()).unwrap(); + $crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value) }}; - ($send_node: expr, $recv_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{ + ($send_node: expr, $recv_node: expr, $payment_params: expr, $recv_value: expr) => {{ let (payment_preimage, payment_hash, payment_secret) = $crate::ln::functional_test_utils::get_payment_preimage_hash(&$recv_node, Some($recv_value), None); - let route = $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value, $cltv); + let route = $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value); (route.unwrap(), payment_hash, payment_preimage, payment_secret) }} } @@ -2272,8 +2313,8 @@ pub const TEST_FINAL_CLTV: u32 = 70; 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(), TEST_FINAL_CLTV) - .with_features(expected_route.last().unwrap().node.invoice_features()); - let route = get_route(origin_node, &payment_params, recv_value, TEST_FINAL_CLTV).unwrap(); + .with_bolt11_features(expected_route.last().unwrap().node.invoice_features()).unwrap(); + let route = get_route(origin_node, &payment_params, recv_value).unwrap(); assert_eq!(route.paths.len(), 1); assert_eq!(route.paths[0].hops.len(), expected_route.len()); for (node, hop) in expected_route.iter().zip(route.paths[0].hops.iter()) { @@ -2286,7 +2327,7 @@ pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: 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(), TEST_FINAL_CLTV) - .with_features(expected_route.last().unwrap().node.invoice_features()); + .with_bolt11_features(expected_route.last().unwrap().node.invoice_features()).unwrap(); let network_graph = origin_node.network_graph.read_only(); let scorer = test_utils::TestScorer::new(); let seed = [0u8; 32]; @@ -2294,7 +2335,7 @@ pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_rou let random_seed_bytes = keys_manager.get_secure_random_bytes(); let route = router::get_route( &origin_node.node.get_our_node_id(), &payment_params, &network_graph, - None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap(); + None, recv_value, origin_node.logger, &scorer, &(), &random_seed_bytes).unwrap(); assert_eq!(route.paths.len(), 1); assert_eq!(route.paths[0].hops.len(), expected_route.len()); for (node, hop) in expected_route.iter().zip(route.paths[0].hops.iter()) { diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 2b8c8b8e3..98fc4bd95 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -17,7 +17,7 @@ use crate::chain::chaininterface::LowerBoundedFeeEstimator; use crate::chain::channelmonitor; use crate::chain::channelmonitor::{CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY}; use crate::chain::transaction::OutPoint; -use crate::chain::keysinterface::{ChannelSigner, EcdsaChannelSigner, EntropySource}; +use crate::sign::{ChannelSigner, EcdsaChannelSigner, EntropySource}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason}; use crate::ln::{PaymentPreimage, PaymentSecret, PaymentHash}; use crate::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}; @@ -38,12 +38,11 @@ use crate::util::string::UntrustedString; use crate::util::config::UserConfig; use bitcoin::hash_types::BlockHash; -use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::blockdata::script::{Builder, Script}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::constants::genesis_block; use bitcoin::network::constants::Network; -use bitcoin::{PackedLockTime, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Witness}; +use bitcoin::{PackedLockTime, Sequence, Transaction, TxIn, TxOut, Witness}; use bitcoin::OutPoint as BitcoinOutPoint; use bitcoin::secp256k1::Secp256k1; @@ -509,10 +508,7 @@ fn do_test_sanity_on_in_flight_opens(steps: u8) { let nodes = create_network(2, &node_cfgs, &node_chanmgrs); if steps & 0b1000_0000 != 0{ - let block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }, - txdata: vec![], - }; + let block = create_dummy_block(nodes[0].best_block_hash(), 42, Vec::new()); connect_block(&nodes[0], &block); connect_block(&nodes[1], &block); } @@ -1383,7 +1379,7 @@ fn test_fee_spike_violation_fails_htlc() { let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap(); let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, RecipientOnionFields::secret_only(payment_secret), cur_height, &None).unwrap(); - let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash); + let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap(); let msg = msgs::UpdateAddHTLC { channel_id: chan.2, htlc_id: 0, @@ -1571,7 +1567,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() { let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap(); let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 700_000, RecipientOnionFields::secret_only(payment_secret), cur_height, &None).unwrap(); - let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash); + let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap(); let msg = msgs::UpdateAddHTLC { channel_id: chan.2, htlc_id: MIN_AFFORDABLE_HTLC_COUNT as u64, @@ -1745,7 +1741,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap(); let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads( &route_2.paths[0], recv_value_2, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap(); - let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1); + let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1).unwrap(); let msg = msgs::UpdateAddHTLC { channel_id: chan.2, htlc_id: 1, @@ -1829,8 +1825,8 @@ fn test_channel_reserve_holding_cell_htlcs() { // 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(), TEST_FINAL_CLTV) - .with_features(nodes[2].node.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); + .with_bolt11_features(nodes[2].node.invoice_features()).unwrap().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); route.paths[0].hops.last_mut().unwrap().fee_msat += 1; assert!(route.paths[0].hops.iter().rev().skip(1).all(|h| h.fee_msat == feemsat)); @@ -1856,8 +1852,8 @@ fn test_channel_reserve_holding_cell_htlcs() { } let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV) - .with_features(nodes[2].node.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(); + .with_bolt11_features(nodes[2].node.invoice_features()).unwrap().with_max_channel_saturation_power_of_half(0); + let route = get_route!(nodes[0], payment_params, recv_value_0).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); @@ -2763,8 +2759,7 @@ fn test_htlc_on_chain_success() { assert_eq!(node_txn[1].lock_time.0, 0); // Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42}; - connect_block(&nodes[1], &Block { header, txdata: vec![commitment_tx[0].clone(), node_txn[0].clone(), node_txn[1].clone()]}); + connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![commitment_tx[0].clone(), node_txn[0].clone(), node_txn[1].clone()])); connect_blocks(&nodes[1], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires { let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap(); @@ -2900,8 +2895,7 @@ fn test_htlc_on_chain_success() { // we already checked the same situation with A. // Verify that A's ChannelManager is able to extract preimage from preimage tx and generate PaymentSent - let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42}; - connect_block(&nodes[0], &Block { header, txdata: vec![node_a_commitment_tx[0].clone(), commitment_spend.clone()] }); + connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![node_a_commitment_tx[0].clone(), commitment_spend.clone()])); connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32); // Confirm blocks until the HTLC expires check_closed_broadcast!(nodes[0], true); check_added_monitors!(nodes[0], 1); @@ -3398,7 +3392,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() { let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads( &route.paths[0], 50_000, RecipientOnionFields::secret_only(payment_secret), current_height, &None).unwrap(); let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap(); - let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash); + let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap(); // Send a 0-msat update_add_htlc to fail the channel. let update_add_htlc = msgs::UpdateAddHTLC { @@ -3463,15 +3457,15 @@ fn test_htlc_ignore_latest_remote_commitment() { assert_eq!(node_txn.len(), 3); assert_eq!(node_txn[0].txid(), node_txn[1].txid()); - let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[1].clone()]}); + let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone(), node_txn[1].clone()]); + connect_block(&nodes[1], &block); check_closed_broadcast!(nodes[1], true); check_added_monitors!(nodes[1], 1); check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed); // Duplicate the connect_block call since this may happen due to other listeners // registering new transactions - connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[2].clone()]}); + connect_block(&nodes[1], &block); } #[test] @@ -4152,10 +4146,7 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) { route_payment(&nodes[0], &[&nodes[1]], 100000).1 }; - let mut block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }, - txdata: vec![], - }; + let mut block = create_dummy_block(nodes[0].best_block_hash(), 42, Vec::new()); connect_block(&nodes[0], &block); connect_block(&nodes[1], &block); let block_count = TEST_FINAL_CLTV + CHAN_CONFIRM_DEPTH + 2 - CLTV_CLAIM_BUFFER - LATENCY_GRACE_PERIOD_BLOCKS; @@ -4263,7 +4254,7 @@ macro_rules! check_spendable_outputs { match event { Event::SpendableOutputs { mut outputs } => { for outp in outputs.drain(..) { - txn.push($keysinterface.backing.spend_spendable_outputs(&[&outp], Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &secp_ctx).unwrap()); + txn.push($keysinterface.backing.spend_spendable_outputs(&[&outp], Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &secp_ctx).unwrap()); all_outputs.push(outp); } }, @@ -4271,7 +4262,7 @@ macro_rules! check_spendable_outputs { }; } if all_outputs.len() > 1 { - if let Ok(tx) = $keysinterface.backing.spend_spendable_outputs(&all_outputs.iter().map(|a| a).collect::>(), Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &secp_ctx) { + if let Ok(tx) = $keysinterface.backing.spend_spendable_outputs(&all_outputs.iter().map(|a| a).collect::>(), Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &secp_ctx) { txn.push(tx); } } @@ -4534,8 +4525,7 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() { assert_ne!(revoked_htlc_txn[0].lock_time.0, 0); // HTLC-Timeout // B will generate justice tx from A's revoked commitment/HTLC tx - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[1], &Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] }); + connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()])); check_closed_broadcast!(nodes[1], true); check_added_monitors!(nodes[1], 1); check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed); @@ -4605,8 +4595,7 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { assert_eq!(revoked_local_txn[0].output[unspent_local_txn_output].script_pubkey.len(), 2 + 20); // P2WPKH // A will generate justice tx from B's revoked commitment/HTLC tx - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] }); + connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()])); check_closed_broadcast!(nodes[0], true); check_added_monitors!(nodes[0], 1); check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed); @@ -4699,8 +4688,7 @@ fn test_onchain_to_onchain_claim() { assert_eq!(c_txn[0].lock_time.0, 0); // Success tx // So we broadcast C's commitment tx and HTLC-Success on B's chain, we should successfully be able to extract preimage and update downstream monitor - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42}; - connect_block(&nodes[1], &Block { header, txdata: vec![commitment_tx[0].clone(), c_txn[0].clone()]}); + connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![commitment_tx[0].clone(), c_txn[0].clone()])); check_added_monitors!(nodes[1], 1); let events = nodes[1].node.get_and_clear_pending_events(); assert_eq!(events.len(), 2); @@ -4795,8 +4783,8 @@ fn test_duplicate_payment_hash_one_failure_one_success() { // 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(), TEST_FINAL_CLTV - 40) - .with_features(nodes[3].node.invoice_features()); - let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[3], payment_params, 800_000, TEST_FINAL_CLTV - 40); + .with_bolt11_features(nodes[3].node.invoice_features()).unwrap(); + let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[3], payment_params, 800_000); send_along_route_with_secret(&nodes[0], route, &[&[&nodes[1], &nodes[2], &nodes[3]]], 800_000, duplicate_payment_hash, payment_secret); let commitment_txn = get_local_commitment_txn!(nodes[2], chan_2.2); @@ -5457,10 +5445,7 @@ fn do_htlc_claim_local_commitment_only(use_dust: bool) { check_added_monitors!(nodes[1], 1); let starting_block = nodes[1].best_block_info(); - let mut block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: starting_block.0, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }, - txdata: vec![], - }; + let mut block = create_dummy_block(starting_block.0, 42, Vec::new()); for _ in starting_block.1 + 1..TEST_FINAL_CLTV - CLTV_CLAIM_BUFFER + starting_block.1 + 2 { connect_block(&nodes[1], &block); block.header.prev_blockhash = block.block_hash(); @@ -5490,11 +5475,11 @@ fn do_htlc_claim_current_remote_commitment_only(use_dust: bool) { // to "time out" the HTLC. let starting_block = nodes[1].best_block_info(); - let mut header = BlockHeader { version: 0x20000000, prev_blockhash: starting_block.0, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; + let mut block = create_dummy_block(starting_block.0, 42, Vec::new()); for _ in starting_block.1 + 1..TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + starting_block.1 + 2 { - connect_block(&nodes[0], &Block { header, txdata: Vec::new()}); - header.prev_blockhash = header.block_hash(); + connect_block(&nodes[0], &block); + block.header.prev_blockhash = block.block_hash(); } test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE); check_closed_broadcast!(nodes[0], true); @@ -5536,10 +5521,7 @@ fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no } let starting_block = nodes[1].best_block_info(); - let mut block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: starting_block.0, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }, - txdata: vec![], - }; + let mut block = create_dummy_block(starting_block.0, 42, Vec::new()); for _ in starting_block.1 + 1..TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + CHAN_CONFIRM_DEPTH + 2 { connect_block(&nodes[0], &block); block.header.prev_blockhash = block.block_hash(); @@ -6101,8 +6083,8 @@ fn test_update_add_htlc_bolt2_sender_cltv_expiry_too_high() { let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 0); let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), 0) - .with_features(nodes[1].node.invoice_features()); - let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], payment_params, 100000000, 0); + .with_bolt11_features(nodes[1].node.invoice_features()).unwrap(); + let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], payment_params, 100000000); route.paths[0].hops.last_mut().unwrap().cltv_expiry_delta = 500000001; unwrap_send_err!(nodes[0].node.send_payment_with_route(&route, our_payment_hash, RecipientOnionFields::secret_only(our_payment_secret), PaymentId(our_payment_hash.0) @@ -6267,7 +6249,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() { let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap(); let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads( &route.paths[0], 3999999, RecipientOnionFields::secret_only(our_payment_secret), cur_height, &None).unwrap(); - let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash); + let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash).unwrap(); let mut msg = msgs::UpdateAddHTLC { channel_id: chan.2, @@ -7043,8 +7025,8 @@ fn test_check_htlc_underpaying() { let scorer = test_utils::TestScorer::new(); 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(), TEST_FINAL_CLTV).with_features(nodes[1].node.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 payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV).with_bolt11_features(nodes[1].node.invoice_features()).unwrap(); + let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None, 10_000, 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, None).unwrap(); nodes[0].node.send_payment_with_route(&route, our_payment_hash, @@ -7189,8 +7171,8 @@ fn test_bump_penalty_txn_on_revoked_commitment() { 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(), 30) - .with_features(nodes[0].node.invoice_features()); - let (route,_, _, _) = get_route_and_payment_hash!(nodes[1], nodes[0], payment_params, 3000000, 30); + .with_bolt11_features(nodes[0].node.invoice_features()).unwrap(); + let (route,_, _, _) = get_route_and_payment_hash!(nodes[1], nodes[0], payment_params, 3000000); send_along_route(&nodes[1], route, &vec!(&nodes[0])[..], 3000000); let revoked_txn = get_local_commitment_txn!(nodes[0], chan.2); @@ -7212,8 +7194,7 @@ fn test_bump_penalty_txn_on_revoked_commitment() { // Actually revoke tx by claiming a HTLC claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage); - let header = BlockHeader { version: 0x20000000, prev_blockhash: header_114, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[1], &Block { header, txdata: vec![revoked_txn[0].clone()] }); + connect_block(&nodes[1], &create_dummy_block(header_114, 42, vec![revoked_txn[0].clone()])); check_added_monitors!(nodes[1], 1); // One or more justice tx should have been broadcast, check it @@ -7294,15 +7275,15 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000); // 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(), 50).with_features(nodes[1].node.invoice_features()); + let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), 50).with_bolt11_features(nodes[1].node.invoice_features()).unwrap(); let scorer = test_utils::TestScorer::new(); 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(); + 3_000_000, 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(), 50).with_features(nodes[0].node.invoice_features()); + let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id(), 50).with_bolt11_features(nodes[0].node.invoice_features()).unwrap(); 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(); + 3_000_000, nodes[0].logger, &scorer, &(), &random_seed_bytes).unwrap(); send_along_route(&nodes[1], route, &[&nodes[0]], 3_000_000); let revoked_local_txn = get_local_commitment_txn!(nodes[1], chan.2); @@ -7312,9 +7293,8 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { // Revoke local commitment tx claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage); - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; // B will generate both revoked HTLC-timeout/HTLC-preimage txn from revoked commitment tx - connect_block(&nodes[1], &Block { header, txdata: vec![revoked_local_txn[0].clone()] }); + connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![revoked_local_txn[0].clone()])); check_closed_broadcast!(nodes[1], true); check_added_monitors!(nodes[1], 1); check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed); @@ -7338,10 +7318,10 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { // Broadcast set of revoked txn on A let hash_128 = connect_blocks(&nodes[0], 40); - let header_11 = BlockHeader { version: 0x20000000, prev_blockhash: hash_128, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header: header_11, txdata: vec![revoked_local_txn[0].clone()] }); - let header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_11.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header: header_129, txdata: vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()] }); + let block_11 = create_dummy_block(hash_128, 42, vec![revoked_local_txn[0].clone()]); + connect_block(&nodes[0], &block_11); + let block_129 = create_dummy_block(block_11.block_hash(), 42, vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()]); + connect_block(&nodes[0], &block_129); let events = nodes[0].node.get_and_clear_pending_events(); expect_pending_htlcs_forwardable_from_events!(nodes[0], events[0..1], true); match events.last().unwrap() { @@ -7392,10 +7372,10 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { } // Connect one more block to see if bumped penalty are issued for HTLC txn - let header_130 = BlockHeader { version: 0x20000000, prev_blockhash: header_129.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header: header_130, txdata: penalty_txn }); - let header_131 = BlockHeader { version: 0x20000000, prev_blockhash: header_130.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header: header_131, txdata: Vec::new() }); + let block_130 = create_dummy_block(block_129.block_hash(), 42, penalty_txn); + connect_block(&nodes[0], &block_130); + let block_131 = create_dummy_block(block_130.block_hash(), 42, Vec::new()); + connect_block(&nodes[0], &block_131); // Few more blocks to confirm penalty txn connect_blocks(&nodes[0], 4); @@ -7417,8 +7397,7 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { txn }; // Broadcast claim txn and confirm blocks to avoid further bumps on this outputs - let header_145 = BlockHeader { version: 0x20000000, prev_blockhash: header_144, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header: header_145, txdata: node_txn }); + connect_block(&nodes[0], &create_dummy_block(header_144, 42, node_txn)); connect_blocks(&nodes[0], 20); { let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); @@ -7630,8 +7609,7 @@ fn test_bump_txn_sanitize_tracking_maps() { node_txn.clear(); penalty_txn }; - let header_130 = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header: header_130, txdata: penalty_txn }); + connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, penalty_txn)); connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1); { let monitor = nodes[0].chain_monitor.chain_monitor.get_monitor(OutPoint { txid: chan.3.txid(), index: 0 }).unwrap(); @@ -8087,7 +8065,7 @@ fn test_onion_value_mpp_set_calculation() { // Edit amt_to_forward to simulate the sender having set // the final amount and the routing node taking less fee onion_payloads[1].amt_to_forward = 99_000; - let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash); + let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash).unwrap(); payment_event.msgs[0].onion_routing_packet = new_onion_packet; } @@ -8275,14 +8253,7 @@ fn test_secret_timeout() { } else { panic!(); } let mut block = { let node_1_blocks = nodes[1].blocks.lock().unwrap(); - Block { - header: BlockHeader { - version: 0x2000000, - prev_blockhash: node_1_blocks.last().unwrap().0.block_hash(), - merkle_root: TxMerkleNode::all_zeros(), - time: node_1_blocks.len() as u32 + 7200, bits: 42, nonce: 42 }, - txdata: vec![], - } + create_dummy_block(node_1_blocks.last().unwrap().0.block_hash(), node_1_blocks.len() as u32 + 7200, Vec::new()) }; connect_block(&nodes[1], &block); if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2) { @@ -8430,8 +8401,7 @@ fn test_update_err_monitor_lockdown() { 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 }; - let block = Block { header, txdata: vec![] }; + let block = create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()); // Make the tx_broadcaster aware of enough blocks that it doesn't think we're violating // transaction lock time requirements here. chanmon_cfgs[0].tx_broadcaster.blocks.lock().unwrap().resize(200, (block.clone(), 200)); @@ -8449,7 +8419,7 @@ fn test_update_err_monitor_lockdown() { let mut node_0_per_peer_lock; let mut node_0_peer_state_lock; let mut channel = get_channel_ref!(nodes[0], nodes[1], node_0_per_peer_lock, node_0_peer_state_lock, chan_1.2); - if let Ok(update) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { + if let Ok(Some(update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { assert_eq!(watchtower.chain_monitor.update_channel(outpoint, &update), ChannelMonitorUpdateStatus::PermanentFailure); assert_eq!(nodes[0].chain_monitor.update_channel(outpoint, &update), ChannelMonitorUpdateStatus::Completed); } else { assert!(false); } @@ -8501,8 +8471,7 @@ fn test_concurrent_monitor_claim() { 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 }; - let block = Block { header, txdata: vec![] }; + let block = create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()); // Make Alice aware of enough blocks that it doesn't think we're violating transaction lock time // requirements here. const HTLC_TIMEOUT_BROADCAST: u32 = CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS; @@ -8533,8 +8502,7 @@ fn test_concurrent_monitor_claim() { 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 }; - watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, HTLC_TIMEOUT_BROADCAST - 1); + watchtower_bob.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()), HTLC_TIMEOUT_BROADCAST - 1); // Route another payment to generate another update with still previous HTLC pending let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], 3000000); @@ -8549,7 +8517,7 @@ fn test_concurrent_monitor_claim() { let mut node_0_per_peer_lock; let mut node_0_peer_state_lock; let mut channel = get_channel_ref!(nodes[0], nodes[1], node_0_per_peer_lock, node_0_peer_state_lock, chan_1.2); - if let Ok(update) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { + if let Ok(Some(update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { // Watchtower Alice should already have seen the block and reject the update assert_eq!(watchtower_alice.chain_monitor.update_channel(outpoint, &update), ChannelMonitorUpdateStatus::PermanentFailure); assert_eq!(watchtower_bob.chain_monitor.update_channel(outpoint, &update), ChannelMonitorUpdateStatus::Completed); @@ -8560,8 +8528,7 @@ fn test_concurrent_monitor_claim() { check_added_monitors!(nodes[0], 1); //// Provide one more block to watchtower Bob, expect broadcast of commitment and HTLC-Timeout - let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, HTLC_TIMEOUT_BROADCAST); + watchtower_bob.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()), HTLC_TIMEOUT_BROADCAST); // Watchtower Bob should have broadcast a commitment/HTLC-timeout let bob_state_y; @@ -8572,12 +8539,11 @@ fn test_concurrent_monitor_claim() { }; // We confirm Bob's state Y on Alice, she should broadcast a HTLC-timeout - let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; let height = HTLC_TIMEOUT_BROADCAST + 1; connect_blocks(&nodes[0], height - nodes[0].best_block_info().1); check_closed_broadcast(&nodes[0], 1, true); check_closed_event(&nodes[0], 1, ClosureReason::CommitmentTxConfirmed, false); - watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![bob_state_y.clone()] }, height); + watchtower_alice.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, vec![bob_state_y.clone()]), height); check_added_monitors(&nodes[0], 1); { let htlc_txn = alice_broadcaster.txn_broadcast(); @@ -8652,11 +8618,11 @@ fn test_htlc_no_detection() { check_spends!(local_txn[0], chan_1.3); // Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header, txdata: vec![local_txn[0].clone()] }); + let block = create_dummy_block(nodes[0].best_block_hash(), 42, vec![local_txn[0].clone()]); + connect_block(&nodes[0], &block); // We deliberately connect the local tx twice as this should provoke a failure calling // this test before #653 fix. - chain::Listen::block_connected(&nodes[0].chain_monitor.chain_monitor, &Block { header, txdata: vec![local_txn[0].clone()] }, nodes[0].best_block_info().1 + 1); + chain::Listen::block_connected(&nodes[0].chain_monitor.chain_monitor, &block, nodes[0].best_block_info().1 + 1); check_closed_broadcast!(nodes[0], true); check_added_monitors!(nodes[0], 1); check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed); @@ -8671,8 +8637,7 @@ fn test_htlc_no_detection() { node_txn[0].clone() }; - let header_201 = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; - connect_block(&nodes[0], &Block { header: header_201, txdata: vec![htlc_timeout.clone()] }); + connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![htlc_timeout.clone()])); connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1); expect_payment_failed!(nodes[0], our_payment_hash, false); } @@ -8732,8 +8697,7 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain true => alice_txn.clone(), false => get_local_commitment_txn!(nodes[1], chan_ab.2) }; - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42}; - connect_block(&nodes[1], &Block { header, txdata: vec![txn_to_broadcast[0].clone()]}); + connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![txn_to_broadcast[0].clone()])); if broadcast_alice { check_closed_broadcast!(nodes[1], true); check_added_monitors!(nodes[1], 1); @@ -8812,8 +8776,7 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain let mut txn_to_broadcast = alice_txn.clone(); if !broadcast_alice { txn_to_broadcast = get_local_commitment_txn!(nodes[1], chan_ab.2); } if !go_onchain_before_fulfill { - let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42}; - connect_block(&nodes[1], &Block { header, txdata: vec![txn_to_broadcast[0].clone()]}); + connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![txn_to_broadcast[0].clone()])); // If Bob was the one to force-close, he will have already passed these checks earlier. if broadcast_alice { check_closed_broadcast!(nodes[1], true); @@ -9300,8 +9263,8 @@ fn do_test_dup_htlc_second_rejected(test_for_second_fail_panic: bool) { let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001); let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV) - .with_features(nodes[1].node.invoice_features()); - let route = get_route!(nodes[0], payment_params, 10_000, TEST_FINAL_CLTV).unwrap(); + .with_bolt11_features(nodes[1].node.invoice_features()).unwrap(); + let route = get_route!(nodes[0], payment_params, 10_000).unwrap(); let (our_payment_preimage, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(&nodes[1]); @@ -9409,8 +9372,8 @@ fn test_inconsistent_mpp_params() { let chan_2_3 =create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0); let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id(), TEST_FINAL_CLTV) - .with_features(nodes[3].node.invoice_features()); - let mut route = get_route!(nodes[0], payment_params, 15_000_000, TEST_FINAL_CLTV).unwrap(); + .with_bolt11_features(nodes[3].node.invoice_features()).unwrap(); + let mut route = get_route!(nodes[0], payment_params, 15_000_000).unwrap(); assert_eq!(route.paths.len(), 2); route.paths.sort_by(|path_a, _| { // Sort the path so that the path through nodes[1] comes first @@ -9520,7 +9483,7 @@ fn test_keysend_payments_to_public_node() { }; let scorer = test_utils::TestScorer::new(); let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); - let route = find_route(&payer_pubkey, &route_params, &network_graph, None, nodes[0].logger, &scorer, &random_seed_bytes).unwrap(); + let route = find_route(&payer_pubkey, &route_params, &network_graph, None, nodes[0].logger, &scorer, &(), &random_seed_bytes).unwrap(); let test_preimage = PaymentPreimage([42; 32]); let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(test_preimage), @@ -9555,7 +9518,7 @@ fn test_keysend_payments_to_private_node() { let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::>()), - nodes[0].logger, &scorer, &random_seed_bytes + nodes[0].logger, &scorer, &(), &random_seed_bytes ).unwrap(); let test_preimage = PaymentPreimage([42; 32]); @@ -9956,7 +9919,7 @@ fn do_payment_with_custom_min_final_cltv_expiry(valid_delta: bool, use_user_hash let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(recv_value), 7200, Some(min_final_cltv_expiry_delta)).unwrap(); (payment_hash, nodes[1].node.get_payment_preimage(payment_hash, payment_secret).unwrap(), payment_secret) }; - let route = get_route!(nodes[0], payment_parameters, recv_value, final_cltv_expiry_delta as u32).unwrap(); + let route = get_route!(nodes[0], payment_parameters, recv_value).unwrap(); nodes[0].node.send_payment_with_route(&route, payment_hash, RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap(); check_added_monitors!(nodes[0], 1); diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index 2d15876bf..1b0fd1707 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -14,7 +14,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::cmp::fixed_time_eq; use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; -use crate::chain::keysinterface::{KeyMaterial, EntropySource}; +use crate::sign::{KeyMaterial, EntropySource}; use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::msgs; use crate::ln::msgs::MAX_VALUE_MSAT; @@ -37,7 +37,7 @@ const METHOD_TYPE_OFFSET: usize = 5; /// A set of keys that were HKDF-expanded from an initial call to /// [`NodeSigner::get_inbound_payment_key_material`]. /// -/// [`NodeSigner::get_inbound_payment_key_material`]: crate::chain::keysinterface::NodeSigner::get_inbound_payment_key_material +/// [`NodeSigner::get_inbound_payment_key_material`]: crate::sign::NodeSigner::get_inbound_payment_key_material pub struct ExpandedKey { /// The key used to encrypt the bytes containing the payment metadata (i.e. the amount and /// expiry, included for payment verification on decryption). @@ -166,8 +166,8 @@ fn min_final_cltv_expiry_delta_from_metadata(bytes: [u8; METADATA_LEN]) -> u16 { /// Note that if `min_final_cltv_expiry_delta` is set to some value, then the payment will not be receivable /// on versions of LDK prior to 0.0.114. /// -/// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager -/// [`NodeSigner::get_inbound_payment_key_material`]: crate::chain::keysinterface::NodeSigner::get_inbound_payment_key_material +/// [phantom node payments]: crate::sign::PhantomKeysManager +/// [`NodeSigner::get_inbound_payment_key_material`]: crate::sign::NodeSigner::get_inbound_payment_key_material pub fn create(keys: &ExpandedKey, min_value_msat: Option, invoice_expiry_delta_secs: u32, entropy_source: &ES, current_time: u64, min_final_cltv_expiry_delta: Option) -> Result<(PaymentHash, PaymentSecret), ()> @@ -202,7 +202,7 @@ pub fn create(keys: &ExpandedKey, min_value_msat: Option, /// Note that if `min_final_cltv_expiry_delta` is set to some value, then the payment will not be receivable /// on versions of LDK prior to 0.0.114. /// -/// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager +/// [phantom node payments]: crate::sign::PhantomKeysManager pub fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option, payment_hash: PaymentHash, invoice_expiry_delta_secs: u32, current_time: u64, min_final_cltv_expiry_delta: Option) -> Result { let metadata_bytes = construct_metadata_bytes(min_value_msat, if min_final_cltv_expiry_delta.is_some() { @@ -311,7 +311,7 @@ fn construct_payment_secret(iv_bytes: &[u8; IV_LEN], metadata_bytes: &[u8; METAD /// /// See [`ExpandedKey`] docs for more info on the individual keys used. /// -/// [`NodeSigner::get_inbound_payment_key_material`]: crate::chain::keysinterface::NodeSigner::get_inbound_payment_key_material +/// [`NodeSigner::get_inbound_payment_key_material`]: crate::sign::NodeSigner::get_inbound_payment_key_material /// [`create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment /// [`create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash pub(super) fn verify(payment_hash: PaymentHash, payment_data: &msgs::FinalOnionHopData, diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 340213c51..92edb0611 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -72,17 +72,17 @@ pub use self::peer_channel_encryptor::LN_MAX_MSG_LEN; /// payment_hash type, use to cross-lock hop /// /// This is not exported to bindings users as we just use [u8; 32] directly -#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)] pub struct PaymentHash(pub [u8; 32]); /// payment_preimage type, use to route payment between hop /// /// This is not exported to bindings users as we just use [u8; 32] directly -#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)] pub struct PaymentPreimage(pub [u8; 32]); /// payment_secret type, use to authenticate sender to the receiver and tie MPP HTLCs together /// /// This is not exported to bindings users as we just use [u8; 32] directly -#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)] pub struct PaymentSecret(pub [u8; 32]); use crate::prelude::*; diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index b20a2e575..5fa39137c 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -10,7 +10,7 @@ //! Further functional tests which test blockchain reorganizations. #[cfg(anchors)] -use crate::chain::keysinterface::{ChannelSigner, EcdsaChannelSigner}; +use crate::sign::{ChannelSigner, EcdsaChannelSigner}; #[cfg(anchors)] use crate::chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS; use crate::chain::channelmonitor::{ANTI_REORG_DELAY, Balance}; @@ -114,7 +114,7 @@ fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_t if let Event::SpendableOutputs { outputs } = spendable.pop().unwrap() { assert_eq!(outputs.len(), 1); let spend_tx = node.keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(), - Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap(); + Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &Secp256k1::new()).unwrap(); check_spends!(spend_tx, spendable_tx); } else { panic!(); } } @@ -298,28 +298,49 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); let remote_txn = get_local_commitment_txn!(nodes[1], chan_id); + let sent_htlc_balance = Balance::MaybeTimeoutClaimableHTLC { + claimable_amount_satoshis: 3_000, + claimable_height: htlc_cltv_timeout, + payment_hash, + }; + let sent_htlc_timeout_balance = Balance::MaybeTimeoutClaimableHTLC { + claimable_amount_satoshis: 4_000, + claimable_height: htlc_cltv_timeout, + payment_hash: timeout_payment_hash, + }; + let received_htlc_balance = Balance::MaybePreimageClaimableHTLC { + claimable_amount_satoshis: 3_000, + expiry_height: htlc_cltv_timeout, + payment_hash, + }; + let received_htlc_timeout_balance = Balance::MaybePreimageClaimableHTLC { + claimable_amount_satoshis: 4_000, + expiry_height: htlc_cltv_timeout, + payment_hash: timeout_payment_hash, + }; + let received_htlc_claiming_balance = Balance::ContentiousClaimable { + claimable_amount_satoshis: 3_000, + timeout_height: htlc_cltv_timeout, + payment_hash, + payment_preimage, + }; + let received_htlc_timeout_claiming_balance = Balance::ContentiousClaimable { + claimable_amount_satoshis: 4_000, + timeout_height: htlc_cltv_timeout, + payment_hash: timeout_payment_hash, + payment_preimage: timeout_payment_preimage, + }; + // Before B receives the payment preimage, it only suggests the push_msat value of 1_000 sats // as claimable. A lists both its to-self balance and the (possibly-claimable) HTLCs. assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 3_000, - claimable_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 4_000, - claimable_height: htlc_cltv_timeout, - }]), + }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 3_000, - expiry_height: htlc_cltv_timeout, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 4_000, - expiry_height: htlc_cltv_timeout, - }]), + }, received_htlc_balance.clone(), received_htlc_timeout_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); nodes[1].node.claim_funds(payment_preimage); @@ -364,15 +385,9 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + if prev_commitment_tx { 1 } else { 2 } * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 4_000, - claimable_height: htlc_cltv_timeout, - }]; + }, sent_htlc_timeout_balance.clone()]; if !prev_commitment_tx { - a_expected_balances.push(Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 3_000, - claimable_height: htlc_cltv_timeout, - }); + a_expected_balances.push(sent_htlc_balance.clone()); } assert_eq!(sorted_vec(a_expected_balances), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -419,13 +434,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { claimable_amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 3_000, - claimable_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 4_000, - claimable_height: htlc_cltv_timeout, - }]), + }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // The main non-HTLC balance is just awaiting confirmations, but the claimable height is the // CSV delay, not ANTI_REORG_DELAY. @@ -435,13 +444,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { }, // Both HTLC balances are "contentious" as our counterparty could claim them if we wait too // long. - Balance::ContentiousClaimable { - claimable_amount_satoshis: 3_000, - timeout_height: htlc_cltv_timeout, - }, Balance::ContentiousClaimable { - claimable_amount_satoshis: 4_000, - timeout_height: htlc_cltv_timeout, - }]), + received_htlc_claiming_balance.clone(), received_htlc_timeout_claiming_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1); @@ -450,24 +453,12 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { // After ANTI_REORG_DELAY, A will consider its balance fully spendable and generate a // `SpendableOutputs` event. However, B still has to wait for the CSV delay. - assert_eq!(sorted_vec(vec![Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 3_000, - claimable_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 4_000, - claimable_height: htlc_cltv_timeout, - }]), + assert_eq!(sorted_vec(vec![sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000, confirmation_height: node_b_commitment_claimable, - }, Balance::ContentiousClaimable { - claimable_amount_satoshis: 3_000, - timeout_height: htlc_cltv_timeout, - }, Balance::ContentiousClaimable { - claimable_amount_satoshis: 4_000, - timeout_height: htlc_cltv_timeout, - }]), + }, received_htlc_claiming_balance.clone(), received_htlc_timeout_claiming_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); test_spendable_output(&nodes[0], &remote_txn[0]); @@ -481,19 +472,10 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { } else { expect_payment_sent!(nodes[0], payment_preimage); } - assert_eq!(sorted_vec(vec![Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 3_000, - claimable_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 4_000, - claimable_height: htlc_cltv_timeout, - }]), + assert_eq!(sorted_vec(vec![sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1); - assert_eq!(vec![Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 4_000, - claimable_height: htlc_cltv_timeout, - }], + assert_eq!(vec![sent_htlc_timeout_balance.clone()], nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); // When the HTLC timeout output is spendable in the next block, A should broadcast it @@ -540,10 +522,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 3_000, confirmation_height: node_b_htlc_claimable, - }, Balance::ContentiousClaimable { - claimable_amount_satoshis: 4_000, - timeout_height: htlc_cltv_timeout, - }]), + }, received_htlc_timeout_claiming_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // After reaching the commitment output CSV, we'll get a SpendableOutputs event for it and have @@ -554,10 +533,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 3_000, confirmation_height: node_b_htlc_claimable, - }, Balance::ContentiousClaimable { - claimable_amount_satoshis: 4_000, - timeout_height: htlc_cltv_timeout, - }]), + }, received_htlc_timeout_claiming_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // After reaching the claimed HTLC output CSV, we'll get a SpendableOutptus event for it and @@ -565,20 +541,14 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { connect_blocks(&nodes[1], node_b_htlc_claimable - nodes[1].best_block_info().1); test_spendable_output(&nodes[1], &b_broadcast_txn[0]); - assert_eq!(vec![Balance::ContentiousClaimable { - claimable_amount_satoshis: 4_000, - timeout_height: htlc_cltv_timeout, - }], + assert_eq!(vec![received_htlc_timeout_claiming_balance.clone()], nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); // Finally, mine the HTLC timeout transaction that A broadcasted (even though B should be able // to claim this HTLC with the preimage it knows!). It will remain listed as a claimable HTLC // until ANTI_REORG_DELAY confirmations on the spend. mine_transaction(&nodes[1], &a_broadcast_txn[1]); - assert_eq!(vec![Balance::ContentiousClaimable { - claimable_amount_satoshis: 4_000, - timeout_height: htlc_cltv_timeout, - }], + assert_eq!(vec![received_htlc_timeout_claiming_balance.clone()], nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1); assert_eq!(Vec::::new(), @@ -669,17 +639,22 @@ fn test_balances_on_local_commitment_htlcs() { check_closed_broadcast!(nodes[0], true); check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed); + let htlc_balance_known_preimage = Balance::MaybeTimeoutClaimableHTLC { + claimable_amount_satoshis: 10_000, + claimable_height: htlc_cltv_timeout, + payment_hash, + }; + let htlc_balance_unknown_preimage = Balance::MaybeTimeoutClaimableHTLC { + claimable_amount_satoshis: 20_000, + claimable_height: htlc_cltv_timeout, + payment_hash: payment_hash_2, + }; + assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 10_000, - claimable_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 20_000, - claimable_height: htlc_cltv_timeout, - }]), + }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // Get nodes[1]'s HTLC claim tx for the second HTLC @@ -698,13 +673,7 @@ fn test_balances_on_local_commitment_htlcs() { claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 10_000, - claimable_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 20_000, - claimable_height: htlc_cltv_timeout, - }]), + }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); assert_eq!(as_txn[1].lock_time.0, nodes[0].best_block_info().1 + 1); // as_txn[1] can be included in the next block @@ -722,10 +691,7 @@ fn test_balances_on_local_commitment_htlcs() { }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, confirmation_height: node_a_htlc_claimable, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 20_000, - claimable_height: htlc_cltv_timeout, - }]), + }, htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // Now confirm nodes[1]'s HTLC claim, giving nodes[0] the preimage. Note that the "maybe @@ -739,10 +705,7 @@ fn test_balances_on_local_commitment_htlcs() { }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, confirmation_height: node_a_htlc_claimable, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 20_000, - claimable_height: htlc_cltv_timeout, - }]), + }, htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // Finally make the HTLC transactions have ANTI_REORG_DELAY blocks. This call previously @@ -806,6 +769,27 @@ fn test_no_preimage_inbound_htlc_balances() { let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let a_sent_htlc_balance = Balance::MaybeTimeoutClaimableHTLC { + claimable_amount_satoshis: 10_000, + claimable_height: htlc_cltv_timeout, + payment_hash: to_b_failed_payment_hash, + }; + let a_received_htlc_balance = Balance::MaybePreimageClaimableHTLC { + claimable_amount_satoshis: 20_000, + expiry_height: htlc_cltv_timeout, + payment_hash: to_a_failed_payment_hash, + }; + let b_received_htlc_balance = Balance::MaybePreimageClaimableHTLC { + claimable_amount_satoshis: 10_000, + expiry_height: htlc_cltv_timeout, + payment_hash: to_b_failed_payment_hash, + }; + let b_sent_htlc_balance = Balance::MaybeTimeoutClaimableHTLC { + claimable_amount_satoshis: 20_000, + claimable_height: htlc_cltv_timeout, + payment_hash: to_a_failed_payment_hash, + }; + // Both A and B will have an HTLC that's claimable on timeout and one that's claimable if they // receive the preimage. These will remain the same through the channel closure and until the // HTLC output is spent. @@ -813,24 +797,12 @@ fn test_no_preimage_inbound_htlc_balances() { assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 20_000, - expiry_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 10_000, - claimable_height: htlc_cltv_timeout, - }]), + }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 500_000 - 20_000, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 10_000, - expiry_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 20_000, - claimable_height: htlc_cltv_timeout, - }]), + }, b_received_htlc_balance.clone(), b_sent_htlc_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // Get nodes[0]'s commitment transaction and HTLC-Timeout transaction @@ -846,13 +818,7 @@ fn test_no_preimage_inbound_htlc_balances() { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 20_000, - expiry_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 10_000, - claimable_height: htlc_cltv_timeout, - }]); + }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]); mine_transaction(&nodes[0], &as_txn[0]); nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clear(); @@ -872,13 +838,7 @@ fn test_no_preimage_inbound_htlc_balances() { let mut bs_pre_spend_claims = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 500_000 - 20_000, confirmation_height: node_b_commitment_claimable, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 10_000, - expiry_height: htlc_cltv_timeout, - }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis: 20_000, - claimable_height: htlc_cltv_timeout, - }]); + }, b_received_htlc_balance.clone(), b_sent_htlc_balance.clone()]); assert_eq!(bs_pre_spend_claims, sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -930,10 +890,7 @@ fn test_no_preimage_inbound_htlc_balances() { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 20_000, - expiry_height: htlc_cltv_timeout, - }, Balance::ClaimableAwaitingConfirmations { + }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, confirmation_height: as_timeout_claimable_height, }]), @@ -944,10 +901,7 @@ fn test_no_preimage_inbound_htlc_balances() { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, - }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 20_000, - expiry_height: htlc_cltv_timeout, - }, Balance::ClaimableAwaitingConfirmations { + }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, confirmation_height: as_timeout_claimable_height, }]), @@ -985,20 +939,14 @@ fn test_no_preimage_inbound_htlc_balances() { // was already claimed. mine_transaction(&nodes[1], &bs_htlc_timeout_claim[0]); let bs_timeout_claimable_height = nodes[1].best_block_info().1 + ANTI_REORG_DELAY - 1; - assert_eq!(sorted_vec(vec![Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 10_000, - expiry_height: htlc_cltv_timeout, - }, Balance::ClaimableAwaitingConfirmations { + assert_eq!(sorted_vec(vec![b_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 20_000, confirmation_height: bs_timeout_claimable_height, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); mine_transaction(&nodes[1], &as_htlc_timeout_claim[0]); - assert_eq!(sorted_vec(vec![Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 10_000, - expiry_height: htlc_cltv_timeout, - }, Balance::ClaimableAwaitingConfirmations { + assert_eq!(sorted_vec(vec![b_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 20_000, confirmation_height: bs_timeout_claimable_height, }]), @@ -1007,10 +955,7 @@ fn test_no_preimage_inbound_htlc_balances() { connect_blocks(&nodes[1], ANTI_REORG_DELAY - 2); expect_payment_failed!(nodes[1], to_a_failed_payment_hash, false); - assert_eq!(vec![Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis: 10_000, - expiry_height: htlc_cltv_timeout, - }], + assert_eq!(vec![b_received_htlc_balance.clone()], nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); test_spendable_output(&nodes[1], &bs_htlc_timeout_claim[0]); @@ -1133,12 +1078,15 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo }, Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: 2_000, claimable_height: missing_htlc_cltv_timeout, + payment_hash: missing_htlc_payment_hash, }, Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: 4_000, claimable_height: htlc_cltv_timeout, + payment_hash: timeout_payment_hash, }, Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: 5_000, claimable_height: live_htlc_cltv_timeout, + payment_hash: live_payment_hash, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1567,9 +1515,11 @@ fn test_revoked_counterparty_aggregated_claims() { }, Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: 4_000, claimable_height: htlc_cltv_timeout, + payment_hash: revoked_payment_hash, }, Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: 3_000, claimable_height: htlc_cltv_timeout, + payment_hash: claimed_payment_hash, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1746,7 +1696,7 @@ fn do_test_restored_packages_retry(check_old_monitor_retries_after_upgrade: bool // old `ChannelMonitor` that did not exercise said rebroadcasting logic. if check_old_monitor_retries_after_upgrade { let serialized_monitor = hex::decode( - "0101fffffffffffffffff9550f22c95100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665f00002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6302d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e2035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0016001467822698d782e8421ebdf96d010de99382b7ec2300160014caf6d80fe2bab80473b021f57588a9c384bf23170000000000000000000000004d49e5da0000000000000000000000000000002a0270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f74c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c21391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a0000000000000000004a002103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84022103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a04020090004752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae00000000000186a0ffffffffffff0291e7c0a3232fb8650a6b4089568a81062b48a768780e5a74bb4a4a74e33aec2c029d5760248ec86c4a76d9df8308555785a06a65472fb995f5b392d520bbd000650090c1c94b11625690c9d84c5daa67b6ad19fcc7f9f23e194384140b08fcab9e8e810000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000002391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a00000000000000010000000000009896800000005166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f292505000000009c009900202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d10208000000000098968004494800210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c23020500030241000408000001000000000006020000080800000000009896800a0400000046167c86cc0e598a6b541f7c9bf9ef17222e4a76f636e2d22185aeadd2b02d029c00000000000000000000000000000000000000000000000166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925fffffffffffe01e3002004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30108000000000000c299022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0a2102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e0c04000000fd0e00fd01fe002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01080000000000009b5e0221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90a2102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20c04000000fd0efd01193b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925080400000000417e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d39c009900202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d10208000000000098968004494800210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c23020500030241000408000001000000000006020000080800000000009896800a0400000046fffffffffffefffffffffffe000000000000000000000000000000000000000000000000ffe099e83ae3761c7f1b781d22613bd1f6977e9ad59fae12b3eba34462ee8a3d000000500000000000000002fd01da002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b03209452ca8c90d4c78928b80ec41398f2a890324d8ad6e6c81408a0cb9b8d977b070406030400020090fd02a1002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b03209452ca8c90d4c78928b80ec41398f2a890324d8ad6e6c81408a0cb9b8d977b0704cd01cb00c901c7002245cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0001022102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e204020090062b5e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c630821035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0a200000000000000000000000004d49e5da0000000000000000000000000000002a0c0800000000000186a0000000000000000274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e0000000000000001000000000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c45cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d000000000000000100000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d5349010100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665ffd027100fd01e6fd01e300080000fffffffffffe02080000000000009b5e0408000000000000c3500604000000fd08b0af002102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90acdcc00a8020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d350c92220022045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0c3c3b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f29250804000000000240671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec64b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613404010006407e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d3010000000000000001010000000000000000090b2a953d93a124c600ecb1a0ccfed420169cdd37f538ad94a3e4e6318c93c14adf59cdfbb40bdd40950c9f8dd547d29d75a173e1376a7850743394c46dea2dfd01cefd01ca00fd017ffd017c00080000ffffffffffff0208000000000000c2990408000000000000c3500604000000fd08b0af002102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0aa2a1007d020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800299c2000000000000220020740e108cfbc93967b6ab242a351ebee7de51814cf78d366adefd78b10281f17e50c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d351c92220022004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30c00024045cb2485594bb1ec08e7bb6af4f89c912bd53f006d7876ea956773e04a4aad4a40e2b8d4fc612102f0b54061b3c1239fb78783053e8e6f9d92b1b99f81ae9ec2040100060000fd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000287010108d30df34e3a1e00ecdd03a2c843db062479a81752c4dfd0cc4baef0f81e7bc7ef8820990daf8d8e8d30a3b4b08af12c9f5cd71e45c7238103e0c80ca13850862e4fd2c56b69b7195312518de1bfe9aed63c80bb7760d70b2a870d542d815895fd12423d11e2adb0cdf55d776dac8f487c9b3b7ea12f1b150eb15889cf41333ade465692bf1cdc360b9c2a19bf8c1ca4fed7639d8bc953d36c10d8c6c9a8c0a57608788979bcf145e61b308006896e21d03e92084f93bd78740c20639134a7a8fd019afd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000000000186a00000000000000000000000004d49e5da0000000000000000000000000000002a000000000000000001b77b61346a2a408afdb01743a2230cb36e55771a0790f67a0910e207fd223fc8000000000000000145cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d00000000041000080000000000989680020400000051160004000000510208000000000000000004040000000b000000000000000145cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d00000000b77b61346a2a408afdb01743a2230cb36e55771a0790f67a0910e207fd223fc80000005000000000000000000000000000000000000101300300050007010109210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c230d000f020000", + "0101fffffffffffffffff9550f22c95100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665f00002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6302d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e2035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0016001467822698d782e8421ebdf96d010de99382b7ec2300160014caf6d80fe2bab80473b021f57588a9c384bf23170000000000000000000000004d49e5da0000000000000000000000000000002a0270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f74c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c21391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a0000000000000000004a002103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84022103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a04020090004752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae00000000000186a0ffffffffffff0291e7c0a3232fb8650a6b4089568a81062b48a768780e5a74bb4a4a74e33aec2c029d5760248ec86c4a76d9df8308555785a06a65472fb995f5b392d520bbd000650090c1c94b11625690c9d84c5daa67b6ad19fcc7f9f23e194384140b08fcab9e8e810000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000002167c86cc0e598a6b541f7c9bf9ef17222e4a76f636e2d22185aeadd2b02d029c0000000000000000391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a00000000000000010000000000009896800000005166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f29250500000000a0009d00202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d102080000000000989680044d4c00210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c2302090007000000000241000408000001000000000006020000080800000000009896800a04000000460000000000000000000000000000000166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925fffffffffffe01e3002004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30108000000000000c299022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0a2102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e0c04000000fd0e00fd0202002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01080000000000009b5e0221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90a2102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20c04000000fd0efd011d3b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925080400000000417e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d3a0009d00202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d102080000000000989680044d4c00210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c2302090007000000000241000408000001000000000006020000080800000000009896800a0400000046fffffffffffefffffffffffe000000000000000000000000000000000000000000000000f1600ef6ea657b8d411d553516ae35cedfe86b0cd48d1f91b32772facbae757d0000000b0000000000000002fd01da002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b0320f1600ef6ea657b8d411d553516ae35cedfe86b0cd48d1f91b32772facbae757d0406030400020090fd02a1002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b0320f1600ef6ea657b8d411d553516ae35cedfe86b0cd48d1f91b32772facbae757d04cd01cb00c901c7002245cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0001022102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e204020090062b5e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c630821035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0a200000000000000000000000004d49e5da0000000000000000000000000000002a0c0800000000000186a0000000000000000274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e0000000000000001000000000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c45cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d000000000000000100000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d5349010100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665ffd027100fd01e6fd01e300080000fffffffffffe02080000000000009b5e0408000000000000c3500604000000fd08b0af002102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90acdcc00a8020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d350c92220022045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0c3c3b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f29250804000000000240671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec64b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613404010006407e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d3010000000000000001010000000000000000090b2a953d93a124c600ecb1a0ccfed420169cdd37f538ad94a3e4e6318c93c14adf59cdfbb40bdd40950c9f8dd547d29d75a173e1376a7850743394c46dea2dfd01cefd01ca00fd017ffd017c00080000ffffffffffff0208000000000000c2990408000000000000c3500604000000fd08b0af002102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0aa2a1007d020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800299c2000000000000220020740e108cfbc93967b6ab242a351ebee7de51814cf78d366adefd78b10281f17e50c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d351c92220022004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30c00024045cb2485594bb1ec08e7bb6af4f89c912bd53f006d7876ea956773e04a4aad4a40e2b8d4fc612102f0b54061b3c1239fb78783053e8e6f9d92b1b99f81ae9ec2040100060000fd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000287010108d30df34e3a1e00ecdd03a2c843db062479a81752c4dfd0cc4baef0f81e7bc7ef8820990daf8d8e8d30a3b4b08af12c9f5cd71e45c7238103e0c80ca13850862e4fd2c56b69b7195312518de1bfe9aed63c80bb7760d70b2a870d542d815895fd12423d11e2adb0cdf55d776dac8f487c9b3b7ea12f1b150eb15889cf41333ade465692bf1cdc360b9c2a19bf8c1ca4fed7639d8bc953d36c10d8c6c9a8c0a57608788979bcf145e61b308006896e21d03e92084f93bd78740c20639134a7a8fd019afd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000000000186a00000000000000000000000004d49e5da0000000000000000000000000000002a00000000000000000000000000000000000000000000000001000000510000000000000001000000000000000145cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d00000000041000080000000000989680020400000051160004000000510208000000000000000004040000000b0000000000000000000101300300050007010109210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c230d000f020000", ).unwrap(); reload_node!(nodes[0], &nodes[0].node.encode(), &[&serialized_monitor], persister, new_chain_monitor, node_deserialized); } @@ -2235,21 +2185,20 @@ fn test_anchors_aggregated_revoked_htlc_tx() { // revoked outputs. { let txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0); - assert_eq!(txn.len(), 2); + assert_eq!(txn.len(), 4); - let (revoked_claim_a, revoked_claim_b) = if txn[0].input[0].previous_output.txid == revoked_commitment_a.txid() { - (&txn[0], &txn[1]) + let (revoked_htlc_claim_a, revoked_htlc_claim_b) = if txn[0].input[0].previous_output.txid == revoked_commitment_a.txid() { + (if txn[0].input.len() == 2 { &txn[0] } else { &txn[1] }, if txn[2].input.len() == 2 { &txn[2] } else { &txn[3] }) } else { - (&txn[1], &txn[0]) + (if txn[2].input.len() == 2 { &txn[2] } else { &txn[3] }, if txn[0].input.len() == 2 { &txn[0] } else { &txn[1] }) }; - // TODO: to_self claim must be separate from HTLC claims - assert_eq!(revoked_claim_a.input.len(), 3); // Spends both HTLC outputs and to_self output - assert_eq!(revoked_claim_a.output.len(), 1); - check_spends!(revoked_claim_a, revoked_commitment_a); - assert_eq!(revoked_claim_b.input.len(), 3); // Spends both HTLC outputs and to_self output - assert_eq!(revoked_claim_b.output.len(), 1); - check_spends!(revoked_claim_b, revoked_commitment_b); + assert_eq!(revoked_htlc_claim_a.input.len(), 2); // Spends both HTLC outputs + assert_eq!(revoked_htlc_claim_a.output.len(), 1); + check_spends!(revoked_htlc_claim_a, revoked_commitment_a); + assert_eq!(revoked_htlc_claim_b.input.len(), 2); // Spends both HTLC outputs + assert_eq!(revoked_htlc_claim_b.output.len(), 1); + check_spends!(revoked_htlc_claim_b, revoked_commitment_b); } // Since Bob was able to confirm his revoked commitment, he'll now try to claim the HTLCs @@ -2346,21 +2295,7 @@ fn test_anchors_aggregated_revoked_htlc_tx() { // the second level instead. let revoked_claims = { let txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0); - assert_eq!(txn.len(), 4); - - let revoked_to_self_claim_a = txn.iter().find(|tx| - tx.input.len() == 1 && - tx.output.len() == 1 && - tx.input[0].previous_output.txid == revoked_commitment_a.txid() - ).unwrap(); - check_spends!(revoked_to_self_claim_a, revoked_commitment_a); - - let revoked_to_self_claim_b = txn.iter().find(|tx| - tx.input.len() == 1 && - tx.output.len() == 1 && - tx.input[0].previous_output.txid == revoked_commitment_b.txid() - ).unwrap(); - check_spends!(revoked_to_self_claim_b, revoked_commitment_b); + assert_eq!(txn.len(), 2); let revoked_htlc_claims = txn.iter().filter(|tx| tx.input.len() == 2 && @@ -2393,12 +2328,12 @@ fn test_anchors_aggregated_revoked_htlc_tx() { assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty()); let spendable_output_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events(); - assert_eq!(spendable_output_events.len(), 4); + assert_eq!(spendable_output_events.len(), 2); for (idx, event) in spendable_output_events.iter().enumerate() { if let Event::SpendableOutputs { outputs } = event { assert_eq!(outputs.len(), 1); let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs( - &[&outputs[0]], Vec::new(), Script::new_op_return(&[]), 253, &Secp256k1::new(), + &[&outputs[0]], Vec::new(), Script::new_op_return(&[]), 253, None, &Secp256k1::new(), ).unwrap(); check_spends!(spend_tx, revoked_claims[idx]); } else { @@ -2408,7 +2343,8 @@ fn test_anchors_aggregated_revoked_htlc_tx() { assert!(nodes[0].node.list_channels().is_empty()); assert!(nodes[1].node.list_channels().is_empty()); - assert!(nodes[0].chain_monitor.chain_monitor.get_claimable_balances(&[]).is_empty()); + // On the Alice side, the individual to_self_claim are still pending confirmation. + assert_eq!(nodes[0].chain_monitor.chain_monitor.get_claimable_balances(&[]).len(), 2); // TODO: From Bob's PoV, he still thinks he can claim the outputs from his revoked commitment. // This needs to be fixed before we enable pruning `ChannelMonitor`s once they don't have any // balances to claim. diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 4b2eb9674..76ed56635 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -26,7 +26,7 @@ use bitcoin::secp256k1::PublicKey; use bitcoin::secp256k1::ecdsa::Signature; -use bitcoin::secp256k1; +use bitcoin::{secp256k1, Witness}; use bitcoin::blockdata::script::Script; use bitcoin::hash_types::{Txid, BlockHash}; @@ -42,7 +42,7 @@ use crate::io_extras::read_to_end; use crate::events::{MessageSendEventsProvider, OnionMessageProvider}; use crate::util::logger; -use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname}; +use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited}; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; @@ -158,6 +158,8 @@ pub struct Pong { /// An [`open_channel`] message to be sent to or received from a peer. /// +/// Used in V1 channel establishment +/// /// [`open_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message #[derive(Clone, Debug, PartialEq, Eq)] pub struct OpenChannel { @@ -199,8 +201,8 @@ pub struct OpenChannel { pub first_per_commitment_point: PublicKey, /// The channel flags to be used pub channel_flags: u8, - /// Optionally, a request to pre-set the to-sender output's `scriptPubkey` for when we collaboratively close - pub shutdown_scriptpubkey: OptionalField