Merge pull request #2708 from TheBlueMatt/2023-11-less-graph-memory-frag
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Mon, 13 Nov 2023 16:45:26 +0000 (16:45 +0000)
committerGitHub <noreply@github.com>
Mon, 13 Nov 2023 16:45:26 +0000 (16:45 +0000)
Reduce common allocations across the codebase

24 files changed:
fuzz/README.md
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
lightning-background-processor/src/lib.rs
lightning-invoice/src/utils.rs
lightning/src/events/mod.rs
lightning/src/ln/async_signer_tests.rs
lightning/src/ln/chanmon_update_fail_tests.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/mod.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onion_utils.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/priv_short_conf_tests.rs
lightning/src/ln/reload_tests.rs
lightning/src/ln/shutdown_tests.rs
lightning/src/offers/invoice.rs
lightning/src/offers/invoice_request.rs
lightning/src/offers/merkle.rs
lightning/src/onion_message/mod.rs
lightning/src/util/config.rs

index bfc8fa5f4bfb5c6ae71b5d1262d17bb831d1ee52..987288b5d932f908f456bde2dc34d6f3e2289928 100644 (file)
@@ -1,22 +1,23 @@
 # Fuzzing
 
-Fuzz tests generate a ton of random parameter arguments to the program and then validate that none cause it to crash.
+Fuzz tests generate a ton of random parameter arguments to the program and then validate that none 
+cause it to crash.
 
 ## How does it work?
 
-Typically, Travis CI will run `travis-fuzz.sh` on one of the environments the automated tests are configured for.
-This is the most time-consuming component of the continuous integration workflow, so it is recommended that you detect
-issues locally, and Travis merely acts as a sanity check. Fuzzing is further only effective with
-a lot of CPU time, indicating that if crash scenarios are discovered on Travis with its low
-runtime constraints, the crash is caused relatively easily.
+Typically, CI will run `ci-fuzz.sh` on one of the environments the automated tests are
+configured for. Fuzzing is further only effective with a lot of CPU time, indicating that if crash 
+scenarios are discovered on CI with its low runtime constraints, the crash is caused relatively
+easily.
 
 ## How do I run fuzz tests locally?
 
-You typically won't need to run the entire combination of different fuzzing tools. For local execution, `honggfuzz`
-should be more than sufficient. 
+We support multiple fuzzing engines such as `honggfuzz`, `libFuzzer` and `AFL`. You typically won't 
+need to run the entire suite of different fuzzing tools. For local execution, `honggfuzz`should be 
+more than sufficient. 
 
 ### Setup
-
+#### Honggfuzz
 To install `honggfuzz`, simply run
 
 ```shell
@@ -31,9 +32,18 @@ cargo update -p honggfuzz --precise "0.5.52"
 cargo install --force honggfuzz --version "0.5.52"
 ```
 
+#### cargo-fuzz / libFuzzer
+To install `cargo-fuzz`, simply run
+
+```shell
+cargo update
+cargo install --force cargo-fuzz
+```
+
 ### Execution
 
-To run the Hongg fuzzer, do
+#### Honggfuzz
+To run fuzzing using `honggfuzz`, do
 
 ```shell
 export CPU_COUNT=1 # replace as needed
@@ -46,19 +56,39 @@ cargo hfuzz run $TARGET
 
 (Or, for a prettier output, replace the last line with `cargo --color always hfuzz run $TARGET`.)
 
+#### cargo-fuzz / libFuzzer
+To run fuzzing using `cargo-fuzz / libFuzzer`, run
+
+```shell
+rustup install nightly # Note: libFuzzer requires a nightly version of rust.
+cargo +nightly fuzz run --features "libfuzzer_fuzz" msg_ping_target
+```
+Note: If you encounter a `SIGKILL` during run/build check for OOM in kernel logs and consider 
+increasing RAM size for VM.
+
+If you wish to just generate fuzzing binary executables for `libFuzzer` and not run them:
+```shell 
+cargo +nightly fuzz build --features "libfuzzer_fuzz" msg_ping_target 
+# Generates binary artifact in path ./target/aarch64-unknown-linux-gnu/release/msg_ping_target
+# Exact path depends on your system architecture.
+```
+You can upload the build artifact generated above to `ClusterFuzz` for distributed fuzzing.
+
+### List Fuzzing Targets
 To see a list of available fuzzing targets, run:
 
 ```shell
 ls ./src/bin/
 ```
 
-## A fuzz test failed on Travis, what do I do?
+## A fuzz test failed, what do I do?
 
-You're trying to create a PR, but need to find the underlying cause of that pesky fuzz failure blocking the merge?
+You're trying to create a PR, but need to find the underlying cause of that pesky fuzz failure 
+blocking the merge?
 
 Worry not, for this is easily traced.
 
-If your Travis output log looks like this:
+If your output log looks like this:
 
 ```
 Size:639 (i,b,hw,ed,ip,cmp): 0/0/0/0/0/1, Tot:0/0/0/2036/5/28604
@@ -66,13 +96,13 @@ Seen a crash. Terminating all fuzzing threads
 
 … # a lot of lines in between
 
-<0x0000555555565559> [func:UNKNOWN file: line:0 module:/home/travis/build/rust-bitcoin/rust-lightning/fuzz/hfuzz_target/x86_64-unknown-linux-gnu/release/full_stack_target]
+<0x0000555555565559> [func:UNKNOWN file: line:0 module:./rust-lightning/fuzz/hfuzz_target/x86_64-unknown-linux-gnu/release/full_stack_target]
 <0x0000000000000000> [func:UNKNOWN file: line:0 module:UNKNOWN]
 =====================================================================
 2d3136383734090101010101010101010101010101010101010101010101
 010101010100040101010101010101010101010103010101010100010101
 0069d07c319a4961
-The command "if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./travis-fuzz.sh; fi" exited with 1.
+The command "if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./ci-fuzz.sh; fi" exited with 1.
 ```
 
 Note that the penultimate stack trace line ends in `release/full_stack_target]`. That indicates that
index ea0b78dc8ae77096cb1d1e21f30f05512915937c..3e7737ac19ec83e90eca1349ad37d9cd4c812f52 100644 (file)
@@ -526,7 +526,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
                                features: $source.init_features(), networks: None, remote_network_address: None
                        }, false).unwrap();
 
-                       $source.create_channel($dest.get_our_node_id(), 100_000, 42, 0, None).unwrap();
+                       $source.create_channel($dest.get_our_node_id(), 100_000, 42, 0, None, None).unwrap();
                        let open_channel = {
                                let events = $source.get_and_clear_pending_msg_events();
                                assert_eq!(events.len(), 1);
index 9ed58dd949d82f6c046ef948bc61bcb4549a6d64..1034f36686e407756ba5176b9bdc4722ab01dfa9 100644 (file)
@@ -571,7 +571,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
                                let their_key = get_pubkey!();
                                let chan_value = slice_to_be24(get_slice!(3)) as u64;
                                let push_msat_value = slice_to_be24(get_slice!(3)) as u64;
-                               if channelmanager.create_channel(their_key, chan_value, push_msat_value, 0, None).is_err() { return; }
+                               if channelmanager.create_channel(their_key, chan_value, push_msat_value, 0, None, None).is_err() { return; }
                        },
                        6 => {
                                let mut channels = channelmanager.list_channels();
index aa6d0b0615ef21e221e745e3563f1ddc9c2bf620..24d39bf50c1991357859c0ead0b9ecdc15247a57 100644 (file)
@@ -1241,7 +1241,7 @@ mod tests {
 
        macro_rules! begin_open_channel {
                ($node_a: expr, $node_b: expr, $channel_value: expr) => {{
-                       $node_a.node.create_channel($node_b.node.get_our_node_id(), $channel_value, 100, 42, None).unwrap();
+                       $node_a.node.create_channel($node_b.node.get_our_node_id(), $channel_value, 100, 42, None, None).unwrap();
                        $node_b.node.handle_open_channel(&$node_a.node.get_our_node_id(), &get_event_msg!($node_a, MessageSendEvent::SendOpenChannel, $node_b.node.get_our_node_id()));
                        $node_a.node.handle_accept_channel(&$node_b.node.get_our_node_id(), &get_event_msg!($node_b, MessageSendEvent::SendAcceptChannel, $node_a.node.get_our_node_id()));
                }}
index a512b2de05dd74eb7125bf543d44fd0dbe5ec315..d551d248a6cc1471fee0e1393d37e9859b0deaa4 100644 (file)
@@ -1141,7 +1141,7 @@ mod test {
                // is never handled, the `channel.counterparty.forwarding_info` is never assigned.
                let mut private_chan_cfg = UserConfig::default();
                private_chan_cfg.channel_handshake_config.announced_channel = false;
-               let temporary_channel_id = nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
+               let temporary_channel_id = nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None, Some(private_chan_cfg)).unwrap();
                let open_channel = get_event_msg!(nodes[2], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
                nodes[0].node.handle_open_channel(&nodes[2].node.get_our_node_id(), &open_channel);
                let accept_channel = get_event_msg!(nodes[0], MessageSendEvent::SendAcceptChannel, nodes[2].node.get_our_node_id());
@@ -1547,7 +1547,7 @@ mod test {
                // is never handled, the `channel.counterparty.forwarding_info` is never assigned.
                let mut private_chan_cfg = UserConfig::default();
                private_chan_cfg.channel_handshake_config.announced_channel = false;
-               let temporary_channel_id = nodes[1].node.create_channel(nodes[3].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
+               let temporary_channel_id = nodes[1].node.create_channel(nodes[3].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None, Some(private_chan_cfg)).unwrap();
                let open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[3].node.get_our_node_id());
                nodes[3].node.handle_open_channel(&nodes[1].node.get_our_node_id(), &open_channel);
                let accept_channel = get_event_msg!(nodes[3], MessageSendEvent::SendAcceptChannel, nodes[1].node.get_our_node_id());
index 32192297432d1873c6898e79ccf41f8b66ada62a..5ffea4ee6485399f070b65f3e3798775c58a0693 100644 (file)
@@ -102,9 +102,15 @@ pub struct ClaimedHTLC {
        pub cltv_expiry: u32,
        /// The amount (in msats) of this part of an MPP.
        pub value_msat: u64,
+       /// The extra fee our counterparty skimmed off the top of this HTLC, if any.
+       ///
+       /// This value will always be 0 for [`ClaimedHTLC`]s serialized with LDK versions prior to
+       /// 0.0.119.
+       pub counterparty_skimmed_fee_msat: u64,
 }
 impl_writeable_tlv_based!(ClaimedHTLC, {
        (0, channel_id, required),
+       (1, counterparty_skimmed_fee_msat, (default_value, 0u64)),
        (2, user_channel_id, required),
        (4, cltv_expiry, required),
        (6, value_msat, required),
index a82fd2e4201dfe2d514224cf35f3e917ee0f0fe7..0f51bea0d36cc18ac022d70d1482e7202a14e3b4 100644 (file)
@@ -23,7 +23,7 @@ fn test_async_commitment_signature_for_funding_created() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
 
        // nodes[0] --- open_channel --> nodes[1]
        let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
@@ -74,7 +74,7 @@ fn test_async_commitment_signature_for_funding_signed() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
 
        // nodes[0] --- open_channel --> nodes[1]
        let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
@@ -177,7 +177,7 @@ fn test_async_commitment_signature_for_funding_signed_0conf() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // nodes[0] --- open_channel --> nodes[1]
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
index 6fb21b3a15b1d0631e513068c66a8afc6769baa3..af827b8cebbc3a60cfe2a46ba02ad37cc0d59abf 100644 (file)
@@ -1850,7 +1850,7 @@ fn do_during_funding_monitor_fail(confirm_a_first: bool, restore_b_before_conf:
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 43, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 43, None, None).unwrap();
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
        nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
 
@@ -2768,7 +2768,7 @@ fn do_test_outbound_reload_without_init_mon(use_0conf: bool) {
 
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 43, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 43, None, None).unwrap();
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
 
        let events = nodes[1].node.get_and_clear_pending_events();
@@ -2859,7 +2859,7 @@ fn do_test_inbound_reload_without_init_mon(use_0conf: bool, lock_commitment: boo
 
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 43, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 43, None, None).unwrap();
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
 
        let events = nodes[1].node.get_and_clear_pending_events();
index 7d5af2774175dd1bfb12195dead1de423434c9c7..16e8ed3ef69503cb9e9ed56172a6749b3747254b 100644 (file)
@@ -48,6 +48,7 @@ use crate::util::scid_utils::scid_from_parts;
 use crate::io;
 use crate::prelude::*;
 use core::{cmp,mem,fmt};
+use core::convert::TryInto;
 use core::ops::Deref;
 #[cfg(any(test, fuzzing, debug_assertions))]
 use crate::sync::Mutex;
@@ -1195,8 +1196,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                match self.config.options.max_dust_htlc_exposure {
                        MaxDustHTLCExposure::FeeRateMultiplier(multiplier) => {
                                let feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(
-                                       ConfirmationTarget::OnChainSweep);
-                               feerate_per_kw as u64 * multiplier
+                                       ConfirmationTarget::OnChainSweep) as u64;
+                               feerate_per_kw.saturating_mul(multiplier)
                        },
                        MaxDustHTLCExposure::FixedLimitMsat(limit) => limit,
                }
@@ -1780,14 +1781,14 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                         context.holder_dust_limit_satoshis       + dust_buffer_feerate * htlc_timeout_tx_weight(context.get_channel_type()) / 1000)
                };
                let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
-               if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat as i64 {
+               if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat.try_into().unwrap_or(i64::max_value()) {
                        remaining_msat_below_dust_exposure_limit =
                                Some(max_dust_htlc_exposure_msat.saturating_sub(on_counterparty_dust_htlc_exposure_msat));
                        dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_success_dust_limit * 1000);
                }
 
                let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
-               if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat as i64 {
+               if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat.try_into().unwrap_or(i64::max_value()) {
                        remaining_msat_below_dust_exposure_limit = Some(cmp::min(
                                remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()),
                                max_dust_htlc_exposure_msat.saturating_sub(on_holder_dust_htlc_exposure_msat)));
@@ -5876,7 +5877,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
        pub fn new<ES: Deref, F: Deref>(
                fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP, counterparty_node_id: PublicKey, their_features: &InitFeatures,
                channel_value_satoshis: u64, push_msat: u64, user_id: u128, config: &UserConfig, current_chain_height: u32,
-               outbound_scid_alias: u64
+               outbound_scid_alias: u64, temporary_channel_id: Option<ChannelId>
        ) -> Result<OutboundV1Channel<SP>, APIError>
        where ES::Target: EntropySource,
              F::Target: FeeEstimator
@@ -5943,7 +5944,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
                        Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}),
                };
 
-               let temporary_channel_id = ChannelId::temporary_from_entropy_source(entropy_source);
+               let temporary_channel_id = temporary_channel_id.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
 
                Ok(Self {
                        context: ChannelContext {
@@ -7893,7 +7894,7 @@ mod tests {
                let secp_ctx = Secp256k1::new();
                let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               match OutboundV1Channel::<&TestKeysInterface>::new(&LowerBoundedFeeEstimator::new(&TestFeeEstimator { fee_est: 253 }), &&keys_provider, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config, 0, 42) {
+               match OutboundV1Channel::<&TestKeysInterface>::new(&LowerBoundedFeeEstimator::new(&TestFeeEstimator { fee_est: 253 }), &&keys_provider, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config, 0, 42, None) {
                        Err(APIError::IncompatibleShutdownScript { script }) => {
                                assert_eq!(script.into_inner(), non_v0_segwit_shutdown_script.into_inner());
                        },
@@ -7916,7 +7917,7 @@ mod tests {
 
                let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&bounded_fee_estimator, &&keys_provider, &&keys_provider, node_a_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap();
+               let node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&bounded_fee_estimator, &&keys_provider, &&keys_provider, node_a_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42, None).unwrap();
 
                // Now change the fee so we can check that the fee in the open_channel message is the
                // same as the old fee.
@@ -7943,7 +7944,7 @@ mod tests {
                // Create Node A's channel pointing to Node B's pubkey
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap();
+               let mut node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42, None).unwrap();
 
                // Create Node B's channel by receiving Node A's open_channel message
                // Make sure A's dust limit is as we expect.
@@ -8024,7 +8025,7 @@ mod tests {
 
                let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut chan = OutboundV1Channel::<&TestKeysInterface>::new(&fee_est, &&keys_provider, &&keys_provider, node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap();
+               let mut chan = OutboundV1Channel::<&TestKeysInterface>::new(&fee_est, &&keys_provider, &&keys_provider, node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42, None).unwrap();
 
                let commitment_tx_fee_0_htlcs = commit_tx_fee_msat(chan.context.feerate_per_kw, 0, chan.context.get_channel_type());
                let commitment_tx_fee_1_htlc = commit_tx_fee_msat(chan.context.feerate_per_kw, 1, chan.context.get_channel_type());
@@ -8073,7 +8074,7 @@ mod tests {
                // Create Node A's channel pointing to Node B's pubkey
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap();
+               let mut node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42, None).unwrap();
 
                // Create Node B's channel by receiving Node A's open_channel message
                let open_channel_msg = node_a_chan.get_open_channel(chain_hash);
@@ -8136,12 +8137,12 @@ mod tests {
                // Test that `OutboundV1Channel::new` creates a channel with the correct value for
                // `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value,
                // which is set to the lower bound + 1 (2%) of the `channel_value`.
-               let chan_1 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_2_percent), 10000000, 100000, 42, &config_2_percent, 0, 42).unwrap();
+               let chan_1 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_2_percent), 10000000, 100000, 42, &config_2_percent, 0, 42, None).unwrap();
                let chan_1_value_msat = chan_1.context.channel_value_satoshis * 1000;
                assert_eq!(chan_1.context.holder_max_htlc_value_in_flight_msat, (chan_1_value_msat as f64 * 0.02) as u64);
 
                // Test with the upper bound - 1 of valid values (99%).
-               let chan_2 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_99_percent), 10000000, 100000, 42, &config_99_percent, 0, 42).unwrap();
+               let chan_2 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_99_percent), 10000000, 100000, 42, &config_99_percent, 0, 42, None).unwrap();
                let chan_2_value_msat = chan_2.context.channel_value_satoshis * 1000;
                assert_eq!(chan_2.context.holder_max_htlc_value_in_flight_msat, (chan_2_value_msat as f64 * 0.99) as u64);
 
@@ -8161,14 +8162,14 @@ mod tests {
 
                // Test that `OutboundV1Channel::new` uses the lower bound of the configurable percentage values (1%)
                // if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1.
-               let chan_5 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_0_percent), 10000000, 100000, 42, &config_0_percent, 0, 42).unwrap();
+               let chan_5 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_0_percent), 10000000, 100000, 42, &config_0_percent, 0, 42, None).unwrap();
                let chan_5_value_msat = chan_5.context.channel_value_satoshis * 1000;
                assert_eq!(chan_5.context.holder_max_htlc_value_in_flight_msat, (chan_5_value_msat as f64 * 0.01) as u64);
 
                // Test that `OutboundV1Channel::new` uses the upper bound of the configurable percentage values
                // (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value
                // than 100.
-               let chan_6 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_101_percent), 10000000, 100000, 42, &config_101_percent, 0, 42).unwrap();
+               let chan_6 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_101_percent), 10000000, 100000, 42, &config_101_percent, 0, 42, None).unwrap();
                let chan_6_value_msat = chan_6.context.channel_value_satoshis * 1000;
                assert_eq!(chan_6.context.holder_max_htlc_value_in_flight_msat, chan_6_value_msat);
 
@@ -8221,7 +8222,7 @@ mod tests {
 
                let mut outbound_node_config = UserConfig::default();
                outbound_node_config.channel_handshake_config.their_channel_reserve_proportional_millionths = (outbound_selected_channel_reserve_perc * 1_000_000.0) as u32;
-               let chan = OutboundV1Channel::<&TestKeysInterface>::new(&&fee_est, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&outbound_node_config), channel_value_satoshis, 100_000, 42, &outbound_node_config, 0, 42).unwrap();
+               let chan = OutboundV1Channel::<&TestKeysInterface>::new(&&fee_est, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&outbound_node_config), channel_value_satoshis, 100_000, 42, &outbound_node_config, 0, 42, None).unwrap();
 
                let expected_outbound_selected_chan_reserve = cmp::max(MIN_THEIR_CHAN_RESERVE_SATOSHIS, (chan.context.channel_value_satoshis as f64 * outbound_selected_channel_reserve_perc) as u64);
                assert_eq!(chan.context.holder_selected_channel_reserve_satoshis, expected_outbound_selected_chan_reserve);
@@ -8258,7 +8259,7 @@ mod tests {
                // Create Node A's channel pointing to Node B's pubkey
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap();
+               let mut node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42, None).unwrap();
 
                // Create Node B's channel by receiving Node A's open_channel message
                // Make sure A's dust limit is as we expect.
@@ -8360,7 +8361,7 @@ mod tests {
                let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let mut config = UserConfig::default();
                config.channel_handshake_config.announced_channel = false;
-               let mut chan = OutboundV1Channel::<&Keys>::new(&LowerBoundedFeeEstimator::new(&feeest), &&keys_provider, &&keys_provider, counterparty_node_id, &channelmanager::provided_init_features(&config), 10_000_000, 0, 42, &config, 0, 42).unwrap(); // Nothing uses their network key in this test
+               let mut chan = OutboundV1Channel::<&Keys>::new(&LowerBoundedFeeEstimator::new(&feeest), &&keys_provider, &&keys_provider, counterparty_node_id, &channelmanager::provided_init_features(&config), 10_000_000, 0, 42, &config, 0, 42, None).unwrap(); // Nothing uses their network key in this test
                chan.context.holder_dust_limit_satoshis = 546;
                chan.context.counterparty_selected_channel_reserve_satoshis = Some(0); // Filled in in accept_channel
 
@@ -9106,7 +9107,7 @@ mod tests {
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
                let node_a_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider,
-                       node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap();
+                       node_b_node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42, None).unwrap();
 
                let mut channel_type_features = ChannelTypeFeatures::only_static_remote_key();
                channel_type_features.set_zero_conf_required();
@@ -9141,7 +9142,7 @@ mod tests {
                let channel_a = OutboundV1Channel::<&TestKeysInterface>::new(
                        &fee_estimator, &&keys_provider, &&keys_provider, node_id_b,
                        &channelmanager::provided_init_features(&UserConfig::default()), 10000000, 100000, 42,
-                       &config, 0, 42
+                       &config, 0, 42, None
                ).unwrap();
                assert!(!channel_a.context.channel_type.supports_anchors_zero_fee_htlc_tx());
 
@@ -9151,7 +9152,8 @@ mod tests {
 
                let channel_a = OutboundV1Channel::<&TestKeysInterface>::new(
                        &fee_estimator, &&keys_provider, &&keys_provider, node_id_b,
-                       &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42
+                       &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42,
+                       None
                ).unwrap();
 
                let open_channel_msg = channel_a.get_open_channel(ChainHash::using_genesis_block(network));
@@ -9188,7 +9190,8 @@ mod tests {
 
                let channel_a = OutboundV1Channel::<&TestKeysInterface>::new(
                        &fee_estimator, &&keys_provider, &&keys_provider, node_id_b,
-                       &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42
+                       &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42,
+                       None
                ).unwrap();
 
                // Set `channel_type` to `None` to force the implicit feature negotiation.
@@ -9234,7 +9237,8 @@ mod tests {
                // B as it's not supported by LDK.
                let channel_a = OutboundV1Channel::<&TestKeysInterface>::new(
                        &fee_estimator, &&keys_provider, &&keys_provider, node_id_b,
-                       &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42
+                       &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42,
+                       None
                ).unwrap();
 
                let mut open_channel_msg = channel_a.get_open_channel(ChainHash::using_genesis_block(network));
@@ -9253,7 +9257,7 @@ mod tests {
                // LDK.
                let mut channel_a = OutboundV1Channel::<&TestKeysInterface>::new(
                        &fee_estimator, &&keys_provider, &&keys_provider, node_id_b, &simple_anchors_init,
-                       10000000, 100000, 42, &config, 0, 42
+                       10000000, 100000, 42, &config, 0, 42, None
                ).unwrap();
 
                let open_channel_msg = channel_a.get_open_channel(ChainHash::using_genesis_block(network));
@@ -9303,6 +9307,7 @@ mod tests {
                        &config,
                        0,
                        42,
+                       None
                ).unwrap();
 
                let open_channel_msg = node_a_chan.get_open_channel(ChainHash::using_genesis_block(network));
index 37a8feb446d6865bcdbe7849e9c1a854d318b4d9..ce79f25400a53645b8fccf2f71ddb7ca48f46e64 100644 (file)
@@ -238,6 +238,7 @@ impl From<&ClaimableHTLC> for events::ClaimedHTLC {
                        user_channel_id: val.prev_hop.user_channel_id.unwrap_or(0),
                        cltv_expiry: val.cltv_expiry,
                        value_msat: val.value,
+                       counterparty_skimmed_fee_msat: val.counterparty_skimmed_fee_msat.unwrap_or(0),
                }
        }
 }
@@ -2390,6 +2391,9 @@ where
        /// connection is available, the outbound `open_channel` message may fail to send, resulting in
        /// the channel eventually being silently forgotten (dropped on reload).
        ///
+       /// If `temporary_channel_id` is specified, it will be used as the temporary channel ID of the
+       /// channel. Otherwise, a random one will be generated for you.
+       ///
        /// Returns the new Channel's temporary `channel_id`. This ID will appear as
        /// [`Event::FundingGenerationReady::temporary_channel_id`] and in
        /// [`ChannelDetails::channel_id`] until after
@@ -2400,7 +2404,7 @@ where
        /// [`Event::FundingGenerationReady::user_channel_id`]: events::Event::FundingGenerationReady::user_channel_id
        /// [`Event::FundingGenerationReady::temporary_channel_id`]: events::Event::FundingGenerationReady::temporary_channel_id
        /// [`Event::ChannelClosed::channel_id`]: events::Event::ChannelClosed::channel_id
-       pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, override_config: Option<UserConfig>) -> Result<ChannelId, APIError> {
+       pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, temporary_channel_id: Option<ChannelId>, override_config: Option<UserConfig>) -> Result<ChannelId, APIError> {
                if channel_value_satoshis < 1000 {
                        return Err(APIError::APIMisuseError { err: format!("Channel value must be at least 1000 satoshis. It was {}", channel_value_satoshis) });
                }
@@ -2415,13 +2419,20 @@ where
                        .ok_or_else(|| APIError::APIMisuseError{ err: format!("Not connected to node: {}", their_network_key) })?;
 
                let mut peer_state = peer_state_mutex.lock().unwrap();
+
+               if let Some(temporary_channel_id) = temporary_channel_id {
+                       if peer_state.channel_by_id.contains_key(&temporary_channel_id) {
+                               return Err(APIError::APIMisuseError{ err: format!("Channel with temporary channel ID {} already exists!", temporary_channel_id)});
+                       }
+               }
+
                let channel = {
                        let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
                        let their_features = &peer_state.latest_features;
                        let config = if override_config.is_some() { override_config.as_ref().unwrap() } else { &self.default_configuration };
                        match OutboundV1Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider, their_network_key,
                                their_features, channel_value_satoshis, push_msat, user_channel_id, config,
-                               self.best_block.read().unwrap().height(), outbound_scid_alias)
+                               self.best_block.read().unwrap().height(), outbound_scid_alias, temporary_channel_id)
                        {
                                Ok(res) => res,
                                Err(e) => {
@@ -3419,12 +3430,10 @@ where
                let prng_seed = self.entropy_source.get_secure_random_bytes();
                let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
 
-               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)?;
-
-               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 (onion_packet, htlc_msat, htlc_cltv) = onion_utils::create_payment_onion(
+                       &self.secp_ctx, &path, &session_priv, total_value, recipient_onion, cur_height,
+                       payment_hash, keysend_preimage, prng_seed
+               )?;
 
                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) {
@@ -11402,7 +11411,7 @@ mod tests {
                let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None, None).unwrap();
                let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
                let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
@@ -11560,7 +11569,7 @@ mod tests {
                let intercept_id = InterceptId([0; 32]);
 
                // Test the API functions.
-               check_not_connected_to_peer_error(nodes[0].node.create_channel(unkown_public_key, 1_000_000, 500_000_000, 42, None), unkown_public_key);
+               check_not_connected_to_peer_error(nodes[0].node.create_channel(unkown_public_key, 1_000_000, 500_000_000, 42, None, None), unkown_public_key);
 
                check_unkown_peer_error(nodes[0].node.accept_inbound_channel(&channel_id, &unkown_public_key, 42), unkown_public_key);
 
@@ -11615,7 +11624,7 @@ mod tests {
 
                // Note that create_network connects the nodes together for us
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                let mut funding_tx = None;
@@ -11702,7 +11711,7 @@ mod tests {
                        open_channel_msg.temporary_channel_id);
 
                // Of course, however, outbound channels are always allowed
-               nodes[1].node.create_channel(last_random_pk, 100_000, 0, 42, None).unwrap();
+               nodes[1].node.create_channel(last_random_pk, 100_000, 0, 42, None, None).unwrap();
                get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, last_random_pk);
 
                // If we fund the first channel, nodes[0] has a live on-chain channel with us, it is now
@@ -11729,7 +11738,7 @@ mod tests {
 
                // Note that create_network connects the nodes together for us
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                for _ in 0..super::MAX_UNFUNDED_CHANS_PER_PEER {
@@ -11745,7 +11754,7 @@ mod tests {
                        open_channel_msg.temporary_channel_id);
 
                // but we can still open an outbound channel.
-               nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
 
                // but even with such an outbound channel, additional inbound channels will still fail.
@@ -11767,7 +11776,7 @@ mod tests {
 
                // Note that create_network connects the nodes together for us
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                // First, get us up to MAX_UNFUNDED_CHANNEL_PEERS so we can test at the edge
@@ -11905,7 +11914,7 @@ mod tests {
                        &[Some(anchors_cfg.clone()), Some(anchors_cfg.clone()), Some(anchors_manual_accept_cfg.clone())]);
                let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
@@ -11946,7 +11955,7 @@ mod tests {
                let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config.clone()), Some(anchors_config.clone())]);
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None, None).unwrap();
                let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
                assert!(open_channel_msg.channel_type.as_ref().unwrap().supports_anchors_zero_fee_htlc_tx());
 
@@ -12204,7 +12213,7 @@ pub mod bench {
                node_b.peer_connected(&node_a.get_our_node_id(), &Init {
                        features: node_a.init_features(), networks: None, remote_network_address: None
                }, false).unwrap();
-               node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None).unwrap();
+               node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None, None).unwrap();
                node_b.handle_open_channel(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id()));
                node_a.handle_accept_channel(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id()));
 
index 08dbda3fe758c3548b17f3f02874c6f9d222f550..c335b11d9ca24d873c689d448eefaf23fb99d034 100644 (file)
@@ -1126,7 +1126,7 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r
        let initiator_channels = initiator.node.list_usable_channels().len();
        let receiver_channels = receiver.node.list_usable_channels().len();
 
-       initiator.node.create_channel(receiver.node.get_our_node_id(), 100_000, 10_001, 42, initiator_config).unwrap();
+       initiator.node.create_channel(receiver.node.get_our_node_id(), 100_000, 10_001, 42, None, initiator_config).unwrap();
        let open_channel = get_event_msg!(initiator, MessageSendEvent::SendOpenChannel, receiver.node.get_our_node_id());
 
        receiver.node.handle_open_channel(&initiator.node.get_our_node_id(), &open_channel);
@@ -1192,7 +1192,7 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r
 }
 
 pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64) -> Transaction {
-       let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap();
+       let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None, None).unwrap();
        let open_channel_msg = get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id());
        assert_eq!(open_channel_msg.temporary_channel_id, create_chan_id);
        assert_eq!(node_a.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 42);
@@ -1309,7 +1309,7 @@ pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c: 'd, 'd>(nodes:
 pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize, channel_value: u64, push_msat: u64) -> (msgs::ChannelReady, Transaction) {
        let mut no_announce_cfg = test_default_channel_config();
        no_announce_cfg.channel_handshake_config.announced_channel = false;
-       nodes[a].node.create_channel(nodes[b].node.get_our_node_id(), channel_value, push_msat, 42, Some(no_announce_cfg)).unwrap();
+       nodes[a].node.create_channel(nodes[b].node.get_our_node_id(), channel_value, push_msat, 42, None, Some(no_announce_cfg)).unwrap();
        let open_channel = get_event_msg!(nodes[a], MessageSendEvent::SendOpenChannel, nodes[b].node.get_our_node_id());
        nodes[b].node.handle_open_channel(&nodes[a].node.get_our_node_id(), &open_channel);
        let accept_channel = get_event_msg!(nodes[b], MessageSendEvent::SendAcceptChannel, nodes[a].node.get_our_node_id());
@@ -3438,6 +3438,7 @@ pub fn create_batch_channel_funding<'a, 'b, 'c>(
                // Initialize channel opening.
                let temp_chan_id = funding_node.node.create_channel(
                        other_node.node.get_our_node_id(), *channel_value_satoshis, *push_msat, *user_channel_id,
+                       None,
                        *override_config,
                ).unwrap();
                let open_channel_msg = get_event_msg!(funding_node, MessageSendEvent::SendOpenChannel, other_node.node.get_our_node_id());
index 8ceb9728931972e4d172540b801db379370404eb..98bb83a7f9d466f802499328dcabd9452528f9a9 100644 (file)
@@ -81,7 +81,7 @@ fn test_insane_channel_opens() {
        let push_msat = (channel_value_sat - channel_reserve_satoshis) * 1000;
 
        // Have node0 initiate a channel to node1 with aforementioned parameters
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_sat, push_msat, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_sat, push_msat, 42, None, None).unwrap();
 
        // Extract the channel open message from node0 to node1
        let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
@@ -135,7 +135,7 @@ fn test_funding_exceeds_no_wumbo_limit() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       match nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), MAX_FUNDING_SATOSHIS_NO_WUMBO + 1, 0, 42, None) {
+       match nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), MAX_FUNDING_SATOSHIS_NO_WUMBO + 1, 0, 42, None, None) {
                Err(APIError::APIMisuseError { err }) => {
                        assert_eq!(format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, MAX_FUNDING_SATOSHIS_NO_WUMBO + 1), err);
                },
@@ -161,7 +161,7 @@ fn do_test_counterparty_no_reserve(send_from_initiator: bool) {
        push_amt -= feerate_per_kw as u64 * (commitment_tx_base_weight(&channel_type_features) + 4 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 * 1000;
        push_amt -= get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
 
-       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, if send_from_initiator { 0 } else { push_amt }, 42, None).unwrap();
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, if send_from_initiator { 0 } else { push_amt }, 42, None, None).unwrap();
        let mut open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        if !send_from_initiator {
                open_channel_message.channel_reserve_satoshis = 0;
@@ -523,7 +523,7 @@ fn do_test_sanity_on_in_flight_opens(steps: u8) {
        }
 
        if steps & 0x0f == 0 { return; }
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        if steps & 0x0f == 1 { return; }
@@ -1681,13 +1681,13 @@ fn test_chan_init_feerate_unaffordability() {
        // HTLC.
        let mut push_amt = 100_000_000;
        push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type_features);
-       assert_eq!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, push_amt + 1, 42, None).unwrap_err(),
+       assert_eq!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, push_amt + 1, 42, None, None).unwrap_err(),
                APIError::APIMisuseError { err: "Funding amount (356) can't even pay fee for initial commitment transaction fee of 357.".to_string() });
 
        // During open, we don't have a "counterparty channel reserve" to check against, so that
        // requirement only comes into play on the open_channel handling side.
        push_amt -= get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, push_amt, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, push_amt, 42, None, None).unwrap();
        let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        open_channel_msg.push_msat += 1;
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
@@ -3695,7 +3695,7 @@ fn test_peer_disconnected_before_funding_broadcasted() {
 
        // Open a channel between `nodes[0]` and `nodes[1]`, for which the funding transaction is never
        // broadcasted, even though it's created by `nodes[0]`.
-       let expected_temporary_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
+       let expected_temporary_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None, None).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
        let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
@@ -5786,14 +5786,14 @@ fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on i
        // BOLT #2 spec: Sending node must ensure temporary_channel_id is unique from any other channel ID with the same peer.
        let channel_value_satoshis=10000;
        let push_msat=10001;
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None, None).unwrap();
        let node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &node0_to_1_send_open_channel);
        get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
 
        // Create a second channel with the same random values. This used to panic due to a colliding
        // channel_id, but now panics due to a colliding outbound SCID alias.
-       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).is_err());
+       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None, None).is_err());
 }
 
 #[test]
@@ -5806,18 +5806,18 @@ fn bolt2_open_channel_sending_node_checks_part2() {
        // BOLT #2 spec: Sending node must set funding_satoshis to less than 2^24 satoshis
        let channel_value_satoshis=2^24;
        let push_msat=10001;
-       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).is_err());
+       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None, None).is_err());
 
        // BOLT #2 spec: Sending node must set push_msat to equal or less than 1000 * funding_satoshis
        let channel_value_satoshis=10000;
        // Test when push_msat is equal to 1000 * funding_satoshis.
        let push_msat=1000*channel_value_satoshis+1;
-       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).is_err());
+       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None, None).is_err());
 
        // BOLT #2 spec: Sending node must set set channel_reserve_satoshis greater than or equal to dust_limit_satoshis
        let channel_value_satoshis=10000;
        let push_msat=10001;
-       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).is_ok()); //Create a valid channel
+       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None, None).is_ok()); //Create a valid channel
        let node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        assert!(node0_to_1_send_open_channel.channel_reserve_satoshis>=node0_to_1_send_open_channel.dust_limit_satoshis);
 
@@ -5850,7 +5850,7 @@ fn bolt2_open_channel_sane_dust_limit() {
 
        let channel_value_satoshis=1000000;
        let push_msat=10001;
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None, None).unwrap();
        let mut node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        node0_to_1_send_open_channel.dust_limit_satoshis = 547;
        node0_to_1_send_open_channel.channel_reserve_satoshis = 100001;
@@ -7156,7 +7156,7 @@ fn test_user_configurable_csv_delay() {
        // We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in OutboundV1Channel::new()
        if let Err(error) = OutboundV1Channel::new(&LowerBoundedFeeEstimator::new(&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }),
                &nodes[0].keys_manager, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &nodes[1].node.init_features(), 1000000, 1000000, 0,
-               &low_our_to_self_config, 0, 42)
+               &low_our_to_self_config, 0, 42, None)
        {
                match error {
                        APIError::APIMisuseError { err } => { assert!(regex::Regex::new(r"Configured with an unreasonable our_to_self_delay \(\d+\) putting user funds at risks").unwrap().is_match(err.as_str())); },
@@ -7165,7 +7165,7 @@ fn test_user_configurable_csv_delay() {
        } else { assert!(false) }
 
        // We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in InboundV1Channel::new()
-       nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
+       nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
        open_channel.to_self_delay = 200;
        if let Err(error) = InboundV1Channel::new(&LowerBoundedFeeEstimator::new(&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }),
@@ -7179,7 +7179,7 @@ fn test_user_configurable_csv_delay() {
        } else { assert!(false); }
 
        // We test msg.to_self_delay <= config.their_to_self_delay is enforced in Chanel::accept_channel()
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1000000, 1000000, 42, None, None).unwrap();
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
        let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
        accept_channel.to_self_delay = 200;
@@ -7197,7 +7197,7 @@ fn test_user_configurable_csv_delay() {
        check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: reason_msg }, [nodes[1].node.get_our_node_id()], 1000000);
 
        // We test msg.to_self_delay <= config.their_to_self_delay is enforced in InboundV1Channel::new()
-       nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
+       nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
        open_channel.to_self_delay = 200;
        if let Err(error) = InboundV1Channel::new(&LowerBoundedFeeEstimator::new(&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }),
@@ -7880,7 +7880,7 @@ fn test_override_channel_config() {
        let mut override_config = UserConfig::default();
        override_config.channel_handshake_config.our_to_self_delay = 200;
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 16_000_000, 12_000_000, 42, Some(override_config)).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 16_000_000, 12_000_000, 42, None, Some(override_config)).unwrap();
 
        // Assert the channel created by node0 is using the override config.
        let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
@@ -7897,7 +7897,7 @@ fn test_override_0msat_htlc_minimum() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(zero_config.clone())]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 16_000_000, 12_000_000, 42, Some(zero_config)).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 16_000_000, 12_000_000, 42, None, Some(zero_config)).unwrap();
        let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        assert_eq!(res.htlc_minimum_msat, 1);
 
@@ -7967,7 +7967,7 @@ fn test_manually_accept_inbound_channel_request() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf.clone())]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap();
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(manually_accept_conf)).unwrap();
        let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &res);
@@ -8017,7 +8017,7 @@ fn test_manually_reject_inbound_channel_request() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf.clone())]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(manually_accept_conf)).unwrap();
        let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &res);
@@ -8057,7 +8057,7 @@ fn test_can_not_accept_inbound_channel_twice() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf.clone())]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(manually_accept_conf)).unwrap();
        let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &res);
@@ -8637,7 +8637,7 @@ fn test_pre_lockin_no_chan_closed_update() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // Create an initial channel
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_chan_msg);
        let accept_chan_msg = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
@@ -8900,11 +8900,11 @@ fn test_duplicate_temporary_channel_id_from_different_peers() {
        let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
 
        // Create an first channel channel
-       nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let mut open_chan_msg_chan_1_0 = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
 
        // Create an second channel
-       nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 100000, 10001, 43, None).unwrap();
+       nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 100000, 10001, 43, None, None).unwrap();
        let mut open_chan_msg_chan_2_0 = get_event_msg!(nodes[2], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
 
        // Modify the `OpenChannel` from `nodes[2]` to `nodes[0]` to ensure that it uses the same
@@ -8955,7 +8955,7 @@ fn test_duplicate_chan_id() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // Create an initial channel
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_chan_msg);
        nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
@@ -9023,7 +9023,7 @@ fn test_duplicate_chan_id() {
        }
 
        // Now try to create a second channel which has a duplicate funding output.
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let open_chan_2_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_chan_2_msg);
        nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
@@ -9171,7 +9171,7 @@ fn test_invalid_funding_tx() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_000, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_000, 42, None, None).unwrap();
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
        nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
 
@@ -9256,7 +9256,7 @@ fn test_coinbase_funding_tx() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
@@ -9691,7 +9691,7 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        open_channel.max_htlc_value_in_flight_msat = 50_000_000;
        open_channel.max_accepted_htlcs = 60;
@@ -9873,7 +9873,7 @@ fn test_non_final_funding_tx() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
        let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_message);
        let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
@@ -9918,7 +9918,7 @@ fn test_non_final_funding_tx_within_headroom() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
        let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_message);
        let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
@@ -10218,7 +10218,7 @@ fn test_remove_expired_outbound_unfunded_channels() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
        let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_message);
        let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
@@ -10269,7 +10269,7 @@ fn test_remove_expired_inbound_unfunded_channels() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
        let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_message);
        let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
index 6a9a10c80c060b41f3a11fc128add17c99a93553..f9d364ed0db848b746ae65266f68df83d8264e82 100644 (file)
@@ -39,6 +39,7 @@ pub(crate) mod onion_utils;
 mod outbound_payment;
 pub mod wire;
 
+pub use onion_utils::create_payment_onion;
 // Older rustc (which we support) refuses to let us call the get_payment_preimage_hash!() macro
 // without the node parameter being mut. This is incorrect, and thus newer rustcs will complain
 // about an unnecessary mut. Thus, we silence the unused_mut warning in two test modules below.
index 6043bf35b99d4d85ae79a5656cc75b82e7d6c09e..d43ad6d0aebc2fd372c5c7837349a9beac0ebedf 100644 (file)
@@ -1674,17 +1674,21 @@ pub use self::fuzzy_internal_msgs::*;
 #[cfg(not(fuzzing))]
 pub(crate) use self::fuzzy_internal_msgs::*;
 
+/// BOLT 4 onion packet including hop data for the next peer.
 #[derive(Clone)]
-pub(crate) struct OnionPacket {
-       pub(crate) version: u8,
+pub struct OnionPacket {
+       /// BOLT 4 version number.
+       pub version: u8,
        /// In order to ensure we always return an error on onion decode in compliance with [BOLT
        /// #4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md), we have to
        /// deserialize `OnionPacket`s contained in [`UpdateAddHTLC`] messages even if the ephemeral
        /// public key (here) is bogus, so we hold a [`Result`] instead of a [`PublicKey`] as we'd
        /// like.
-       pub(crate) public_key: Result<PublicKey, secp256k1::Error>,
-       pub(crate) hop_data: [u8; 20*65],
-       pub(crate) hmac: [u8; 32],
+       pub public_key: Result<PublicKey, secp256k1::Error>,
+       /// 1300 bytes encrypted payload for the next hop.
+       pub hop_data: [u8; 20*65],
+       /// HMAC to verify the integrity of hop_data.
+       pub hmac: [u8; 32],
 }
 
 impl onion_utils::Packet for OnionPacket {
index 7f694565f325a8c73463d48d0deea4c23400a57c..e952bd8e2e125c5d8c16ef6f8419e1c8a2579ba0 100644 (file)
@@ -935,6 +935,27 @@ pub(crate) fn decode_next_payment_hop<NS: Deref>(
        }
 }
 
+/// Build a payment onion, returning the first hop msat and cltv values as well.
+/// `cur_block_height` should be set to the best known block height + 1.
+pub fn create_payment_onion<T: secp256k1::Signing>(
+       secp_ctx: &Secp256k1<T>, path: &Path, session_priv: &SecretKey, total_msat: u64,
+       recipient_onion: RecipientOnionFields, cur_block_height: u32, payment_hash: &PaymentHash,
+       keysend_preimage: &Option<PaymentPreimage>, prng_seed: [u8; 32]
+) -> Result<(msgs::OnionPacket, u64, u32), APIError> {
+       let onion_keys = construct_onion_keys(&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) = build_onion_payloads(
+               &path, total_msat, recipient_onion, cur_block_height, keysend_preimage
+       )?;
+       let onion_packet = 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()
+               })?;
+       Ok((onion_packet, htlc_msat, htlc_cltv))
+}
+
 pub(crate) fn decode_next_untagged_hop<T, R: ReadableArgs<T>, N: NextPacketBytes>(shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32], read_args: T) -> Result<(R, Option<([u8; 32], N)>), OnionDecodeErr> {
        decode_next_hop(shared_secret, hop_data, hmac_bytes, None, read_args)
 }
index addf7405d697130465e9156d77a3fc717b816528..87952a1bbdf50dc3af6d8f18b722dff15ccf7d13 100644 (file)
@@ -1940,7 +1940,7 @@ fn do_test_intercepted_payment(test: InterceptTest) {
                expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
        } else if test == InterceptTest::Forward {
                // Check that we'll fail as expected when sending to a channel that isn't in `ChannelReady` yet.
-               let temp_chan_id = nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               let temp_chan_id = nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let unusable_chan_err = nodes[1].node.forward_intercepted_htlc(intercept_id, &temp_chan_id, nodes[2].node.get_our_node_id(), expected_outbound_amount_msat).unwrap_err();
                assert_eq!(unusable_chan_err , APIError::ChannelUnavailable {
                        err: format!("Channel with id {} for the passed counterparty node_id {} is still opening.",
index d24554bac64e1fff17fcd83f335a1721f7612a57..85e757204fe5205c7534f614a71c1085535e25c5 100644 (file)
@@ -290,7 +290,7 @@ fn test_scid_privacy_on_pub_channel() {
        let mut scid_privacy_cfg = test_default_channel_config();
        scid_privacy_cfg.channel_handshake_config.announced_channel = true;
        scid_privacy_cfg.channel_handshake_config.negotiate_scid_privacy = true;
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(scid_privacy_cfg)).unwrap();
        let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        assert!(!open_channel.channel_type.as_ref().unwrap().supports_scid_privacy()); // we ignore `negotiate_scid_privacy` on pub channels
@@ -314,7 +314,7 @@ fn test_scid_privacy_negotiation() {
        let mut scid_privacy_cfg = test_default_channel_config();
        scid_privacy_cfg.channel_handshake_config.announced_channel = false;
        scid_privacy_cfg.channel_handshake_config.negotiate_scid_privacy = true;
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(scid_privacy_cfg)).unwrap();
 
        let init_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        assert!(init_open_channel.channel_type.as_ref().unwrap().supports_scid_privacy());
@@ -360,7 +360,7 @@ fn test_inbound_scid_privacy() {
        let mut no_announce_cfg = test_default_channel_config();
        no_announce_cfg.channel_handshake_config.announced_channel = false;
        no_announce_cfg.channel_handshake_config.negotiate_scid_privacy = true;
-       nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 100_000, 10_000, 42, Some(no_announce_cfg)).unwrap();
+       nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 100_000, 10_000, 42, None, Some(no_announce_cfg)).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[2].node.get_our_node_id());
 
        assert!(open_channel.channel_type.as_ref().unwrap().requires_scid_privacy());
@@ -591,7 +591,7 @@ fn test_0conf_channel_with_async_monitor() {
        create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0);
 
        chan_config.channel_handshake_config.announced_channel = false;
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(chan_config)).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(chan_config)).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
@@ -882,7 +882,7 @@ fn test_zero_conf_accept_reject() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        open_channel_msg.channel_type = Some(channel_type_features.clone());
@@ -909,7 +909,7 @@ fn test_zero_conf_accept_reject() {
 
        // 2.1 First try the non-0conf method to manually accept
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42,
-               Some(manually_accept_conf)).unwrap();
+               None, Some(manually_accept_conf)).unwrap();
        let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel,
                nodes[1].node.get_our_node_id());
 
@@ -941,7 +941,7 @@ fn test_zero_conf_accept_reject() {
 
        // 2.2 Try again with the 0conf method to manually accept
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42,
-               Some(manually_accept_conf)).unwrap();
+               None, Some(manually_accept_conf)).unwrap();
        let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel,
                nodes[1].node.get_our_node_id());
 
@@ -982,7 +982,7 @@ fn test_connect_before_funding() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_001, 42, None, None).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
index 079dea653e71120049b6b98c64cf16a98f7c8cfe..ade396fbebff5e1f899e51b26ad15af7aa3ff9cb 100644 (file)
@@ -247,7 +247,7 @@ fn test_manager_serialize_deserialize_events() {
        let push_msat = 10001;
        let node_a = nodes.remove(0);
        let node_b = nodes.remove(0);
-       node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap();
+       node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None, None).unwrap();
        node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), &get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id()));
        node_a.node.handle_accept_channel(&node_b.node.get_our_node_id(), &get_event_msg!(node_b, MessageSendEvent::SendAcceptChannel, node_a.node.get_our_node_id()));
 
index 0d02e89b8bbdcaaf01d1268eeba8523529f8fc0a..de57e5878ec7d8b43d7f079f1d491dfc72723435 100644 (file)
@@ -261,7 +261,7 @@ fn shutdown_on_unfunded_channel() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 100_000, 0, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 100_000, 0, None, None).unwrap();
        let open_chan = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
        // Create a dummy P2WPKH script
@@ -770,7 +770,7 @@ fn test_unsupported_anysegwit_upfront_shutdown_script() {
                .into_script();
 
        // Check script when handling an open_channel message
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        open_channel.shutdown_scriptpubkey = Some(anysegwit_shutdown_script.clone());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
@@ -793,7 +793,7 @@ fn test_unsupported_anysegwit_upfront_shutdown_script() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // Check script when handling an accept_channel message
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
        let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
@@ -820,7 +820,7 @@ fn test_invalid_upfront_shutdown_script() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, None).unwrap();
 
        // Use a segwit v0 script with an unsupported witness program
        let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
index c6fd5d056491560b5b3f630564fe97af93bea372..5bd5a95d8e627a3e69964db540fbffa554bbddf4 100644 (file)
@@ -439,6 +439,7 @@ impl UnsignedBolt12Invoice {
                        bytes: self.bytes,
                        contents: self.contents,
                        signature,
+                       tagged_hash: self.tagged_hash,
                })
        }
 }
@@ -463,6 +464,7 @@ pub struct Bolt12Invoice {
        bytes: Vec<u8>,
        contents: InvoiceContents,
        signature: Signature,
+       tagged_hash: TaggedHash,
 }
 
 /// The contents of an [`Bolt12Invoice`] for responding to either an [`Offer`] or a [`Refund`].
@@ -707,7 +709,7 @@ impl Bolt12Invoice {
 
        /// Hash that was used for signing the invoice.
        pub fn signable_hash(&self) -> [u8; 32] {
-               merkle::message_digest(SIGNATURE_TAG, &self.bytes).as_ref().clone()
+               self.tagged_hash.as_digest().as_ref().clone()
        }
 
        /// Verifies that the invoice was for a request or refund created using the given key. Returns
@@ -1212,11 +1214,11 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
                        None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
                        Some(signature) => signature,
                };
-               let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
+               let tagged_hash = TaggedHash::new(SIGNATURE_TAG, &bytes);
                let pubkey = contents.fields().signing_pubkey;
-               merkle::verify_signature(&signature, message, pubkey)?;
+               merkle::verify_signature(&signature, &tagged_hash, pubkey)?;
 
-               Ok(Bolt12Invoice { bytes, contents, signature })
+               Ok(Bolt12Invoice { bytes, contents, signature, tagged_hash })
        }
 }
 
@@ -1431,7 +1433,7 @@ mod tests {
                assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
 
                let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
-               assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
+               assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok());
 
                let digest = Message::from_slice(&invoice.signable_hash()).unwrap();
                let pubkey = recipient_pubkey().into();
@@ -1528,7 +1530,7 @@ mod tests {
                assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
 
                let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
-               assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
+               assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok());
 
                assert_eq!(
                        invoice.as_tlv_stream(),
index bd6d58371a9f316cccf6b362cc4825f27171f177..9ddd741a1d5428745e2bd1d840fa14eb4a1eee08 100644 (file)
@@ -876,7 +876,7 @@ impl TryFrom<Vec<u8>> for InvoiceRequest {
                        Some(signature) => signature,
                };
                let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
-               merkle::verify_signature(&signature, message, contents.payer_id)?;
+               merkle::verify_signature(&signature, &message, contents.payer_id)?;
 
                Ok(InvoiceRequest { bytes, contents, signature })
        }
@@ -1013,7 +1013,7 @@ mod tests {
                assert_eq!(invoice_request.payer_note(), None);
 
                let message = TaggedHash::new(SIGNATURE_TAG, &invoice_request.bytes);
-               assert!(merkle::verify_signature(&invoice_request.signature, message, payer_pubkey()).is_ok());
+               assert!(merkle::verify_signature(&invoice_request.signature, &message, payer_pubkey()).is_ok());
 
                assert_eq!(
                        invoice_request.as_tlv_stream(),
index 7390b58fef8ef780a68f58aa50438dcbe1979d71..7330541220f625240dee1db5e13539a73aaea824 100644 (file)
@@ -30,20 +30,41 @@ tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, {
 ///
 /// [BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
 /// [BOLT 12]: https://github.com/rustyrussell/lightning-rfc/blob/guilt/offers/12-offer-encoding.md#signature-calculation
-#[derive(Debug, PartialEq)]
-pub struct TaggedHash(Message);
+#[derive(Clone, Debug, PartialEq)]
+pub struct TaggedHash {
+       tag: &'static str,
+       merkle_root: sha256::Hash,
+       digest: Message,
+}
 
 impl TaggedHash {
        /// Creates a tagged hash with the given parameters.
        ///
        /// Panics if `tlv_stream` is not a well-formed TLV stream containing at least one TLV record.
-       pub(super) fn new(tag: &str, tlv_stream: &[u8]) -> Self {
-               Self(message_digest(tag, tlv_stream))
+       pub(super) fn new(tag: &'static str, tlv_stream: &[u8]) -> Self {
+               let tag_hash = sha256::Hash::hash(tag.as_bytes());
+               let merkle_root = root_hash(tlv_stream);
+               let digest = Message::from_slice(&tagged_hash(tag_hash, merkle_root)).unwrap();
+               Self {
+                       tag,
+                       merkle_root,
+                       digest,
+               }
        }
 
        /// Returns the digest to sign.
        pub fn as_digest(&self) -> &Message {
-               &self.0
+               &self.digest
+       }
+
+       /// Returns the tag used in the tagged hash.
+       pub fn tag(&self) -> &str {
+               &self.tag
+       }
+
+       /// Returns the merkle root used in the tagged hash.
+       pub fn merkle_root(&self) -> sha256::Hash {
+               self.merkle_root
        }
 }
 
@@ -91,7 +112,7 @@ where
 /// Verifies the signature with a pubkey over the given message using a tagged hash as the message
 /// digest.
 pub(super) fn verify_signature(
-       signature: &Signature, message: TaggedHash, pubkey: PublicKey,
+       signature: &Signature, message: &TaggedHash, pubkey: PublicKey,
 ) -> Result<(), secp256k1::Error> {
        let digest = message.as_digest();
        let pubkey = pubkey.into();
@@ -99,12 +120,6 @@ pub(super) fn verify_signature(
        secp_ctx.verify_schnorr(signature, digest, &pubkey)
 }
 
-pub(super) fn message_digest(tag: &str, bytes: &[u8]) -> Message {
-       let tag = sha256::Hash::hash(tag.as_bytes());
-       let merkle_root = root_hash(bytes);
-       Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap()
-}
-
 /// Computes a merkle root hash for the given data, which must be a well-formed TLV stream
 /// containing at least one TLV record.
 fn root_hash(data: &[u8]) -> sha256::Hash {
@@ -258,12 +273,13 @@ mod tests {
        use super::{SIGNATURE_TYPES, TlvStream, WithoutSignatures};
 
        use bitcoin::hashes::{Hash, sha256};
-       use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey};
+       use bitcoin::secp256k1::{KeyPair, Message, Secp256k1, SecretKey};
        use bitcoin::secp256k1::schnorr::Signature;
        use core::convert::Infallible;
        use crate::offers::offer::{Amount, OfferBuilder};
        use crate::offers::invoice_request::InvoiceRequest;
        use crate::offers::parse::Bech32Encode;
+       use crate::offers::test_utils::{payer_pubkey, recipient_pubkey};
        use crate::util::ser::Writeable;
 
        #[test]
@@ -322,6 +338,25 @@ mod tests {
                );
        }
 
+        #[test]
+        fn compute_tagged_hash() {
+                let unsigned_invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
+                        .amount_msats(1000)
+                        .build().unwrap()
+                        .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                        .payer_note("bar".into())
+                        .build().unwrap();
+
+                // Simply test that we can grab the tag and merkle root exposed by the accessor
+                // functions, then use them to succesfully compute a tagged hash.
+                let tagged_hash = unsigned_invoice_request.as_ref();
+                let expected_digest = unsigned_invoice_request.as_ref().as_digest();
+                let tag = sha256::Hash::hash(tagged_hash.tag().as_bytes());
+                let actual_digest = Message::from_slice(&super::tagged_hash(tag, tagged_hash.merkle_root()))
+                        .unwrap();
+                assert_eq!(*expected_digest, actual_digest);
+        }
+
        #[test]
        fn skips_encoding_signature_tlv_records() {
                let secp_ctx = Secp256k1::new();
index ff6e0cd8e5d59a44324838a9156bce79ae0ea45e..d106a542fd368156f0a4f7959c37919d8e1821ec 100644 (file)
@@ -28,6 +28,7 @@ mod functional_tests;
 
 // Re-export structs so they can be imported with just the `onion_message::` module prefix.
 pub use self::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, PeeledOnion, PendingOnionMessage, SendError};
+pub use self::messenger::{create_onion_message, peel_onion_message};
 #[cfg(not(c_bindings))]
 pub use self::messenger::{SimpleArcOnionMessenger, SimpleRefOnionMessenger};
 pub use self::offers::{OffersMessage, OffersMessageHandler};
index ef4111e4f82f744385fa345c610f5249b10b2d1a..13284113d2ca03469166bf959ba6607d66aaef4c 100644 (file)
@@ -462,8 +462,9 @@ pub struct ChannelConfig {
        /// - The counterparty will get an [`HTLCIntercepted`] event upon payment forward, and call
        ///   [`forward_intercepted_htlc`] with less than the amount provided in
        ///   [`HTLCIntercepted::expected_outbound_amount_msat`]. The difference between the expected and
-       ///   actual forward amounts is their fee.
-       // TODO: link to LSP JIT channel invoice generation spec when it's merged
+       ///   actual forward amounts is their fee. See
+       ///   <https://github.com/BitcoinAndLightningLayerSpecs/lsp/tree/main/LSPS2#flow-lsp-trusts-client-model>
+       ///   for how this feature may be used in the LSP use case.
        ///
        /// # Note
        /// It's important for payee wallet software to verify that [`PaymentClaimable::amount_msat`] is