Merge pull request #2439 from tnull/2023-05-fix-0conf-sigs-racing-confirms
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Fri, 21 Jul 2023 19:37:28 +0000 (19:37 +0000)
committerGitHub <noreply@github.com>
Fri, 21 Jul 2023 19:37:28 +0000 (19:37 +0000)
Avoid panic when 0conf channel's ann. sigs race on-chain confirmation

85 files changed:
.github/workflows/build.yml
CHANGELOG.md
Cargo.toml
ci/check-compiles.sh
ci/ci-tests.sh
fuzz/src/bech32_parse.rs
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
fuzz/src/invoice_deser.rs
fuzz/src/invoice_request_deser.rs
fuzz/src/offer_deser.rs
fuzz/src/refund_deser.rs
fuzz/src/router.rs
lightning-background-processor/Cargo.toml
lightning-background-processor/src/lib.rs
lightning-block-sync/Cargo.toml
lightning-custom-message/Cargo.toml
lightning-invoice/Cargo.toml
lightning-invoice/src/de.rs
lightning-invoice/src/lib.rs
lightning-invoice/src/payment.rs
lightning-invoice/src/ser.rs
lightning-invoice/src/utils.rs
lightning-invoice/tests/ser_de.rs
lightning-net-tokio/Cargo.toml
lightning-net-tokio/src/lib.rs
lightning-persister/Cargo.toml
lightning-rapid-gossip-sync/Cargo.toml
lightning-transaction-sync/Cargo.toml
lightning/Cargo.toml
lightning/src/chain/chaininterface.rs
lightning/src/chain/chainmonitor.rs
lightning/src/chain/channelmonitor.rs
lightning/src/chain/mod.rs
lightning/src/chain/onchaintx.rs
lightning/src/chain/package.rs
lightning/src/events/bump_transaction.rs
lightning/src/events/mod.rs
lightning/src/lib.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/chanmon_update_fail_tests.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/features.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/monitor_tests.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onion_route_tests.rs
lightning/src/ln/onion_utils.rs
lightning/src/ln/outbound_payment.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/peer_handler.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_error.rs
lightning/src/offers/invoice_request.rs
lightning/src/offers/offer.rs
lightning/src/offers/parse.rs
lightning/src/offers/refund.rs
lightning/src/offers/test_utils.rs
lightning/src/onion_message/messenger.rs
lightning/src/onion_message/mod.rs
lightning/src/onion_message/offers.rs
lightning/src/onion_message/packet.rs
lightning/src/routing/gossip.rs
lightning/src/routing/router.rs
lightning/src/routing/scoring.rs
lightning/src/sign/mod.rs
lightning/src/util/chacha20poly1305rfc.rs
lightning/src/util/config.rs
lightning/src/util/enforcing_trait_impls.rs
lightning/src/util/logger.rs
lightning/src/util/macro_logger.rs
lightning/src/util/mod.rs
lightning/src/util/ser.rs
lightning/src/util/ser_macros.rs
lightning/src/util/test_utils.rs
lightning/src/util/time.rs
msrv-no-dev-deps-check/Cargo.toml [new file with mode: 0644]
msrv-no-dev-deps-check/src/lib.rs [new file with mode: 0644]
pending_changelog/big-om-error.txt [deleted file]
pending_changelog/blinded_pay_param_compat.txt [deleted file]

index 3b6d1a0388c693e407419af903f295a57cd715b7..525dcbe5f068b6eeaa3e865ee614e029f4168430 100644 (file)
@@ -37,11 +37,9 @@ jobs:
       - name: Checkout source code
         uses: actions/checkout@v3
       - name: Install Rust ${{ matrix.toolchain }} toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: ${{ matrix.toolchain }}
-          override: true
-          profile: minimal
+        run: |
+          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }}
+          rustup override set ${{ matrix.toolchain }}
       - name: Install no-std-check dependencies for ARM Embedded
         if: "matrix.platform == 'ubuntu-latest'"
         run: |
@@ -101,11 +99,9 @@ jobs:
       - name: Checkout source code
         uses: actions/checkout@v3
       - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: ${{ env.TOOLCHAIN }}
-          override: true
-          profile: minimal
+        run: |
+          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ env.TOOLCHAIN }}
+          rustup override set ${{ env.TOOLCHAIN }}
       - name: Cache routing graph snapshot
         id: cache-graph
         uses: actions/cache@v3
@@ -151,18 +147,16 @@ jobs:
   check_commits:
     runs-on: ubuntu-latest
     env:
-      TOOLCHAIN: 1.57.0
+      TOOLCHAIN: stable
     steps:
       - name: Checkout source code
         uses: actions/checkout@v3
         with:
           fetch-depth: 0
       - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: ${{ env.TOOLCHAIN }}
-          override: true
-          profile: minimal
+        run: |
+          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ env.TOOLCHAIN }}
+          rustup override set ${{ env.TOOLCHAIN }}
       - name: Fetch full tree and rebase on upstream
         run: |
           git remote add upstream https://github.com/lightningdevkit/rust-lightning
@@ -183,18 +177,15 @@ jobs:
         with:
           fetch-depth: 0
       - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: ${{ env.TOOLCHAIN }}
-          override: true
-          profile: minimal
+        run: |
+          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ env.TOOLCHAIN }}
+          rustup override set ${{ env.TOOLCHAIN }}
       - name: Run cargo check for release build.
         run: |
           cargo check --release
           cargo check --no-default-features --features=no-std --release
           cargo check --no-default-features --features=futures --release
           cargo doc --release
-          RUSTDOCFLAGS="--cfg=anchors" cargo doc --release
       - name: Run cargo check for Taproot build.
         run: |
           cargo check --release
@@ -202,22 +193,20 @@ jobs:
           cargo check --no-default-features --features=futures --release
           cargo doc --release
         env:
-          RUSTFLAGS: '--cfg=anchors --cfg=taproot'
-          RUSTDOCFLAGS: '--cfg=anchors --cfg=taproot'
+          RUSTFLAGS: '--cfg=taproot'
+          RUSTDOCFLAGS: '--cfg=taproot'
 
   fuzz:
     runs-on: ubuntu-latest
     env:
-      TOOLCHAIN: stable
+      TOOLCHAIN: 1.58
     steps:
       - name: Checkout source code
         uses: actions/checkout@v3
-      - name: Install Rust 1.58 toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: 1.58
-          override: true
-          profile: minimal
+      - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
+        run: |
+          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ env.TOOLCHAIN }}
+          rustup override set ${{ env.TOOLCHAIN }}
       - name: Install dependencies for honggfuzz
         run: |
           sudo apt-get update
@@ -237,11 +226,9 @@ jobs:
       - name: Checkout source code
         uses: actions/checkout@v3
       - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: ${{ env.TOOLCHAIN }}
-          override: true
-          profile: minimal
+        run: |
+          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ env.TOOLCHAIN }}
+          rustup override set ${{ env.TOOLCHAIN }}
       - name: Install clippy
         run: |
           rustup component add clippy
index 2874f33db0cae3c5ada1da06cfeee31de93d9892..7243b520ba655a5087cd58dc1ae5781c3ad92a10 100644 (file)
@@ -1,3 +1,125 @@
+# 0.0.116rc1 - Jul 14, 2023 - "Anchoring the Roadmap"
+
+## API Updates
+
+ * Support for zero-HTLC-fee anchor output channels has been added and is now
+   considered beta (#2367). Users who set
+   `ChannelHandshakeConfig::negotiate_anchors_zero_fee_htlc_tx` should be
+   prepared to handle the new `Event::BumpTransaction`, e.g. via the
+   `BumpTransactionEventHandler` (#2089). Users who set the same and wish to
+   accept inbound anchor-based channels must do so manually by setting
+   `UserConfig::manually_accept_inbound_channels` (#2368).
+ * Support forwarding and accepting HTLCs with a reduced amount has been added,
+   to support LSPs skimming a fee on the penultimate hop (#2319).
+ * BOLT11 and BOLT12 Invoice and related types have been renamed to include a
+   BOLTNN prefix, ensuring uniqueness in `lightning{,-invoice}` crates (#2416).
+ * `Score`rs now have an associated type which represents a parameter passed
+   when calculating penalties. This allows for the same `Score`r to be used with
+   different penalty calculation parameters (#2237).
+ * `DefaultRouter` is no longer restrained to a `Mutex`-wrapped `Score`,
+   allowing it to be used in `no-std` builds (#2383).
+ * `CustomMessageHandler::provided_{node,init}_features` and various custom
+   feature bit methods on `*Features` were added (#2204).
+ * Keysend/push payments using MPP are now supported when receiving if
+   `UserConfig::accept_mpp_keysend` is set and when sending if specified in the
+   `PaymentParameters`. Note that not all recipients support this (#2156).
+ * A new `ConfirmationTarget::MempoolMinimum` has been added (#2415).
+ * `SpendableOutputDescriptor::to_psbt_input` was added (#2286).
+ * `ChannelManager::update_partial_channel_config` was added (#2330).
+ * `ChannelDetails::channel_shutdown_state` was added (#2347).
+ * The shutdown script can now be provided at shutdown time via
+   `ChannelManager::close_channel_with_feerate_and_script` (#2219).
+ * `BroadcasterInterface` now takes multiple transactions at once. While not
+   available today, in the future single calls should be passed to a full node
+   via a single batch/package transaction acceptance API (#2272).
+ * `Balance::claimable_amount_satoshis` was added (#2333).
+ * `payment_{hash,preimage}` have been added to some `Balance` variants (#2217).
+ * The `lightning::chain::keysinterface` is now `lightning::sign` (#2246).
+ * Routing to a blinded path has been implemented, though sending to such a
+   route is not yet supported in `ChannelManager` (#2120).
+ * `OffersMessageHandler` was added for offers-related onion messages (#2294).
+ * The `CustomMessageHandler` parameter to `PeerManager` has moved to
+   `MessageHandler` from `PeerManager::new` explicitly (#2249).
+ * Various P2P messages for dual funding channel establishment have been added,
+   though handling for them is not yet in `ChannelManager` (#1794)
+ * Script-fetching methods in `sign` interfaces can now return errors, see docs
+   for the implications of failing (#2213).
+ * The `data_loss_protect` option is now required when reading
+   `channel_reestablish` messages, as many others have done (#2253).
+ * `InFlightHtlcs::add_inflight_htlc` has been added (#2042).
+ * The `init` message `networks` field is now written and checked (#2329).
+ * `PeerManager` generics have been simplified with the introduction of the
+   `APeerManager` trait (#2249).
+ * `ParitalOrd` and `Ord` are now implemented for `Invoice` (#2279).
+ * `ParitalEq` and `Debug` are now implemented for `InMemorySigner` (#2328).
+ * `ParitalEq` and `Eq` are now implemented for `PaymentError` (#2316).
+ * `NetworkGraph::update_channel_from_announcement_no_lookup` was added (#2222).
+ * `lightning::routing::gossip::verify_{channel,node}_announcement` was added
+   (#2307).
+
+## Backwards Compatibility
+ * `PaymentParameters` written with blinded path info using LDK 0.0.115 will not
+   be readable in LDK 0.0.116, and vice versa.
+ * Forwarding less than `Event::HTLCIntercepted::expected_outbound_amount_msat`
+   in `ChannelManager::forward_intercepted_htlc` may prevent the
+   `ChannelManager` from being read by LDK prior to 0.0.116 (#2319)
+ * Setting `ChannelConfig::accept_underpaying_htlcs` may prevent the
+   `ChannelManager` from being read by LDK prior to 0.0.116 and un-setting the
+   parameter between restarts may lead to payment failures (#2319).
+ * `ChannelManager::create_inbound_payment{,_for_hash}_legacy` has been removed,
+   removing the ability to create inbound payments which are claimable after
+   downgrade to LDK 0.0.103 and prior. In the future handling such payments will
+   also be removed (#2351).
+ * Some fields required by LDK 0.0.103 and earlier are no longer written, thus
+   deserializing objects written by 0.0.116 with 0.0.103 may now fail (#2351).
+
+## Bug Fixes
+ * `ChannelDetails::next_outbound_htlc_limit_msat` was made substantially more
+   accurate and a corresponding `next_outbound_htlc_minimum_msat` was added.
+   This resolves issues where unpayable routes were generated due to
+   overestimation of the amount which is payable over one of our channels as
+   the first hop (#2312).
+ * A rare case where delays in processing `Event`s generated by
+   `ChannelMonitor`s could lead to loss of those events in case of an untimely
+   crash. This could lead to the loss of an `Event::SpendableOutputs` (#2369).
+ * Fixed a regression in 0.0.115 which caused `PendingHTLCsForwardable` events
+   to be missed when processing phantom node receives. This caused such
+   payments to be delayed until a further, unrelated HTLC came in (#2395).
+ * Peers which are unresponsive to channel messages for several timer ticks are
+   now disconnected to allow for on-reconnection state machine reset. This
+   works around some issues in LND prior to 16.3 which can cause channels to
+   hang and eventually force-close (#2293).
+ * `ChannelManager::new` now requires the current time (either from a recent
+   block header or the system clock), ensuring invoices created immediately
+   after startup aren't already expired (#2372).
+ * Resolved an issue where reading a `ProbabilisticScorer` on some platforms
+   (e.g. iOS) can lead to a panic (#2322).
+ * `ChannelConfig::max_dust_htlc_exposure` is now allowed to scale based on
+   current fees, and the default has been updated to do so. This substantially
+   reduces the chance of force-closure due to dust exposure. Note that existing
+   channels will retain their current value and you may wish to update the
+   value on your existing channels on upgrade (#2354).
+ * `PeerManager::process_events` no longer blocks in any case. This fixes a bug
+   where reentrancy from `PeerManager` into user code which eventually calls
+   `process_events` could lead to a deadlock (#2280).
+ * The persist timing of network graph and scoring in
+   `lightning-background-processor` has been tweaked to provide more reliable
+   persistence after updates to either (#2226).
+ * The number of route hints added to BOLT 11 invoices by the
+   `lightning-invoice::utils` builders has been reduced to three to ensure
+   invoices can be represented in scan-able QR codes (#2044).
+ * Fixed sending large onion messages, which would previously have resulted in
+   an HMAC error on the second hop (#2277).
+ * Fixed a memory leak that may occur when a `ChannelManager` or
+   `ChannelMonitor` is `drop`ed (#2233).
+ * A potential deadlock in calling `NetworkGraph::eq` was resolved (#2284).
+ * Fixed an overflow which prevented disconnecting peers in some minor cases
+   with more than 31 peers (#2245).
+ * Gossip messages with an unknown chain hash are now ignored (#2230).
+ * Rapid Gossip Sync processing now fails on an unknown chain hash (#2324).
+ * `RouteHintHop::htlc_maximum_msat` is now enforced. Note that BOLT11 route
+   hints do not have such a field so this code is generally unused (#2305).
+
 # 0.0.115 - Apr 24, 2023 - "Rebroadcast the Bugfixes"
 
 ## API Updates
index a3acccfdaea91614b98421590dd567d1a678ef58..8614cb48c1f15207023d9fd00b952600804d4e1b 100644 (file)
@@ -14,6 +14,7 @@ exclude = [
     "lightning-custom-message",
     "lightning-transaction-sync",
     "no-std-check",
+    "msrv-no-dev-deps-check",
     "bench",
 ]
 
index 193c2b4ef1fee74d6dbbdfdaee2c09bb86cc9197..af88bceee01127667377c294c69429ae0c2e4630 100755 (executable)
@@ -7,3 +7,4 @@ cargo doc
 cargo doc --document-private-items
 cd fuzz && RUSTFLAGS="--cfg=fuzzing" cargo check --features=stdin_fuzz
 cd ../lightning && cargo check --no-default-features --features=no-std
+cd .. && RUSTC_BOOTSTRAP=1 RUSTFLAGS="--cfg=c_bindings" cargo check -Z avoid-dev-deps
index 69bf7dd2e149d269b8c1a38263ef63dd78fa68c8..7a16b749200de77219c7268eb79fe793fe0d1bfb 100755 (executable)
@@ -4,12 +4,33 @@ set -eox pipefail
 RUSTC_MINOR_VERSION=$(rustc --version | awk '{ split($2,a,"."); print a[2] }')
 HOST_PLATFORM="$(rustc --version --verbose | grep "host:" | awk '{ print $2 }')"
 
-# Tokio MSRV on versions 1.17 through 1.26 is rustc 1.49. Above 1.26 MSRV is 1.56.
-[ "$RUSTC_MINOR_VERSION" -lt 49 ] && cargo update -p tokio --precise "1.14.1" --verbose
-[[ "$RUSTC_MINOR_VERSION" -gt 48  &&  "$RUSTC_MINOR_VERSION" -lt 56 ]] && cargo update -p tokio --precise "1.25.1" --verbose
+# Some crates require pinning to meet our MSRV even for our downstream users,
+# which we do here.
+# Further crates which appear only as dev-dependencies are pinned further down.
+function PIN_RELEASE_DEPS {
+       # Tokio MSRV on versions 1.17 through 1.26 is rustc 1.49. Above 1.26 MSRV is 1.56.
+       [ "$RUSTC_MINOR_VERSION" -lt 49 ] && cargo update -p tokio --precise "1.14.1" --verbose
+       [[ "$RUSTC_MINOR_VERSION" -gt 48  &&  "$RUSTC_MINOR_VERSION" -lt 56 ]] && cargo update -p tokio --precise "1.25.1" --verbose
 
-# Sadly the log crate is always a dependency of tokio until 1.20, and has no reasonable MSRV guarantees
-[ "$RUSTC_MINOR_VERSION" -lt 49 ] && cargo update -p log --precise "0.4.18" --verbose
+       # Sadly the log crate is always a dependency of tokio until 1.20, and has no reasonable MSRV guarantees
+       [ "$RUSTC_MINOR_VERSION" -lt 49 ] && cargo update -p log --precise "0.4.18" --verbose
+
+       # The serde_json crate switched to Rust edition 2021 starting with v1.0.101, i.e., has MSRV of 1.56
+       [ "$RUSTC_MINOR_VERSION" -lt 56 ] && cargo update -p serde_json --precise "1.0.100" --verbose
+
+       return 0 # Don't fail the script if our rustc is higher than the last check
+}
+
+PIN_RELEASE_DEPS # pin the release dependencies in our main workspace
+
+# The addr2line v0.20 crate (a dependency of `backtrace` starting with 0.3.68) relies on 1.55+
+[ "$RUSTC_MINOR_VERSION" -lt 55 ] && cargo update -p backtrace --precise "0.3.67" --verbose
+
+# The quote crate switched to Rust edition 2021 starting with v1.0.31, i.e., has MSRV of 1.56
+[ "$RUSTC_MINOR_VERSION" -lt 56 ] && cargo update -p quote --precise "1.0.30" --verbose
+
+# The proc-macro2 crate switched to Rust edition 2021 starting with v1.0.66, i.e., has MSRV of 1.56
+[ "$RUSTC_MINOR_VERSION" -lt 56 ] && cargo update -p proc-macro2 --precise "1.0.65" --verbose
 
 [ "$LDK_COVERAGE_BUILD" != "" ] && export RUSTFLAGS="-C link-dead-code"
 
@@ -56,7 +77,18 @@ popd
 echo -e "\n\nTesting no-std build on a downstream no-std crate"
 # check no-std compatibility across dependencies
 pushd no-std-check
-cargo check --verbose --color always --features lightning-transaction-sync
+if [[ $RUSTC_MINOR_VERSION -gt 67 ]]; then
+       # lightning-transaction-sync's MSRV is 1.67
+       cargo check --verbose --color always --features lightning-transaction-sync
+else
+       cargo check --verbose --color always
+fi
+popd
+
+# Test that we can build downstream code with only the "release pins".
+pushd msrv-no-dev-deps-check
+PIN_RELEASE_DEPS
+cargo check
 popd
 
 if [ -f "$(which arm-none-eabi-gcc)" ]; then
@@ -101,9 +133,7 @@ if [ "$RUSTC_MINOR_VERSION" -gt 55 ]; then
        popd
 fi
 
-echo -e "\n\nTest anchors builds"
-pushd lightning
-RUSTFLAGS="$RUSTFLAGS --cfg=anchors" cargo test --verbose --color always -p lightning
 echo -e "\n\nTest Taproot builds"
-RUSTFLAGS="$RUSTFLAGS --cfg=anchors --cfg=taproot" cargo test --verbose --color always -p lightning
+pushd lightning
+RUSTFLAGS="$RUSTFLAGS --cfg=taproot" cargo test --verbose --color always -p lightning
 popd
index f3dd5ac9d1e8f27264d548032ed12531c7314dbd..ff465ceea3948fd4d97ea2d18eb9ba49940f0c73 100644 (file)
@@ -9,7 +9,7 @@
 
 use crate::utils::test_logger;
 use core::convert::TryFrom;
-use lightning::offers::parse::{Bech32Encode, ParseError};
+use lightning::offers::parse::{Bech32Encode, Bolt12ParseError};
 
 #[inline]
 pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
@@ -35,8 +35,8 @@ impl AsRef<[u8]> for Bytes {
 }
 
 impl TryFrom<Vec<u8>> for Bytes {
-       type Error = ParseError;
-       fn try_from(data: Vec<u8>) -> Result<Self, ParseError> {
+       type Error = Bolt12ParseError;
+       fn try_from(data: Vec<u8>) -> Result<Self, Bolt12ParseError> {
                Ok(Bytes(data))
        }
 }
index 309faaa95522f0773080cd9a82bd0aa822f6165b..e923ef882f26ce643aa7c9478f15ecc648c931d8 100644 (file)
@@ -78,7 +78,7 @@ impl FeeEstimator for FuzzEstimator {
                // Background feerate which is <= the minimum Normal feerate.
                match conf_target {
                        ConfirmationTarget::HighPriority => MAX_FEE,
-                       ConfirmationTarget::Background => 253,
+                       ConfirmationTarget::Background|ConfirmationTarget::MempoolMinimum => 253,
                        ConfirmationTarget::Normal => cmp::min(self.ret_val.load(atomic::Ordering::Acquire), MAX_FEE),
                }
        }
@@ -89,7 +89,7 @@ struct FuzzRouter {}
 impl Router for FuzzRouter {
        fn find_route(
                &self, _payer: &PublicKey, _params: &RouteParameters, _first_hops: Option<&[&ChannelDetails]>,
-               _inflight_htlcs: &InFlightHtlcs
+               _inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, msgs::LightningError> {
                Err(msgs::LightningError {
                        err: String::from("Not implemented"),
@@ -436,11 +436,12 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
                        config.channel_config.forwarding_fee_proportional_millionths = 0;
                        config.channel_handshake_config.announced_channel = true;
                        let network = Network::Bitcoin;
+                       let best_block_timestamp = genesis_block(network).header.time;
                        let params = ChainParameters {
                                network,
                                best_block: BestBlock::from_network(network),
                        };
-                       (ChannelManager::new($fee_estimator.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params),
+                       (ChannelManager::new($fee_estimator.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params, best_block_timestamp),
                        monitor, keys_manager)
                } }
        }
index 1192766bf3e0baadb5c61fef3c0c07dbff0f56f3..1fbd7dbec8834b9e9dee38f1c19ff02e770f79d1 100644 (file)
@@ -43,7 +43,7 @@ use lightning::ln::functional_test_utils::*;
 use lightning::routing::gossip::{P2PGossipSync, NetworkGraph};
 use lightning::routing::utxo::UtxoLookup;
 use lightning::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router};
-use lightning::util::config::UserConfig;
+use lightning::util::config::{UserConfig, MaxDustHTLCExposure};
 use lightning::util::errors::APIError;
 use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
 use lightning::util::logger::Logger;
@@ -131,7 +131,7 @@ struct FuzzRouter {}
 impl Router for FuzzRouter {
        fn find_route(
                &self, _payer: &PublicKey, _params: &RouteParameters, _first_hops: Option<&[&ChannelDetails]>,
-               _inflight_htlcs: &InFlightHtlcs
+               _inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, msgs::LightningError> {
                Err(msgs::LightningError {
                        err: String::from("Not implemented"),
@@ -439,13 +439,15 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
        });
        let mut config = UserConfig::default();
        config.channel_config.forwarding_fee_proportional_millionths =  slice_to_be32(get_slice!(4));
+       config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253);
        config.channel_handshake_config.announced_channel = get_slice!(1)[0] != 0;
        let network = Network::Bitcoin;
+       let best_block_timestamp = genesis_block(network).header.time;
        let params = ChainParameters {
                network,
                best_block: BestBlock::from_network(network),
        };
-       let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params));
+       let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params, best_block_timestamp));
        // Adding new calls to `EntropySource::get_secure_random_bytes` during startup can change all the
        // keys subsequently generated in this test. Rather than regenerating all the messages manually,
        // it's easier to just increment the counter here so the keys don't change.
@@ -816,6 +818,8 @@ mod tests {
                //
                // 0a - create the funding transaction (client should send funding_created now)
                //
+               // 00fd00fd - Two feerate requests (calculating max dust exposure) (all returning min feerate) (gonna be ingested by FuzzEstimator)
+               //
                // 030112 - inbound read from peer id 1 of len 18
                // 0062 01000000000000000000000000000000 - message header indicating message length 98
                // 030172 - inbound read from peer id 1 of len 114
@@ -844,6 +848,8 @@ mod tests {
                // 0300c1 - inbound read from peer id 0 of len 193
                // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ab00000000000000000000000000000000000000000000000000000000000000 03000000000000000000000000000000 - end of update_add_htlc from 0 to 1 via client and mac
                //
+               // 00fd - One feerate request (calculating max dust exposure) (all returning min feerate) (gonna be ingested by FuzzEstimator)
+               //
                // 030012 - inbound read from peer id 0 of len 18
                // 0064 03000000000000000000000000000000 - message header indicating message length 100
                // 030074 - inbound read from peer id 0 of len 116
@@ -858,6 +864,8 @@ mod tests {
                // 07 - process the now-pending HTLC forward
                // - client now sends id 1 update_add_htlc and commitment_signed (CHECK 7: UpdateHTLCs event for node 03020000 with 1 HTLCs for channel 3f000000)
                //
+               // 00fd00fd - Two feerate requests (calculating max dust exposure) (all returning min feerate) (gonna be ingested by FuzzEstimator)
+               //
                // - we respond with commitment_signed then revoke_and_ack (a weird, but valid, order)
                // 030112 - inbound read from peer id 1 of len 18
                // 0064 01000000000000000000000000000000 - message header indicating message length 100
@@ -901,6 +909,8 @@ mod tests {
                // 0300c1 - inbound read from peer id 0 of len 193
                // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ab00000000000000000000000000000000000000000000000000000000000000 03000000000000000000000000000000 - end of update_add_htlc from 0 to 1 via client and mac
                //
+               // 00fd - One feerate request (calculating max dust exposure) (all returning min feerate) (gonna be ingested by FuzzEstimator)
+               //
                // - now respond to the update_fulfill_htlc+commitment_signed messages the client sent to peer 0
                // 030012 - inbound read from peer id 0 of len 18
                // 0063 03000000000000000000000000000000 - message header indicating message length 99
@@ -922,6 +932,8 @@ mod tests {
                // - client now sends id 1 update_add_htlc and commitment_signed (CHECK 7 duplicate)
                // - we respond with revoke_and_ack, then commitment_signed, then update_fail_htlc
                //
+               // 00fd00fd - Two feerate requests (calculating max dust exposure) (all returning min feerate) (gonna be ingested by FuzzEstimator)
+               //
                // 030112 - inbound read from peer id 1 of len 18
                // 0064 01000000000000000000000000000000 - message header indicating message length 100
                // 030174 - inbound read from peer id 1 of len 116
@@ -977,6 +989,8 @@ mod tests {
                // 0300c1 - inbound read from peer id 0 of len 193
                // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 5300000000000000000000000000000000000000000000000000000000000000 03000000000000000000000000000000 - end of update_add_htlc from 0 to 1 via client and mac
                //
+               // 00fd - One feerate request (calculating max dust exposure) (all returning min feerate) (gonna be ingested by FuzzEstimator)
+               //
                // 030012 - inbound read from peer id 0 of len 18
                // 00a4 03000000000000000000000000000000 - message header indicating message length 164
                // 0300b4 - inbound read from peer id 0 of len 180
@@ -991,6 +1005,8 @@ mod tests {
                // 07 - process the now-pending HTLC forward
                // - client now sends id 1 update_add_htlc and commitment_signed (CHECK 7 duplicate)
                //
+               // 00fd00fd - Two feerate requests (calculating max dust exposure) (all returning min feerate) (gonna be ingested by FuzzEstimator)
+               //
                // 0c007d - connect a block with one transaction of len 125
                // 02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c0000000000000160014280000000000000000000000000000000000000005000020 - the commitment transaction for channel 3f00000000000000000000000000000000000000000000000000000000000000
                //
@@ -1006,7 +1022,7 @@ mod tests {
                // - client now fails the HTLC backwards as it was unable to extract the payment preimage (CHECK 9 duplicate and CHECK 10)
 
                let logger = Arc::new(TrackingLogger { lines: Mutex::new(HashMap::new()) });
-               super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012001003000000000000000000000000000000030020001000021aaa0008aaaaaaaaaaaa9aaa030000000000000000000000000000000300120147030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000162ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030059030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010000010210000300000000000000000000000000000000fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112001001000000000000000000000000000000030120001000021aaa0008aaaaaaaaaaaa9aaa01000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120112010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000016200000000004c4b4000000000000003e800000000000003e80000000203f000050300000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000002000300000000000000000000000000000000000000000000000000000000000003000300000000000000000000000000000000000000000000000000000000000004000300000000000000000000000000000000000000000000000000000000000005000266000000000000000000000000000003012300000000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005551202030927c00401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff53000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c00000000000001600142800000000000000000000000000000000000000050000200c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc<dyn Logger>));
+               super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012001003000000000000000000000000000000030020001000021aaa0008aaaaaaaaaaaa9aaa030000000000000000000000000000000300120147030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000162ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030059030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010000010210000300000000000000000000000000000000fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112001001000000000000000000000000000000030120001000021aaa0008aaaaaaaaaaaa9aaa01000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120112010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000016200000000004c4b4000000000000003e800000000000003e80000000203f000050300000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000002000300000000000000000000000000000000000000000000000000000000000003000300000000000000000000000000000000000000000000000000000000000004000300000000000000000000000000000000000000000000000000000000000005000266000000000000000000000000000003012300000000000000000000000000000000000000010000000000000000000000000000000a00fd00fd03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000700fd00fd03011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000700fd00fd03011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005551202030927c00401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff53000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000700fd00fd0c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c00000000000001600142800000000000000000000000000000000000000050000200c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc<dyn Logger>));
 
                let log_entries = logger.lines.lock().unwrap();
                assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1
index 7b93fd38db1a37ce4a32410f79266b50ef75dc1a..34bb955e2a7c0652826f573f29a5487f63f65e94 100644 (file)
@@ -8,13 +8,13 @@
 // licenses.
 
 use crate::utils::test_logger;
-use lightning::offers::invoice::Invoice;
+use lightning::offers::invoice::Bolt12Invoice;
 use lightning::util::ser::Writeable;
 use std::convert::TryFrom;
 
 #[inline]
 pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
-       if let Ok(invoice) = Invoice::try_from(data.to_vec()) {
+       if let Ok(invoice) = Bolt12Invoice::try_from(data.to_vec()) {
                let mut bytes = Vec::with_capacity(data.len());
                invoice.write(&mut bytes).unwrap();
                assert_eq!(data, bytes);
index 394d57fcebc04c79d76a3894fda2ea7a8e5308e3..ca9d06ab1f8612d3f6c5bf212c191d27c0cb9cc6 100644 (file)
@@ -14,9 +14,9 @@ use lightning::blinded_path::BlindedPath;
 use lightning::sign::EntropySource;
 use lightning::ln::PaymentHash;
 use lightning::ln::features::BlindedHopFeatures;
-use lightning::offers::invoice::{BlindedPayInfo, UnsignedInvoice};
+use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
 use lightning::offers::invoice_request::InvoiceRequest;
-use lightning::offers::parse::SemanticError;
+use lightning::offers::parse::Bolt12SemanticError;
 use lightning::util::ser::Writeable;
 
 #[inline]
@@ -71,7 +71,7 @@ fn privkey(byte: u8) -> SecretKey {
 
 fn build_response<'a, T: secp256k1::Signing + secp256k1::Verification>(
        invoice_request: &'a InvoiceRequest, secp_ctx: &Secp256k1<T>
-) -> Result<UnsignedInvoice<'a>, SemanticError> {
+) -> Result<UnsignedBolt12Invoice<'a>, Bolt12SemanticError> {
        let entropy_source = Randomness {};
        let paths = vec![
                BlindedPath::new_for_message(&[pubkey(43), pubkey(44), pubkey(42)], &entropy_source, secp_ctx).unwrap(),
@@ -97,7 +97,7 @@ fn build_response<'a, T: secp256k1::Signing + secp256k1::Verification>(
                },
        ];
 
-       let payment_paths = paths.into_iter().zip(payinfo.into_iter()).collect();
+       let payment_paths = payinfo.into_iter().zip(paths.into_iter()).collect();
        let payment_hash = PaymentHash([42; 32]);
        invoice_request.respond_with(payment_paths, payment_hash)?.build()
 }
index 213742d8c085b86aba02f0188df4b0d6e08240e3..53f67a3380db07d322f8b1fe1c72a75301e34cc0 100644 (file)
@@ -12,7 +12,7 @@ use crate::utils::test_logger;
 use core::convert::{Infallible, TryFrom};
 use lightning::offers::invoice_request::UnsignedInvoiceRequest;
 use lightning::offers::offer::{Amount, Offer, Quantity};
-use lightning::offers::parse::SemanticError;
+use lightning::offers::parse::Bolt12SemanticError;
 use lightning::util::ser::Writeable;
 
 #[inline]
@@ -41,13 +41,13 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
 
 fn build_response<'a>(
        offer: &'a Offer, pubkey: PublicKey
-) -> Result<UnsignedInvoiceRequest<'a>, SemanticError> {
+) -> Result<UnsignedInvoiceRequest<'a>, Bolt12SemanticError> {
        let mut builder = offer.request_invoice(vec![42; 64], pubkey)?;
 
        builder = match offer.amount() {
                None => builder.amount_msats(1000).unwrap(),
                Some(Amount::Bitcoin { amount_msats }) => builder.amount_msats(amount_msats + 1)?,
-               Some(Amount::Currency { .. }) => return Err(SemanticError::UnsupportedCurrency),
+               Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
        };
 
        builder = match offer.supported_quantity() {
index 359bbcc739dcc8567b4bc3adb4f05f72679dde52..81b614d602b269259a9ce67fadbc86307c583334 100644 (file)
@@ -14,8 +14,8 @@ use lightning::blinded_path::BlindedPath;
 use lightning::sign::EntropySource;
 use lightning::ln::PaymentHash;
 use lightning::ln::features::BlindedHopFeatures;
-use lightning::offers::invoice::{BlindedPayInfo, UnsignedInvoice};
-use lightning::offers::parse::SemanticError;
+use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
+use lightning::offers::parse::Bolt12SemanticError;
 use lightning::offers::refund::Refund;
 use lightning::util::ser::Writeable;
 
@@ -60,7 +60,7 @@ fn privkey(byte: u8) -> SecretKey {
 
 fn build_response<'a, T: secp256k1::Signing + secp256k1::Verification>(
        refund: &'a Refund, signing_pubkey: PublicKey, secp_ctx: &Secp256k1<T>
-) -> Result<UnsignedInvoice<'a>, SemanticError> {
+) -> Result<UnsignedBolt12Invoice<'a>, Bolt12SemanticError> {
        let entropy_source = Randomness {};
        let paths = vec![
                BlindedPath::new_for_message(&[pubkey(43), pubkey(44), pubkey(42)], &entropy_source, secp_ctx).unwrap(),
@@ -86,7 +86,7 @@ fn build_response<'a, T: secp256k1::Signing + secp256k1::Verification>(
                },
        ];
 
-       let payment_paths = paths.into_iter().zip(payinfo.into_iter()).collect();
+       let payment_paths = payinfo.into_iter().zip(paths.into_iter()).collect();
        let payment_hash = PaymentHash([42; 32]);
        refund.respond_with(payment_paths, payment_hash, signing_pubkey)?.build()
 }
index 72935f153eab861f00509c310f88d5d822ea10fd..31732257c3f1a1c099161c8b982f1f5f35d701b2 100644 (file)
@@ -270,6 +270,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                                inbound_htlc_maximum_msat: None,
                                                                config: None,
                                                                feerate_sat_per_1000_weight: None,
+                                                               channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
                                                        });
                                                }
                                                Some(&first_hops_vec[..])
index 1f6509e6910d5451531ca31804769b0a2b3a2249..7b746307012d08dad277a01083fef248a61db51d 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-background-processor"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Valentine Wallace <vwallace@protonmail.com>"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -21,11 +21,11 @@ default = ["std"]
 
 [dependencies]
 bitcoin = { version = "0.29.0", default-features = false }
-lightning = { version = "0.0.115", path = "../lightning", default-features = false }
-lightning-rapid-gossip-sync = { version = "0.0.115", path = "../lightning-rapid-gossip-sync", default-features = false }
+lightning = { version = "0.0.116-rc1", path = "../lightning", default-features = false }
+lightning-rapid-gossip-sync = { version = "0.0.116-rc1", path = "../lightning-rapid-gossip-sync", default-features = false }
 
 [dev-dependencies]
 tokio = { version = "1.14", features = [ "macros", "rt", "rt-multi-thread", "sync", "time" ] }
-lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] }
-lightning-invoice = { version = "0.23.0", path = "../lightning-invoice" }
-lightning-persister = { version = "0.0.115", path = "../lightning-persister" }
+lightning = { version = "0.0.116-rc1", path = "../lightning", features = ["_test_utils"] }
+lightning-invoice = { version = "0.24.0-rc1", path = "../lightning-invoice" }
+lightning-persister = { version = "0.0.116-rc1", path = "../lightning-persister" }
index 0cfa9801badb3a8d31a30cbdce81b93cbaab1f5a..1ed6a2a8345bf8751ad6389e8c306804bedf1e91 100644 (file)
@@ -519,9 +519,8 @@ use core::task;
 /// # type MyUtxoLookup = dyn lightning::routing::utxo::UtxoLookup + Send + Sync;
 /// # type MyFilter = dyn lightning::chain::Filter + Send + Sync;
 /// # type MyLogger = dyn lightning::util::logger::Logger + Send + Sync;
-/// # type MyMessageRouter = dyn lightning::onion_message::MessageRouter + Send + Sync;
 /// # type MyChainMonitor = lightning::chain::chainmonitor::ChainMonitor<lightning::sign::InMemorySigner, Arc<MyFilter>, Arc<MyBroadcaster>, Arc<MyFeeEstimator>, Arc<MyLogger>, Arc<MyPersister>>;
-/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager<MySocketDescriptor, MyChainMonitor, MyBroadcaster, MyFeeEstimator, MyUtxoLookup, MyLogger, MyMessageRouter>;
+/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager<MySocketDescriptor, MyChainMonitor, MyBroadcaster, MyFeeEstimator, MyUtxoLookup, MyLogger>;
 /// # type MyNetworkGraph = lightning::routing::gossip::NetworkGraph<Arc<MyLogger>>;
 /// # type MyGossipSync = lightning::routing::gossip::P2PGossipSync<Arc<MyNetworkGraph>, Arc<MyUtxoLookup>, Arc<MyLogger>>;
 /// # type MyChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager<MyChainMonitor, MyBroadcaster, MyFeeEstimator, MyLogger>;
@@ -886,7 +885,22 @@ mod tests {
                fn disconnect_socket(&mut self) {}
        }
 
-       type ChannelManager = channelmanager::ChannelManager<Arc<ChainMonitor>, Arc<test_utils::TestBroadcaster>, Arc<KeysManager>, Arc<KeysManager>, Arc<KeysManager>, Arc<test_utils::TestFeeEstimator>, Arc<DefaultRouter<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestLogger>, Arc<Mutex<TestScorer>>, (), TestScorer>>, Arc<test_utils::TestLogger>>;
+       type ChannelManager =
+               channelmanager::ChannelManager<
+                       Arc<ChainMonitor>,
+                       Arc<test_utils::TestBroadcaster>,
+                       Arc<KeysManager>,
+                       Arc<KeysManager>,
+                       Arc<KeysManager>,
+                       Arc<test_utils::TestFeeEstimator>,
+                       Arc<DefaultRouter<
+                               Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
+                               Arc<test_utils::TestLogger>,
+                               Arc<Mutex<TestScorer>>,
+                               (),
+                               TestScorer>
+                       >,
+                       Arc<test_utils::TestLogger>>;
 
        type ChainMonitor = chainmonitor::ChainMonitor<InMemorySigner, Arc<test_utils::TestChainSource>, Arc<test_utils::TestBroadcaster>, Arc<test_utils::TestFeeEstimator>, Arc<test_utils::TestLogger>, Arc<FilesystemPersister>>;
 
@@ -1143,7 +1157,7 @@ mod tests {
                        let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new(Some(chain_source.clone()), tx_broadcaster.clone(), logger.clone(), fee_estimator.clone(), persister.clone()));
                        let best_block = BestBlock::from_network(network);
                        let params = ChainParameters { network, best_block };
-                       let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster.clone(), router.clone(), logger.clone(), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), UserConfig::default(), params));
+                       let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster.clone(), router.clone(), logger.clone(), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), UserConfig::default(), params, genesis_block.header.time));
                        let p2p_gossip_sync = Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone()));
                        let rapid_gossip_sync = Arc::new(RapidGossipSync::new(network_graph.clone(), logger.clone()));
                        let msg_handler = MessageHandler {
index a19c3ff8a9dfc41640d325763c0056b6740fc046..b2d69328931351c3340af05771860068b8d7c588 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-block-sync"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Jeffrey Czyz", "Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -19,11 +19,11 @@ rpc-client = [ "serde_json", "chunked_transfer" ]
 
 [dependencies]
 bitcoin = "0.29.0"
-lightning = { version = "0.0.115", path = "../lightning" }
+lightning = { version = "0.0.116-rc1", path = "../lightning" }
 tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true }
 serde_json = { version = "1.0", optional = true }
 chunked_transfer = { version = "1.4", optional = true }
 
 [dev-dependencies]
-lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.116-rc1", path = "../lightning", features = ["_test_utils"] }
 tokio = { version = "1.14", features = [ "macros", "rt" ] }
index 68aa2a1cb259393545c7637d4a8f08ef4bcce6a9..8c372960fcd9213eced137af6fe9b83a39f3e278 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-custom-message"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Jeffrey Czyz"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -15,4 +15,4 @@ rustdoc-args = ["--cfg", "docsrs"]
 
 [dependencies]
 bitcoin = "0.29.0"
-lightning = { version = "0.0.115", path = "../lightning" }
+lightning = { version = "0.0.116-rc1", path = "../lightning" }
index 5179fdc148a5158e9e9e91d64371a09a243ada11..0d868cea13e0fdaf2f76ee6c1d8af6f187ee4071 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 name = "lightning-invoice"
 description = "Data structures to parse and serialize BOLT11 lightning invoices"
-version = "0.23.0"
+version = "0.24.0-rc1"
 authors = ["Sebastian Geisler <sgeisler@wh2.tu-dresden.de>"]
 documentation = "https://docs.rs/lightning-invoice/"
 license = "MIT OR Apache-2.0"
@@ -21,7 +21,7 @@ std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std", "bech32/std"]
 
 [dependencies]
 bech32 = { version = "0.9.0", default-features = false }
-lightning = { version = "0.0.115", path = "../lightning", default-features = false }
+lightning = { version = "0.0.116-rc1", path = "../lightning", default-features = false }
 secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"] }
 num-traits = { version = "0.2.8", default-features = false }
 bitcoin_hashes = { version = "0.11", default-features = false }
@@ -30,6 +30,6 @@ serde = { version = "1.0.118", optional = true }
 bitcoin = { version = "0.29.0", default-features = false }
 
 [dev-dependencies]
-lightning = { version = "0.0.115", path = "../lightning", default-features = false, features = ["_test_utils"] }
+lightning = { version = "0.0.116-rc1", path = "../lightning", default-features = false, features = ["_test_utils"] }
 hex = "0.4"
 serde_json = { version = "1"}
index 01adf67d1af0816bcc78ddeeacd6473f680b71bf..5bfa9a042c364b749359f09a0ed96380a589cba6 100644 (file)
@@ -23,9 +23,9 @@ use num_traits::{CheckedAdd, CheckedMul};
 use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
 use secp256k1::PublicKey;
 
-use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
-       SemanticError, PrivateRoute, ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice,
-       constants, SignedRawInvoice, RawDataPart, InvoiceFeatures};
+use super::{Bolt11Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, Bolt11InvoiceSignature, PositiveTimestamp,
+       Bolt11SemanticError, PrivateRoute, Bolt11ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawBolt11Invoice,
+       constants, SignedRawBolt11Invoice, RawDataPart, Bolt11InvoiceFeatures};
 
 use self::hrp_sm::parse_hrp;
 
@@ -44,20 +44,20 @@ mod hrp_sm {
        }
 
        impl States {
-               fn next_state(&self, read_symbol: char) -> Result<States, super::ParseError> {
+               fn next_state(&self, read_symbol: char) -> Result<States, super::Bolt11ParseError> {
                        match *self {
                                States::Start => {
                                        if read_symbol == 'l' {
                                                Ok(States::ParseL)
                                        } else {
-                                               Err(super::ParseError::MalformedHRP)
+                                               Err(super::Bolt11ParseError::MalformedHRP)
                                        }
                                }
                                States::ParseL => {
                                        if read_symbol == 'n' {
                                                Ok(States::ParseN)
                                        } else {
-                                               Err(super::ParseError::MalformedHRP)
+                                               Err(super::Bolt11ParseError::MalformedHRP)
                                        }
                                },
                                States::ParseN => {
@@ -80,10 +80,10 @@ mod hrp_sm {
                                        } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
                                                Ok(States::ParseAmountSiPrefix)
                                        } else {
-                                               Err(super::ParseError::UnknownSiPrefix)
+                                               Err(super::Bolt11ParseError::UnknownSiPrefix)
                                        }
                                },
-                               States::ParseAmountSiPrefix => Err(super::ParseError::MalformedHRP),
+                               States::ParseAmountSiPrefix => Err(super::Bolt11ParseError::MalformedHRP),
                        }
                }
 
@@ -120,7 +120,7 @@ mod hrp_sm {
                        *range = Some(new_range);
                }
 
-               fn step(&mut self, c: char) -> Result<(), super::ParseError> {
+               fn step(&mut self, c: char) -> Result<(), super::Bolt11ParseError> {
                        let next_state = self.state.next_state(c)?;
                        match next_state {
                                States::ParseCurrencyPrefix => {
@@ -157,14 +157,14 @@ mod hrp_sm {
                }
        }
 
-       pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::ParseError> {
+       pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::Bolt11ParseError> {
                let mut sm = StateMachine::new();
                for c in input.chars() {
                        sm.step(c)?;
                }
 
                if !sm.is_final() {
-                       return Err(super::ParseError::MalformedHRP);
+                       return Err(super::Bolt11ParseError::MalformedHRP);
                }
 
                let currency = sm.currency_prefix().clone()
@@ -180,37 +180,37 @@ mod hrp_sm {
 
 
 impl FromStr for super::Currency {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
+       fn from_str(currency_prefix: &str) -> Result<Self, Bolt11ParseError> {
                match currency_prefix {
                        "bc" => Ok(Currency::Bitcoin),
                        "tb" => Ok(Currency::BitcoinTestnet),
                        "bcrt" => Ok(Currency::Regtest),
                        "sb" => Ok(Currency::Simnet),
                        "tbs" => Ok(Currency::Signet),
-                       _ => Err(ParseError::UnknownCurrency)
+                       _ => Err(Bolt11ParseError::UnknownCurrency)
                }
        }
 }
 
 impl FromStr for SiPrefix {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
+       fn from_str(currency_prefix: &str) -> Result<Self, Bolt11ParseError> {
                use crate::SiPrefix::*;
                match currency_prefix {
                        "m" => Ok(Milli),
                        "u" => Ok(Micro),
                        "n" => Ok(Nano),
                        "p" => Ok(Pico),
-                       _ => Err(ParseError::UnknownSiPrefix)
+                       _ => Err(Bolt11ParseError::UnknownSiPrefix)
                }
        }
 }
 
 /// ```
-/// use lightning_invoice::Invoice;
+/// use lightning_invoice::Bolt11Invoice;
 ///
 ///
 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
@@ -225,14 +225,14 @@ impl FromStr for SiPrefix {
 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
 /// j5r6drg6k6zcqj0fcwg";
 ///
-/// assert!(invoice.parse::<Invoice>().is_ok());
+/// assert!(invoice.parse::<Bolt11Invoice>().is_ok());
 /// ```
-impl FromStr for Invoice {
+impl FromStr for Bolt11Invoice {
        type Err = ParseOrSemanticError;
 
        fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
-               let signed = s.parse::<SignedRawInvoice>()?;
-               Ok(Invoice::from_signed(signed)?)
+               let signed = s.parse::<SignedRawBolt11Invoice>()?;
+               Ok(Bolt11Invoice::from_signed(signed)?)
        }
 }
 
@@ -251,10 +251,10 @@ impl FromStr for Invoice {
 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
 /// j5r6drg6k6zcqj0fcwg";
 ///
-/// let parsed_1 = invoice.parse::<Invoice>();
+/// let parsed_1 = invoice.parse::<Bolt11Invoice>();
 ///
-/// let parsed_2 = match invoice.parse::<SignedRawInvoice>() {
-///    Ok(signed) => match Invoice::from_signed(signed) {
+/// let parsed_2 = match invoice.parse::<SignedRawBolt11Invoice>() {
+///    Ok(signed) => match Bolt11Invoice::from_signed(signed) {
 ///            Ok(invoice) => Ok(invoice),
 ///            Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
 ///    },
@@ -264,8 +264,8 @@ impl FromStr for Invoice {
 /// assert!(parsed_1.is_ok());
 /// assert_eq!(parsed_1, parsed_2);
 /// ```
-impl FromStr for SignedRawInvoice {
-       type Err = ParseError;
+impl FromStr for SignedRawBolt11Invoice {
+       type Err = Bolt11ParseError;
 
        fn from_str(s: &str) -> Result<Self, Self::Err> {
                let (hrp, data, var) = bech32::decode(s)?;
@@ -273,32 +273,32 @@ impl FromStr for SignedRawInvoice {
                if var == bech32::Variant::Bech32m {
                        // Consider Bech32m addresses to be "Invalid Checksum", since that is what we'd get if
                        // we didn't support Bech32m (which lightning does not use).
-                       return Err(ParseError::Bech32Error(bech32::Error::InvalidChecksum));
+                       return Err(Bolt11ParseError::Bech32Error(bech32::Error::InvalidChecksum));
                }
 
                if data.len() < 104 {
-                       return Err(ParseError::TooShortDataPart);
+                       return Err(Bolt11ParseError::TooShortDataPart);
                }
 
                let raw_hrp: RawHrp = hrp.parse()?;
                let data_part = RawDataPart::from_base32(&data[..data.len()-104])?;
 
-               Ok(SignedRawInvoice {
-                       raw_invoice: RawInvoice {
+               Ok(SignedRawBolt11Invoice {
+                       raw_invoice: RawBolt11Invoice {
                                hrp: raw_hrp,
                                data: data_part,
                        },
-                       hash: RawInvoice::hash_from_parts(
+                       hash: RawBolt11Invoice::hash_from_parts(
                                hrp.as_bytes(),
                                &data[..data.len()-104]
                        ),
-                       signature: InvoiceSignature::from_base32(&data[data.len()-104..])?,
+                       signature: Bolt11InvoiceSignature::from_base32(&data[data.len()-104..])?,
                })
        }
 }
 
 impl FromStr for RawHrp {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
        fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
                let parts = parse_hrp(hrp)?;
@@ -317,7 +317,7 @@ impl FromStr for RawHrp {
                        let si: SiPrefix = parts.2.parse()?;
                        if let Some(amt) = amount {
                                if amt.checked_mul(si.multiplier()).is_none() {
-                                       return Err(ParseError::IntegerOverflowError);
+                                       return Err(Bolt11ParseError::IntegerOverflowError);
                                }
                        }
                        Some(si)
@@ -332,11 +332,11 @@ impl FromStr for RawHrp {
 }
 
 impl FromBase32 for RawDataPart {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
        fn from_base32(data: &[u5]) -> Result<Self, Self::Err> {
                if data.len() < 7 { // timestamp length
-                       return Err(ParseError::TooShortDataPart);
+                       return Err(Bolt11ParseError::TooShortDataPart);
                }
 
                let timestamp = PositiveTimestamp::from_base32(&data[0..7])?;
@@ -350,11 +350,11 @@ impl FromBase32 for RawDataPart {
 }
 
 impl FromBase32 for PositiveTimestamp {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
        fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
                if b32.len() != 7 {
-                       return Err(ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
+                       return Err(Bolt11ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
                }
                let timestamp: u64 = parse_int_be(b32, 32)
                        .expect("7*5bit < 64bit, no overflow possible");
@@ -365,17 +365,17 @@ impl FromBase32 for PositiveTimestamp {
        }
 }
 
-impl FromBase32 for InvoiceSignature {
-       type Err = ParseError;
+impl FromBase32 for Bolt11InvoiceSignature {
+       type Err = Bolt11ParseError;
        fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
                if signature.len() != 104 {
-                       return Err(ParseError::InvalidSliceLength("InvoiceSignature::from_base32()".into()));
+                       return Err(Bolt11ParseError::InvalidSliceLength("Bolt11InvoiceSignature::from_base32()".into()));
                }
                let recoverable_signature_bytes = Vec::<u8>::from_base32(signature)?;
                let signature = &recoverable_signature_bytes[0..64];
                let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
 
-               Ok(InvoiceSignature(RecoverableSignature::from_compact(
+               Ok(Bolt11InvoiceSignature(RecoverableSignature::from_compact(
                        signature,
                        recovery_id
                )?))
@@ -393,13 +393,13 @@ pub(crate) fn parse_int_be<T, U>(digits: &[U], base: T) -> Option<T>
        )
 }
 
-fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
+fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, Bolt11ParseError> {
        let mut parts = Vec::<RawTaggedField>::new();
        let mut data = data;
 
        while !data.is_empty() {
                if data.len() < 3 {
-                       return Err(ParseError::UnexpectedEndOfTaggedFields);
+                       return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
                }
 
                // Ignore tag at data[0], it will be handled in the TaggedField parsers and
@@ -408,7 +408,7 @@ fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
                let last_element = 3 + len;
 
                if data.len() < last_element {
-                       return Err(ParseError::UnexpectedEndOfTaggedFields);
+                       return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
                }
 
                // Get the tagged field's data slice
@@ -421,7 +421,7 @@ fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
                        Ok(field) => {
                                parts.push(RawTaggedField::KnownSemantics(field))
                        },
-                       Err(ParseError::Skip)|Err(ParseError::Bech32Error(bech32::Error::InvalidLength)) => {
+                       Err(Bolt11ParseError::Skip)|Err(Bolt11ParseError::Bech32Error(bech32::Error::InvalidLength)) => {
                                parts.push(RawTaggedField::UnknownSemantics(field.into()))
                        },
                        Err(e) => {return Err(e)}
@@ -431,11 +431,11 @@ fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
 }
 
 impl FromBase32 for TaggedField {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field: &[u5]) -> Result<TaggedField, ParseError> {
+       fn from_base32(field: &[u5]) -> Result<TaggedField, Bolt11ParseError> {
                if field.len() < 3 {
-                       return Err(ParseError::UnexpectedEndOfTaggedFields);
+                       return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
                }
 
                let tag = field[0];
@@ -463,22 +463,22 @@ impl FromBase32 for TaggedField {
                        constants::TAG_PAYMENT_METADATA =>
                                Ok(TaggedField::PaymentMetadata(Vec::<u8>::from_base32(field_data)?)),
                        constants::TAG_FEATURES =>
-                               Ok(TaggedField::Features(InvoiceFeatures::from_base32(field_data)?)),
+                               Ok(TaggedField::Features(Bolt11InvoiceFeatures::from_base32(field_data)?)),
                        _ => {
                                // "A reader MUST skip over unknown fields"
-                               Err(ParseError::Skip)
+                               Err(Bolt11ParseError::Skip)
                        }
                }
        }
 }
 
 impl FromBase32 for Sha256 {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field_data: &[u5]) -> Result<Sha256, ParseError> {
+       fn from_base32(field_data: &[u5]) -> Result<Sha256, Bolt11ParseError> {
                if field_data.len() != 52 {
                        // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
-                       Err(ParseError::Skip)
+                       Err(Bolt11ParseError::Skip)
                } else {
                        Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
                                .expect("length was checked before (52 u5 -> 32 u8)")))
@@ -487,9 +487,9 @@ impl FromBase32 for Sha256 {
 }
 
 impl FromBase32 for Description {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field_data: &[u5]) -> Result<Description, ParseError> {
+       fn from_base32(field_data: &[u5]) -> Result<Description, Bolt11ParseError> {
                let bytes = Vec::<u8>::from_base32(field_data)?;
                let description = String::from(str::from_utf8(&bytes)?);
                Ok(Description::new(description).expect(
@@ -499,12 +499,12 @@ impl FromBase32 for Description {
 }
 
 impl FromBase32 for PayeePubKey {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, ParseError> {
+       fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, Bolt11ParseError> {
                if field_data.len() != 53 {
                        // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
-                       Err(ParseError::Skip)
+                       Err(Bolt11ParseError::Skip)
                } else {
                        let data_bytes = Vec::<u8>::from_base32(field_data)?;
                        let pub_key = PublicKey::from_slice(&data_bytes)?;
@@ -514,37 +514,37 @@ impl FromBase32 for PayeePubKey {
 }
 
 impl FromBase32 for ExpiryTime {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, ParseError> {
+       fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, Bolt11ParseError> {
                match parse_int_be::<u64, u5>(field_data, 32)
                        .map(ExpiryTime::from_seconds)
                {
                        Some(t) => Ok(t),
-                       None => Err(ParseError::IntegerOverflowError),
+                       None => Err(Bolt11ParseError::IntegerOverflowError),
                }
        }
 }
 
 impl FromBase32 for MinFinalCltvExpiryDelta {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiryDelta, ParseError> {
+       fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiryDelta, Bolt11ParseError> {
                let expiry = parse_int_be::<u64, u5>(field_data, 32);
                if let Some(expiry) = expiry {
                        Ok(MinFinalCltvExpiryDelta(expiry))
                } else {
-                       Err(ParseError::IntegerOverflowError)
+                       Err(Bolt11ParseError::IntegerOverflowError)
                }
        }
 }
 
 impl FromBase32 for Fallback {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field_data: &[u5]) -> Result<Fallback, ParseError> {
+       fn from_base32(field_data: &[u5]) -> Result<Fallback, Bolt11ParseError> {
                if field_data.is_empty() {
-                       return Err(ParseError::UnexpectedEndOfTaggedFields);
+                       return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
                }
 
                let version = field_data[0];
@@ -553,7 +553,7 @@ impl FromBase32 for Fallback {
                match version.to_u8() {
                        0..=16 => {
                                if bytes.len() < 2 || bytes.len() > 40 {
-                                       return Err(ParseError::InvalidSegWitProgramLength);
+                                       return Err(Bolt11ParseError::InvalidSegWitProgramLength);
                                }
                                let version = WitnessVersion::try_from(version).expect("0 through 16 are valid SegWit versions");
                                Ok(Fallback::SegWitProgram {
@@ -564,30 +564,30 @@ impl FromBase32 for Fallback {
                        17 => {
                                let pkh = match PubkeyHash::from_slice(&bytes) {
                                        Ok(pkh) => pkh,
-                                       Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(ParseError::InvalidPubKeyHashLength),
+                                       Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidPubKeyHashLength),
                                };
                                Ok(Fallback::PubKeyHash(pkh))
                        }
                        18 => {
                                let sh = match ScriptHash::from_slice(&bytes) {
                                        Ok(sh) => sh,
-                                       Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(ParseError::InvalidScriptHashLength),
+                                       Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidScriptHashLength),
                                };
                                Ok(Fallback::ScriptHash(sh))
                        }
-                       _ => Err(ParseError::Skip)
+                       _ => Err(Bolt11ParseError::Skip)
                }
        }
 }
 
 impl FromBase32 for PrivateRoute {
-       type Err = ParseError;
+       type Err = Bolt11ParseError;
 
-       fn from_base32(field_data: &[u5]) -> Result<PrivateRoute, ParseError> {
+       fn from_base32(field_data: &[u5]) -> Result<PrivateRoute, Bolt11ParseError> {
                let bytes = Vec::<u8>::from_base32(field_data)?;
 
                if bytes.len() % 51 != 0 {
-                       return Err(ParseError::UnexpectedEndOfTaggedFields);
+                       return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
                }
 
                let mut route_hops = Vec::<RouteHintHop>::new();
@@ -619,52 +619,52 @@ impl FromBase32 for PrivateRoute {
        }
 }
 
-impl Display for ParseError {
+impl Display for Bolt11ParseError {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
                match *self {
                        // TODO: find a way to combine the first three arms (e as error::Error?)
-                       ParseError::Bech32Error(ref e) => {
+                       Bolt11ParseError::Bech32Error(ref e) => {
                                write!(f, "Invalid bech32: {}", e)
                        }
-                       ParseError::ParseAmountError(ref e) => {
+                       Bolt11ParseError::ParseAmountError(ref e) => {
                                write!(f, "Invalid amount in hrp ({})", e)
                        }
-                       ParseError::MalformedSignature(ref e) => {
+                       Bolt11ParseError::MalformedSignature(ref e) => {
                                write!(f, "Invalid secp256k1 signature: {}", e)
                        }
-                       ParseError::DescriptionDecodeError(ref e) => {
+                       Bolt11ParseError::DescriptionDecodeError(ref e) => {
                                write!(f, "Description is not a valid utf-8 string: {}", e)
                        }
-                       ParseError::InvalidSliceLength(ref function) => {
+                       Bolt11ParseError::InvalidSliceLength(ref function) => {
                                write!(f, "Slice in function {} had the wrong length", function)
                        }
-                       ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
-                       ParseError::UnknownCurrency => f.write_str("currency code unknown"),
-                       ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
-                       ParseError::MalformedHRP => f.write_str("malformed human readable part"),
-                       ParseError::TooShortDataPart => {
+                       Bolt11ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
+                       Bolt11ParseError::UnknownCurrency => f.write_str("currency code unknown"),
+                       Bolt11ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
+                       Bolt11ParseError::MalformedHRP => f.write_str("malformed human readable part"),
+                       Bolt11ParseError::TooShortDataPart => {
                                f.write_str("data part too short (should be at least 111 bech32 chars long)")
                        },
-                       ParseError::UnexpectedEndOfTaggedFields => {
+                       Bolt11ParseError::UnexpectedEndOfTaggedFields => {
                                f.write_str("tagged fields part ended unexpectedly")
                        },
-                       ParseError::PaddingError => f.write_str("some data field had bad padding"),
-                       ParseError::IntegerOverflowError => {
+                       Bolt11ParseError::PaddingError => f.write_str("some data field had bad padding"),
+                       Bolt11ParseError::IntegerOverflowError => {
                                f.write_str("parsed integer doesn't fit into receiving type")
                        },
-                       ParseError::InvalidSegWitProgramLength => {
+                       Bolt11ParseError::InvalidSegWitProgramLength => {
                                f.write_str("fallback SegWit program is too long or too short")
                        },
-                       ParseError::InvalidPubKeyHashLength => {
+                       Bolt11ParseError::InvalidPubKeyHashLength => {
                                f.write_str("fallback public key hash has a length unequal 20 bytes")
                        },
-                       ParseError::InvalidScriptHashLength => {
+                       Bolt11ParseError::InvalidScriptHashLength => {
                                f.write_str("fallback script hash has a length unequal 32 bytes")
                        },
-                       ParseError::InvalidRecoveryId => {
+                       Bolt11ParseError::InvalidRecoveryId => {
                                f.write_str("recovery id is out of range (should be in [0,3])")
                        },
-                       ParseError::Skip => {
+                       Bolt11ParseError::Skip => {
                                f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property")
                        },
                }
@@ -681,14 +681,14 @@ impl Display for ParseOrSemanticError {
 }
 
 #[cfg(feature = "std")]
-impl error::Error for ParseError {}
+impl error::Error for Bolt11ParseError {}
 
 #[cfg(feature = "std")]
 impl error::Error for ParseOrSemanticError {}
 
 macro_rules! from_error {
     ($my_error:expr, $extern_error:ty) => {
-        impl From<$extern_error> for ParseError {
+        impl From<$extern_error> for Bolt11ParseError {
             fn from(e: $extern_error) -> Self {
                 $my_error(e)
             }
@@ -696,34 +696,34 @@ macro_rules! from_error {
     }
 }
 
-from_error!(ParseError::MalformedSignature, secp256k1::Error);
-from_error!(ParseError::ParseAmountError, ParseIntError);
-from_error!(ParseError::DescriptionDecodeError, str::Utf8Error);
+from_error!(Bolt11ParseError::MalformedSignature, secp256k1::Error);
+from_error!(Bolt11ParseError::ParseAmountError, ParseIntError);
+from_error!(Bolt11ParseError::DescriptionDecodeError, str::Utf8Error);
 
-impl From<bech32::Error> for ParseError {
+impl From<bech32::Error> for Bolt11ParseError {
        fn from(e: bech32::Error) -> Self {
                match e {
-                       bech32::Error::InvalidPadding => ParseError::PaddingError,
-                       _ => ParseError::Bech32Error(e)
+                       bech32::Error::InvalidPadding => Bolt11ParseError::PaddingError,
+                       _ => Bolt11ParseError::Bech32Error(e)
                }
        }
 }
 
-impl From<ParseError> for ParseOrSemanticError {
-       fn from(e: ParseError) -> Self {
+impl From<Bolt11ParseError> for ParseOrSemanticError {
+       fn from(e: Bolt11ParseError) -> Self {
                ParseOrSemanticError::ParseError(e)
        }
 }
 
-impl From<crate::SemanticError> for ParseOrSemanticError {
-       fn from(e: SemanticError) -> Self {
+impl From<crate::Bolt11SemanticError> for ParseOrSemanticError {
+       fn from(e: Bolt11SemanticError) -> Self {
                ParseOrSemanticError::SemanticError(e)
        }
 }
 
 #[cfg(test)]
 mod test {
-       use crate::de::ParseError;
+       use crate::de::Bolt11ParseError;
        use secp256k1::PublicKey;
        use bech32::u5;
        use bitcoin_hashes::hex::FromHex;
@@ -756,7 +756,7 @@ mod test {
                assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
                assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
                assert_eq!("tbs".parse::<Currency>(), Ok(Currency::Signet));
-               assert_eq!("something_else".parse::<Currency>(), Err(ParseError::UnknownCurrency))
+               assert_eq!("something_else".parse::<Currency>(), Err(Bolt11ParseError::UnknownCurrency))
        }
 
        #[test]
@@ -789,7 +789,7 @@ mod test {
                let input_unexpected_length = from_bech32(
                        "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes()
                );
-               assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(ParseError::Skip));
+               assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
        }
 
        #[test]
@@ -823,7 +823,7 @@ mod test {
                let input_unexpected_length = from_bech32(
                        "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes()
                );
-               assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(ParseError::Skip));
+               assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
        }
 
        #[test]
@@ -836,7 +836,7 @@ mod test {
                assert_eq!(ExpiryTime::from_base32(&input), expected);
 
                let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
-               assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(ParseError::IntegerOverflowError));
+               assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(Bolt11ParseError::IntegerOverflowError));
        }
 
        #[test]
@@ -885,23 +885,23 @@ mod test {
                        ),
                        (
                                vec![u5::try_from_u8(21).unwrap(); 41],
-                               Err(ParseError::Skip)
+                               Err(Bolt11ParseError::Skip)
                        ),
                        (
                                vec![],
-                               Err(ParseError::UnexpectedEndOfTaggedFields)
+                               Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)
                        ),
                        (
                                vec![u5::try_from_u8(1).unwrap(); 81],
-                               Err(ParseError::InvalidSegWitProgramLength)
+                               Err(Bolt11ParseError::InvalidSegWitProgramLength)
                        ),
                        (
                                vec![u5::try_from_u8(17).unwrap(); 1],
-                               Err(ParseError::InvalidPubKeyHashLength)
+                               Err(Bolt11ParseError::InvalidPubKeyHashLength)
                        ),
                        (
                                vec![u5::try_from_u8(18).unwrap(); 1],
-                               Err(ParseError::InvalidScriptHashLength)
+                               Err(Bolt11ParseError::InvalidScriptHashLength)
                        )
                ];
 
@@ -963,23 +963,23 @@ mod test {
 
                assert_eq!(
                        PrivateRoute::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
-                       Err(ParseError::UnexpectedEndOfTaggedFields)
+                       Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)
                );
        }
 
        #[test]
        fn test_payment_secret_and_features_de_and_ser() {
-               use lightning::ln::features::InvoiceFeatures;
+               use lightning::ln::features::Bolt11InvoiceFeatures;
                use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
                use crate::TaggedField::*;
-               use crate::{SiPrefix, SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart,
+               use crate::{SiPrefix, SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart,
                                 Currency, Sha256, PositiveTimestamp};
 
                // Feature bits 9, 15, and 99 are set.
-               let expected_features = InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
+               let expected_features = Bolt11InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
                let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
-               let invoice = SignedRawInvoice {
-                                       raw_invoice: RawInvoice {
+               let invoice = SignedRawBolt11Invoice {
+                                       raw_invoice: RawBolt11Invoice {
                                                hrp: RawHrp {
                                                        currency: Currency::Bitcoin,
                                                        raw_amount: Some(25),
@@ -998,7 +998,7 @@ mod test {
                                        hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
                                                                        0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
                                                                        0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9],
-                                       signature: InvoiceSignature(RecoverableSignature::from_compact(
+                                       signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact(
                                                                                &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68,
                                                                                        0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60,
                                                                                        0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3,
@@ -1018,15 +1018,15 @@ mod test {
        fn test_raw_signed_invoice_deserialization() {
                use crate::TaggedField::*;
                use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
-               use crate::{SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
+               use crate::{SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256,
                         PositiveTimestamp};
 
                assert_eq!(
                        "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
                        wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
                        ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
-                       Ok(SignedRawInvoice {
-                               raw_invoice: RawInvoice {
+                       Ok(SignedRawBolt11Invoice {
+                               raw_invoice: RawBolt11Invoice {
                                        hrp: RawHrp {
                                                currency: Currency::Bitcoin,
                                                raw_amount: None,
@@ -1051,7 +1051,7 @@ mod test {
                                        0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
                                        0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
                                ],
-                               signature: InvoiceSignature(RecoverableSignature::from_compact(
+                               signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact(
                                        & [
                                                0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
                                                0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
index 8ccd9d979ab139899731d3724566b0b12e27069d..d1b381130c0714c566d48a38dcf8b843935b6f95 100644 (file)
 //! invoices and functions to create, encode and decode these. If you just want to use the standard
 //! en-/decoding functionality this should get you started:
 //!
-//!   * For parsing use `str::parse::<Invoice>(&self)` (see [`Invoice::from_str`])
+//!   * For parsing use `str::parse::<Bolt11Invoice>(&self)` (see [`Bolt11Invoice::from_str`])
 //!   * For constructing invoices use the [`InvoiceBuilder`]
 //!   * For serializing invoices use the [`Display`]/[`ToString`] traits
 //!
-//! [`Invoice::from_str`]: crate::Invoice#impl-FromStr
+//! [`Bolt11Invoice::from_str`]: crate::Bolt11Invoice#impl-FromStr
 
 #[cfg(not(any(feature = "std", feature = "no-std")))]
 compile_error!("at least one of the `std` or `no-std` features must be enabled");
@@ -51,7 +51,7 @@ use bitcoin::{Address, Network, PubkeyHash, ScriptHash};
 use bitcoin::util::address::{Payload, WitnessVersion};
 use bitcoin_hashes::{Hash, sha256};
 use lightning::ln::PaymentSecret;
-use lightning::ln::features::InvoiceFeatures;
+use lightning::ln::features::Bolt11InvoiceFeatures;
 #[cfg(any(doc, test))]
 use lightning::routing::gossip::RoutingFees;
 use lightning::routing::router::RouteHint;
@@ -106,7 +106,7 @@ mod sync;
 /// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user.
 #[allow(missing_docs)]
 #[derive(PartialEq, Eq, Debug, Clone)]
-pub enum ParseError {
+pub enum Bolt11ParseError {
        Bech32Error(bech32::Error),
        ParseAmountError(ParseIntError),
        MalformedSignature(secp256k1::Error),
@@ -136,10 +136,10 @@ pub enum ParseError {
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub enum ParseOrSemanticError {
        /// The invoice couldn't be decoded
-       ParseError(ParseError),
+       ParseError(Bolt11ParseError),
 
        /// The invoice could be decoded but violates the BOLT11 standard
-       SemanticError(crate::SemanticError),
+       SemanticError(crate::Bolt11SemanticError),
 }
 
 /// The number of bits used to represent timestamps as defined in BOLT 11.
@@ -164,8 +164,8 @@ pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
 /// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
 pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
 
-/// Builder for [`Invoice`]s. It's the most convenient and advised way to use this library. It ensures
-/// that only a semantically and syntactically correct Invoice can be built using it.
+/// Builder for [`Bolt11Invoice`]s. It's the most convenient and advised way to use this library. It
+/// ensures that only a semantically and syntactically correct invoice can be built using it.
 ///
 /// ```
 /// extern crate secp256k1;
@@ -243,15 +243,15 @@ pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S:
 
 /// Represents a syntactically and semantically correct lightning BOLT11 invoice.
 ///
-/// There are three ways to construct an `Invoice`:
+/// There are three ways to construct a `Bolt11Invoice`:
 ///  1. using [`InvoiceBuilder`]
-///  2. using [`Invoice::from_signed`]
-///  3. using `str::parse::<Invoice>(&str)` (see [`Invoice::from_str`])
+///  2. using [`Bolt11Invoice::from_signed`]
+///  3. using `str::parse::<Bolt11Invoice>(&str)` (see [`Bolt11Invoice::from_str`])
 ///
-/// [`Invoice::from_str`]: crate::Invoice#impl-FromStr
+/// [`Bolt11Invoice::from_str`]: crate::Bolt11Invoice#impl-FromStr
 #[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
-pub struct Invoice {
-       signed_invoice: SignedRawInvoice,
+pub struct Bolt11Invoice {
+       signed_invoice: SignedRawBolt11Invoice,
 }
 
 /// Represents the description of an invoice which has to be either a directly included string or
@@ -260,7 +260,7 @@ pub struct Invoice {
 /// This is not exported to bindings users as we don't have a good way to map the reference lifetimes making this
 /// practically impossible to use safely in languages like C.
 #[derive(Eq, PartialEq, Debug, Clone, Ord, PartialOrd)]
-pub enum InvoiceDescription<'f> {
+pub enum Bolt11InvoiceDescription<'f> {
        /// Reference to the directly supplied description in the invoice
        Direct(&'f Description),
 
@@ -268,36 +268,36 @@ pub enum InvoiceDescription<'f> {
        Hash(&'f Sha256),
 }
 
-/// Represents a signed [`RawInvoice`] with cached hash. The signature is not checked and may be
+/// Represents a signed [`RawBolt11Invoice`] with cached hash. The signature is not checked and may be
 /// invalid.
 ///
 /// # Invariants
-/// The hash has to be either from the deserialized invoice or from the serialized [`RawInvoice`].
+/// The hash has to be either from the deserialized invoice or from the serialized [`RawBolt11Invoice`].
 #[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
-pub struct SignedRawInvoice {
-       /// The rawInvoice that the signature belongs to
-       raw_invoice: RawInvoice,
+pub struct SignedRawBolt11Invoice {
+       /// The raw invoice that the signature belongs to
+       raw_invoice: RawBolt11Invoice,
 
-       /// Hash of the [`RawInvoice`] that will be used to check the signature.
+       /// Hash of the [`RawBolt11Invoice`] that will be used to check the signature.
        ///
-       /// * if the `SignedRawInvoice` was deserialized the hash is of from the original encoded form,
+       /// * if the `SignedRawBolt11Invoice` was deserialized the hash is of from the original encoded form,
        /// since it's not guaranteed that encoding it again will lead to the same result since integers
        /// could have been encoded with leading zeroes etc.
-       /// * if the `SignedRawInvoice` was constructed manually the hash will be the calculated hash
-       /// from the [`RawInvoice`]
+       /// * if the `SignedRawBolt11Invoice` was constructed manually the hash will be the calculated hash
+       /// from the [`RawBolt11Invoice`]
        hash: [u8; 32],
 
        /// signature of the payment request
-       signature: InvoiceSignature,
+       signature: Bolt11InvoiceSignature,
 }
 
-/// Represents an syntactically correct [`Invoice`] for a payment on the lightning network,
+/// Represents an syntactically correct [`Bolt11Invoice`] for a payment on the lightning network,
 /// but without the signature information.
 /// Decoding and encoding should not lead to information loss but may lead to different hashes.
 ///
-/// For methods without docs see the corresponding methods in [`Invoice`].
+/// For methods without docs see the corresponding methods in [`Bolt11Invoice`].
 #[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
-pub struct RawInvoice {
+pub struct RawBolt11Invoice {
        /// human readable part
        pub hrp: RawHrp,
 
@@ -305,7 +305,7 @@ pub struct RawInvoice {
        pub data: RawDataPart,
 }
 
-/// Data of the [`RawInvoice`] that is encoded in the human readable part.
+/// Data of the [`RawBolt11Invoice`] that is encoded in the human readable part.
 ///
 /// This is not exported to bindings users as we don't yet support `Option<Enum>`
 #[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
@@ -320,7 +320,7 @@ pub struct RawHrp {
        pub si_prefix: Option<SiPrefix>,
 }
 
-/// Data of the [`RawInvoice`] that is encoded in the data part
+/// Data of the [`RawBolt11Invoice`] that is encoded in the data part
 #[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
 pub struct RawDataPart {
        /// generation time of the invoice
@@ -448,7 +448,7 @@ pub enum TaggedField {
        PrivateRoute(PrivateRoute),
        PaymentSecret(PaymentSecret),
        PaymentMetadata(Vec<u8>),
-       Features(InvoiceFeatures),
+       Features(Bolt11InvoiceFeatures),
 }
 
 /// SHA-256 hash
@@ -499,15 +499,15 @@ pub enum Fallback {
 
 /// Recoverable signature
 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
-pub struct InvoiceSignature(pub RecoverableSignature);
+pub struct Bolt11InvoiceSignature(pub RecoverableSignature);
 
-impl PartialOrd for InvoiceSignature {
+impl PartialOrd for Bolt11InvoiceSignature {
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
                self.0.serialize_compact().1.partial_cmp(&other.0.serialize_compact().1)
        }
 }
 
-impl Ord for InvoiceSignature {
+impl Ord for Bolt11InvoiceSignature {
        fn cmp(&self, other: &Self) -> Ordering {
                self.0.serialize_compact().1.cmp(&other.0.serialize_compact().1)
        }
@@ -621,9 +621,9 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Boo
 }
 
 impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool> InvoiceBuilder<D, H, tb::True, C, S, M> {
-       /// Builds a [`RawInvoice`] if no [`CreationError`] occurred while construction any of the
+       /// Builds a [`RawBolt11Invoice`] if no [`CreationError`] occurred while construction any of the
        /// fields.
-       pub fn build_raw(self) -> Result<RawInvoice, CreationError> {
+       pub fn build_raw(self) -> Result<RawBolt11Invoice, CreationError> {
 
                // If an error occurred at any time before, return it now
                if let Some(e) = self.error {
@@ -647,7 +647,7 @@ impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool> InvoiceBui
                        tagged_fields,
                };
 
-               Ok(RawInvoice {
+               Ok(RawBolt11Invoice {
                        hrp,
                        data,
                })
@@ -671,12 +671,12 @@ impl<H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool> InvoiceBui
        }
 
        /// Set the description or description hash. This function is only available if no description (hash) was set.
-       pub fn invoice_description(self, description: InvoiceDescription) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
+       pub fn invoice_description(self, description: Bolt11InvoiceDescription) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
                match description {
-                       InvoiceDescription::Direct(desc) => {
+                       Bolt11InvoiceDescription::Direct(desc) => {
                                self.description(desc.clone().into_inner())
                        }
-                       InvoiceDescription::Hash(hash) => {
+                       Bolt11InvoiceDescription::Hash(hash) => {
                                self.description_hash(hash.0)
                        }
                }
@@ -744,7 +744,7 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, M: tb::Bool> InvoiceBui
                }
                self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret));
                if !found_features {
-                       let mut features = InvoiceFeatures::empty();
+                       let mut features = Bolt11InvoiceFeatures::empty();
                        features.set_variable_length_onion_required();
                        features.set_payment_secret_required();
                        self.tagged_fields.push(TaggedField::Features(features));
@@ -770,7 +770,7 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBui
                        }
                }
                if !found_features {
-                       let mut features = InvoiceFeatures::empty();
+                       let mut features = Bolt11InvoiceFeatures::empty();
                        features.set_payment_metadata_optional();
                        self.tagged_fields.push(TaggedField::Features(features));
                }
@@ -807,7 +807,7 @@ impl<M: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, tb::Tru
        /// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail
        /// and MUST produce a recoverable signature valid for the given hash and if applicable also for
        /// the included payee public key.
-       pub fn build_signed<F>(self, sign_function: F) -> Result<Invoice, CreationError>
+       pub fn build_signed<F>(self, sign_function: F) -> Result<Bolt11Invoice, CreationError>
                where F: FnOnce(&Message) -> RecoverableSignature
        {
                let invoice = self.try_build_signed::<_, ()>(|hash| {
@@ -824,7 +824,7 @@ impl<M: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, tb::Tru
        /// Builds and signs an invoice using the supplied `sign_function`. This function MAY fail with
        /// an error of type `E` and MUST produce a recoverable signature valid for the given hash and
        /// if applicable also for the included payee public key.
-       pub fn try_build_signed<F, E>(self, sign_function: F) -> Result<Invoice, SignOrCreationError<E>>
+       pub fn try_build_signed<F, E>(self, sign_function: F) -> Result<Bolt11Invoice, SignOrCreationError<E>>
                where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
        {
                let raw = match self.build_raw() {
@@ -837,7 +837,7 @@ impl<M: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, tb::Tru
                        Err(e) => return Err(SignOrCreationError::SignError(e)),
                };
 
-               let invoice = Invoice {
+               let invoice = Bolt11Invoice {
                        signed_invoice: signed,
                };
 
@@ -850,27 +850,27 @@ impl<M: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, tb::Tru
 }
 
 
-impl SignedRawInvoice {
-       /// Disassembles the `SignedRawInvoice` into its three parts:
+impl SignedRawBolt11Invoice {
+       /// Disassembles the `SignedRawBolt11Invoice` into its three parts:
        ///  1. raw invoice
        ///  2. hash of the raw invoice
        ///  3. signature
-       pub fn into_parts(self) -> (RawInvoice, [u8; 32], InvoiceSignature) {
+       pub fn into_parts(self) -> (RawBolt11Invoice, [u8; 32], Bolt11InvoiceSignature) {
                (self.raw_invoice, self.hash, self.signature)
        }
 
-       /// The [`RawInvoice`] which was signed.
-       pub fn raw_invoice(&self) -> &RawInvoice {
+       /// The [`RawBolt11Invoice`] which was signed.
+       pub fn raw_invoice(&self) -> &RawBolt11Invoice {
                &self.raw_invoice
        }
 
-       /// The hash of the [`RawInvoice`] that was signed.
+       /// The hash of the [`RawBolt11Invoice`] that was signed.
        pub fn signable_hash(&self) -> &[u8; 32] {
                &self.hash
        }
 
        /// Signature for the invoice.
-       pub fn signature(&self) -> &InvoiceSignature {
+       pub fn signature(&self) -> &Bolt11InvoiceSignature {
                &self.signature
        }
 
@@ -968,7 +968,7 @@ macro_rules! find_all_extract {
 }
 
 #[allow(missing_docs)]
-impl RawInvoice {
+impl RawBolt11Invoice {
        /// Hash the HRP as bytes and signatureless data part.
        fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
                let preimage = construct_invoice_preimage(hrp_bytes, data_without_signature);
@@ -977,23 +977,23 @@ impl RawInvoice {
                hash
        }
 
-       /// Calculate the hash of the encoded `RawInvoice` which should be signed.
+       /// Calculate the hash of the encoded `RawBolt11Invoice` which should be signed.
        pub fn signable_hash(&self) -> [u8; 32] {
                use bech32::ToBase32;
 
-               RawInvoice::hash_from_parts(
+               RawBolt11Invoice::hash_from_parts(
                        self.hrp.to_string().as_bytes(),
                        &self.data.to_base32()
                )
        }
 
        /// Signs the invoice using the supplied `sign_method`. This function MAY fail with an error of
-       /// type `E`. Since the signature of a [`SignedRawInvoice`] is not required to be valid there
+       /// type `E`. Since the signature of a [`SignedRawBolt11Invoice`] is not required to be valid there
        /// are no constraints regarding the validity of the produced signature.
        ///
        /// This is not exported to bindings users as we don't currently support passing function pointers into methods
        /// explicitly.
-       pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawInvoice, E>
+       pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawBolt11Invoice, E>
                where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
        {
                let raw_hash = self.signable_hash();
@@ -1001,10 +1001,10 @@ impl RawInvoice {
                        .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
                let signature = sign_method(&hash)?;
 
-               Ok(SignedRawInvoice {
+               Ok(SignedRawBolt11Invoice {
                        raw_invoice: self,
                        hash: raw_hash,
-                       signature: InvoiceSignature(signature),
+                       signature: Bolt11InvoiceSignature(signature),
                })
        }
 
@@ -1059,7 +1059,7 @@ impl RawInvoice {
                find_extract!(self.known_tagged_fields(), TaggedField::PaymentMetadata(ref x), x)
        }
 
-       pub fn features(&self) -> Option<&InvoiceFeatures> {
+       pub fn features(&self) -> Option<&Bolt11InvoiceFeatures> {
                find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x)
        }
 
@@ -1142,28 +1142,28 @@ impl From<PositiveTimestamp> for SystemTime {
        }
 }
 
-impl Invoice {
-       /// The hash of the [`RawInvoice`] that was signed.
+impl Bolt11Invoice {
+       /// The hash of the [`RawBolt11Invoice`] that was signed.
        pub fn signable_hash(&self) -> [u8; 32] {
                self.signed_invoice.hash
        }
 
-       /// Transform the `Invoice` into it's unchecked version
-       pub fn into_signed_raw(self) -> SignedRawInvoice {
+       /// Transform the `Bolt11Invoice` into its unchecked version.
+       pub fn into_signed_raw(self) -> SignedRawBolt11Invoice {
                self.signed_invoice
        }
 
        /// Check that all mandatory fields are present
-       fn check_field_counts(&self) -> Result<(), SemanticError> {
+       fn check_field_counts(&self) -> Result<(), Bolt11SemanticError> {
                // "A writer MUST include exactly one p field […]."
                let payment_hash_cnt = self.tagged_fields().filter(|&tf| match *tf {
                        TaggedField::PaymentHash(_) => true,
                        _ => false,
                }).count();
                if payment_hash_cnt < 1 {
-                       return Err(SemanticError::NoPaymentHash);
+                       return Err(Bolt11SemanticError::NoPaymentHash);
                } else if payment_hash_cnt > 1 {
-                       return Err(SemanticError::MultiplePaymentHashes);
+                       return Err(Bolt11SemanticError::MultiplePaymentHashes);
                }
 
                // "A writer MUST include either exactly one d or exactly one h field."
@@ -1172,9 +1172,9 @@ impl Invoice {
                        _ => false,
                }).count();
                if  description_cnt < 1 {
-                       return Err(SemanticError::NoDescription);
+                       return Err(Bolt11SemanticError::NoDescription);
                } else if description_cnt > 1 {
-                       return  Err(SemanticError::MultipleDescriptions);
+                       return  Err(Bolt11SemanticError::MultipleDescriptions);
                }
 
                self.check_payment_secret()?;
@@ -1183,33 +1183,33 @@ impl Invoice {
        }
 
        /// Checks that there is exactly one payment secret field
-       fn check_payment_secret(&self) -> Result<(), SemanticError> {
+       fn check_payment_secret(&self) -> Result<(), Bolt11SemanticError> {
                // "A writer MUST include exactly one `s` field."
                let payment_secret_count = self.tagged_fields().filter(|&tf| match *tf {
                        TaggedField::PaymentSecret(_) => true,
                        _ => false,
                }).count();
                if payment_secret_count < 1 {
-                       return Err(SemanticError::NoPaymentSecret);
+                       return Err(Bolt11SemanticError::NoPaymentSecret);
                } else if payment_secret_count > 1 {
-                       return Err(SemanticError::MultiplePaymentSecrets);
+                       return Err(Bolt11SemanticError::MultiplePaymentSecrets);
                }
 
                Ok(())
        }
 
        /// Check that amount is a whole number of millisatoshis
-       fn check_amount(&self) -> Result<(), SemanticError> {
+       fn check_amount(&self) -> Result<(), Bolt11SemanticError> {
                if let Some(amount_pico_btc) = self.amount_pico_btc() {
                        if amount_pico_btc % 10 != 0 {
-                               return Err(SemanticError::ImpreciseAmount);
+                               return Err(Bolt11SemanticError::ImpreciseAmount);
                        }
                }
                Ok(())
        }
 
        /// Check that feature bits are set as required
-       fn check_feature_bits(&self) -> Result<(), SemanticError> {
+       fn check_feature_bits(&self) -> Result<(), Bolt11SemanticError> {
                self.check_payment_secret()?;
 
                // "A writer MUST set an s field if and only if the payment_secret feature is set."
@@ -1220,12 +1220,12 @@ impl Invoice {
                        _ => false,
                });
                match features {
-                       None => Err(SemanticError::InvalidFeatures),
+                       None => Err(Bolt11SemanticError::InvalidFeatures),
                        Some(TaggedField::Features(features)) => {
                                if features.requires_unknown_bits() {
-                                       Err(SemanticError::InvalidFeatures)
+                                       Err(Bolt11SemanticError::InvalidFeatures)
                                } else if !features.supports_payment_secret() {
-                                       Err(SemanticError::InvalidFeatures)
+                                       Err(Bolt11SemanticError::InvalidFeatures)
                                } else {
                                        Ok(())
                                }
@@ -1235,24 +1235,24 @@ impl Invoice {
        }
 
        /// Check that the invoice is signed correctly and that key recovery works
-       pub fn check_signature(&self) -> Result<(), SemanticError> {
+       pub fn check_signature(&self) -> Result<(), Bolt11SemanticError> {
                match self.signed_invoice.recover_payee_pub_key() {
                        Err(secp256k1::Error::InvalidRecoveryId) =>
-                               return Err(SemanticError::InvalidRecoveryId),
+                               return Err(Bolt11SemanticError::InvalidRecoveryId),
                        Err(secp256k1::Error::InvalidSignature) =>
-                               return Err(SemanticError::InvalidSignature),
+                               return Err(Bolt11SemanticError::InvalidSignature),
                        Err(e) => panic!("no other error may occur, got {:?}", e),
                        Ok(_) => {},
                }
 
                if !self.signed_invoice.check_signature() {
-                       return Err(SemanticError::InvalidSignature);
+                       return Err(Bolt11SemanticError::InvalidSignature);
                }
 
                Ok(())
        }
 
-       /// Constructs an `Invoice` from a [`SignedRawInvoice`] by checking all its invariants.
+       /// Constructs a `Bolt11Invoice` from a [`SignedRawBolt11Invoice`] by checking all its invariants.
        /// ```
        /// use lightning_invoice::*;
        ///
@@ -1268,12 +1268,12 @@ impl Invoice {
        /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
        /// j5r6drg6k6zcqj0fcwg";
        ///
-       /// let signed = invoice.parse::<SignedRawInvoice>().unwrap();
+       /// let signed = invoice.parse::<SignedRawBolt11Invoice>().unwrap();
        ///
-       /// assert!(Invoice::from_signed(signed).is_ok());
+       /// assert!(Bolt11Invoice::from_signed(signed).is_ok());
        /// ```
-       pub fn from_signed(signed_invoice: SignedRawInvoice) -> Result<Self, SemanticError> {
-               let invoice = Invoice {
+       pub fn from_signed(signed_invoice: SignedRawBolt11Invoice) -> Result<Self, Bolt11SemanticError> {
+               let invoice = Bolt11Invoice {
                        signed_invoice,
                };
                invoice.check_field_counts()?;
@@ -1284,18 +1284,18 @@ impl Invoice {
                Ok(invoice)
        }
 
-       /// Returns the `Invoice`'s timestamp (should equal its creation time)
+       /// Returns the `Bolt11Invoice`'s timestamp (should equal its creation time)
        #[cfg(feature = "std")]
        pub fn timestamp(&self) -> SystemTime {
                self.signed_invoice.raw_invoice().data.timestamp.as_time()
        }
 
-       /// Returns the `Invoice`'s timestamp as a duration since the Unix epoch
+       /// Returns the `Bolt11Invoice`'s timestamp as a duration since the Unix epoch
        pub fn duration_since_epoch(&self) -> Duration {
                self.signed_invoice.raw_invoice().data.timestamp.0
        }
 
-       /// Returns an iterator over all tagged fields of this Invoice.
+       /// Returns an iterator over all tagged fields of this `Bolt11Invoice`.
        ///
        /// This is not exported to bindings users as there is not yet a manual mapping for a FilterMap
        pub fn tagged_fields(&self)
@@ -1310,12 +1310,12 @@ impl Invoice {
 
        /// Return the description or a hash of it for longer ones
        ///
-       /// This is not exported to bindings users because we don't yet export InvoiceDescription
-       pub fn description(&self) -> InvoiceDescription {
+       /// This is not exported to bindings users because we don't yet export Bolt11InvoiceDescription
+       pub fn description(&self) -> Bolt11InvoiceDescription {
                if let Some(direct) = self.signed_invoice.description() {
-                       return InvoiceDescription::Direct(direct);
+                       return Bolt11InvoiceDescription::Direct(direct);
                } else if let Some(hash) = self.signed_invoice.description_hash() {
-                       return InvoiceDescription::Hash(hash);
+                       return Bolt11InvoiceDescription::Hash(hash);
                }
                unreachable!("ensured by constructor");
        }
@@ -1336,7 +1336,7 @@ impl Invoice {
        }
 
        /// Get the invoice features if they were included in the invoice
-       pub fn features(&self) -> Option<&InvoiceFeatures> {
+       pub fn features(&self) -> Option<&Bolt11InvoiceFeatures> {
                self.signed_invoice.features()
        }
 
@@ -1591,7 +1591,7 @@ impl Deref for PrivateRoute {
        }
 }
 
-impl Deref for InvoiceSignature {
+impl Deref for Bolt11InvoiceSignature {
        type Target = RecoverableSignature;
 
        fn deref(&self) -> &RecoverableSignature {
@@ -1599,15 +1599,15 @@ impl Deref for InvoiceSignature {
        }
 }
 
-impl Deref for SignedRawInvoice {
-       type Target = RawInvoice;
+impl Deref for SignedRawBolt11Invoice {
+       type Target = RawBolt11Invoice;
 
-       fn deref(&self) -> &RawInvoice {
+       fn deref(&self) -> &RawBolt11Invoice {
                &self.raw_invoice
        }
 }
 
-/// Errors that may occur when constructing a new [`RawInvoice`] or [`Invoice`]
+/// Errors that may occur when constructing a new [`RawBolt11Invoice`] or [`Bolt11Invoice`]
 #[derive(Eq, PartialEq, Debug, Clone)]
 pub enum CreationError {
        /// The supplied description string was longer than 639 __bytes__ (see [`Description::new`])
@@ -1651,10 +1651,10 @@ impl Display for CreationError {
 #[cfg(feature = "std")]
 impl std::error::Error for CreationError { }
 
-/// Errors that may occur when converting a [`RawInvoice`] to an [`Invoice`]. They relate to the
-/// requirements sections in BOLT #11
+/// Errors that may occur when converting a [`RawBolt11Invoice`] to a [`Bolt11Invoice`]. They relate to
+/// the requirements sections in BOLT #11
 #[derive(Eq, PartialEq, Debug, Clone)]
-pub enum SemanticError {
+pub enum Bolt11SemanticError {
        /// The invoice is missing the mandatory payment hash
        NoPaymentHash,
 
@@ -1687,25 +1687,25 @@ pub enum SemanticError {
        ImpreciseAmount,
 }
 
-impl Display for SemanticError {
+impl Display for Bolt11SemanticError {
        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
                match self {
-                       SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
-                       SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
-                       SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
-                       SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
-                       SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
-                       SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
-                       SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
-                       SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
-                       SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
-                       SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
+                       Bolt11SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
+                       Bolt11SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
+                       Bolt11SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
+                       Bolt11SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
+                       Bolt11SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
+                       Bolt11SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
+                       Bolt11SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
+                       Bolt11SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
+                       Bolt11SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
+                       Bolt11SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
                }
        }
 }
 
 #[cfg(feature = "std")]
-impl std::error::Error for SemanticError { }
+impl std::error::Error for Bolt11SemanticError { }
 
 /// When signing using a fallible method either an user-supplied `SignError` or a [`CreationError`]
 /// may occur.
@@ -1728,16 +1728,16 @@ impl<S> Display for SignOrCreationError<S> {
 }
 
 #[cfg(feature = "serde")]
-impl Serialize for Invoice {
+impl Serialize for Bolt11Invoice {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
                serializer.serialize_str(self.to_string().as_str())
        }
 }
 #[cfg(feature = "serde")]
-impl<'de> Deserialize<'de> for Invoice {
-       fn deserialize<D>(deserializer: D) -> Result<Invoice, D::Error> where D: Deserializer<'de> {
+impl<'de> Deserialize<'de> for Bolt11Invoice {
+       fn deserialize<D>(deserializer: D) -> Result<Bolt11Invoice, D::Error> where D: Deserializer<'de> {
                let bolt11 = String::deserialize(deserializer)?
-                       .parse::<Invoice>()
+                       .parse::<Bolt11Invoice>()
                        .map_err(|e| D::Error::custom(format_args!("{:?}", e)))?;
 
                Ok(bolt11)
@@ -1760,10 +1760,10 @@ mod test {
 
        #[test]
        fn test_calc_invoice_hash() {
-               use crate::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
+               use crate::{RawBolt11Invoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
                use crate::TaggedField::*;
 
-               let invoice = RawInvoice {
+               let invoice = RawBolt11Invoice {
                        hrp: RawHrp {
                                currency: Currency::Bitcoin,
                                raw_amount: None,
@@ -1797,11 +1797,11 @@ mod test {
                use secp256k1::Secp256k1;
                use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
                use secp256k1::{SecretKey, PublicKey};
-               use crate::{SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
+               use crate::{SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256,
                         PositiveTimestamp};
 
-               let invoice = SignedRawInvoice {
-                       raw_invoice: RawInvoice {
+               let invoice = SignedRawBolt11Invoice {
+                       raw_invoice: RawBolt11Invoice {
                                hrp: RawHrp {
                                        currency: Currency::Bitcoin,
                                        raw_amount: None,
@@ -1826,7 +1826,7 @@ mod test {
                                0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
                                0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
                        ],
-                       signature: InvoiceSignature(RecoverableSignature::from_compact(
+                       signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact(
                                & [
                                        0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
                                        0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
@@ -1863,15 +1863,15 @@ mod test {
        #[test]
        fn test_check_feature_bits() {
                use crate::TaggedField::*;
-               use lightning::ln::features::InvoiceFeatures;
+               use lightning::ln::features::Bolt11InvoiceFeatures;
                use secp256k1::Secp256k1;
                use secp256k1::SecretKey;
-               use crate::{RawInvoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Invoice,
-                        SemanticError};
+               use crate::{Bolt11Invoice, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, 
+                        Bolt11SemanticError};
 
                let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
                let payment_secret = lightning::ln::PaymentSecret([21; 32]);
-               let invoice_template = RawInvoice {
+               let invoice_template = RawBolt11Invoice {
                        hrp: RawHrp {
                                currency: Currency::Bitcoin,
                                raw_amount: None,
@@ -1898,18 +1898,18 @@ mod test {
                        invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
 
                // Missing feature bits
                let invoice = {
                        let mut invoice = invoice_template.clone();
                        invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
-                       invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
+                       invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
 
-               let mut payment_secret_features = InvoiceFeatures::empty();
+               let mut payment_secret_features = Bolt11InvoiceFeatures::empty();
                payment_secret_features.set_payment_secret_required();
 
                // Including payment secret and feature bits
@@ -1919,22 +1919,22 @@ mod test {
                        invoice.data.tagged_fields.push(Features(payment_secret_features.clone()).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert!(Invoice::from_signed(invoice).is_ok());
+               assert!(Bolt11Invoice::from_signed(invoice).is_ok());
 
                // No payment secret or features
                let invoice = {
                        let invoice = invoice_template.clone();
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
 
                // No payment secret or feature bits
                let invoice = {
                        let mut invoice = invoice_template.clone();
-                       invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
+                       invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
 
                // Missing payment secret
                let invoice = {
@@ -1942,7 +1942,7 @@ mod test {
                        invoice.data.tagged_fields.push(Features(payment_secret_features).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
 
                // Multiple payment secrets
                let invoice = {
@@ -1951,7 +1951,7 @@ mod test {
                        invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::MultiplePaymentSecrets));
        }
 
        #[test]
@@ -2142,12 +2142,12 @@ mod test {
                assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
                assert_eq!(
                        invoice.description(),
-                       InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
+                       Bolt11InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
                );
                assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
                assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));
 
-               let mut expected_features = InvoiceFeatures::empty();
+               let mut expected_features = Bolt11InvoiceFeatures::empty();
                expected_features.set_variable_length_onion_required();
                expected_features.set_payment_secret_required();
                expected_features.set_basic_mpp_optional();
@@ -2176,7 +2176,7 @@ mod test {
                                Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
                        })
                        .unwrap();
-               let invoice = Invoice::from_signed(signed_invoice).unwrap();
+               let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
 
                assert_eq!(invoice.min_final_cltv_expiry_delta(), DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA);
                assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
@@ -2202,7 +2202,7 @@ mod test {
                                Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
                        })
                        .unwrap();
-               let invoice = Invoice::from_signed(signed_invoice).unwrap();
+               let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
 
                assert!(invoice.would_expire(Duration::from_secs(1234567 + DEFAULT_EXPIRY_TIME + 1)));
        }
@@ -2221,9 +2221,9 @@ mod test {
                        p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
                        8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
                        j5r6drg6k6zcqj0fcwg";
-               let invoice = invoice_str.parse::<super::Invoice>().unwrap();
+               let invoice = invoice_str.parse::<super::Bolt11Invoice>().unwrap();
                let serialized_invoice = serde_json::to_string(&invoice).unwrap();
-               let deserialized_invoice: super::Invoice = serde_json::from_str(serialized_invoice.as_str()).unwrap();
+               let deserialized_invoice: super::Bolt11Invoice = serde_json::from_str(serialized_invoice.as_str()).unwrap();
                assert_eq!(invoice, deserialized_invoice);
                assert_eq!(invoice_str, deserialized_invoice.to_string().as_str());
                assert_eq!(invoice_str, serialized_invoice.as_str().trim_matches('\"'));
index bf161dbbf0ebc34e78bf5309761621f4ad1662ee..42408540ee41e7a9e1f9d8ba6c711c6def7b565d 100644 (file)
@@ -9,7 +9,7 @@
 
 //! Convenient utilities for paying Lightning invoices and sending spontaneous payments.
 
-use crate::Invoice;
+use crate::Bolt11Invoice;
 
 use bitcoin_hashes::Hash;
 
@@ -25,15 +25,15 @@ use core::fmt::Debug;
 use core::ops::Deref;
 use core::time::Duration;
 
-/// Pays the given [`Invoice`], retrying if needed based on [`Retry`].
+/// Pays the given [`Bolt11Invoice`], retrying if needed based on [`Retry`].
 ///
-/// [`Invoice::payment_hash`] is used as the [`PaymentId`], which ensures idempotency as long
+/// [`Bolt11Invoice::payment_hash`] is used as the [`PaymentId`], which ensures idempotency as long
 /// as the payment is still pending. If the payment succeeds, you must ensure that a second payment
 /// with the same [`PaymentHash`] is never sent.
 ///
 /// If you wish to use a different payment idempotency token, see [`pay_invoice_with_id`].
 pub fn pay_invoice<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
-       invoice: &Invoice, retry_strategy: Retry,
+       invoice: &Bolt11Invoice, retry_strategy: Retry,
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>
 ) -> Result<PaymentId, PaymentError>
 where
@@ -51,17 +51,18 @@ where
                .map(|()| payment_id)
 }
 
-/// Pays the given [`Invoice`] with a custom idempotency key, retrying if needed based on [`Retry`].
+/// Pays the given [`Bolt11Invoice`] with a custom idempotency key, retrying if needed based on
+/// [`Retry`].
 ///
 /// Note that idempotency is only guaranteed as long as the payment is still pending. Once the
 /// payment completes or fails, no idempotency guarantees are made.
 ///
-/// You should ensure that the [`Invoice::payment_hash`] is unique and the same [`PaymentHash`]
-/// has never been paid before.
+/// You should ensure that the [`Bolt11Invoice::payment_hash`] is unique and the same
+/// [`PaymentHash`] has never been paid before.
 ///
 /// See [`pay_invoice`] for a variant which uses the [`PaymentHash`] for the idempotency token.
 pub fn pay_invoice_with_id<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
-       invoice: &Invoice, payment_id: PaymentId, retry_strategy: Retry,
+       invoice: &Bolt11Invoice, payment_id: PaymentId, retry_strategy: Retry,
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>
 ) -> Result<(), PaymentError>
 where
@@ -78,17 +79,17 @@ where
        pay_invoice_using_amount(invoice, amt_msat, payment_id, retry_strategy, channelmanager)
 }
 
-/// Pays the given zero-value [`Invoice`] using the given amount, retrying if needed based on
+/// Pays the given zero-value [`Bolt11Invoice`] using the given amount, retrying if needed based on
 /// [`Retry`].
 ///
-/// [`Invoice::payment_hash`] is used as the [`PaymentId`], which ensures idempotency as long
+/// [`Bolt11Invoice::payment_hash`] is used as the [`PaymentId`], which ensures idempotency as long
 /// as the payment is still pending. If the payment succeeds, you must ensure that a second payment
 /// with the same [`PaymentHash`] is never sent.
 ///
 /// If you wish to use a different payment idempotency token, see
 /// [`pay_zero_value_invoice_with_id`].
 pub fn pay_zero_value_invoice<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
-       invoice: &Invoice, amount_msats: u64, retry_strategy: Retry,
+       invoice: &Bolt11Invoice, amount_msats: u64, retry_strategy: Retry,
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>
 ) -> Result<PaymentId, PaymentError>
 where
@@ -107,19 +108,19 @@ where
                .map(|()| payment_id)
 }
 
-/// Pays the given zero-value [`Invoice`] using the given amount and custom idempotency key,
+/// Pays the given zero-value [`Bolt11Invoice`] using the given amount and custom idempotency key,
 /// retrying if needed based on [`Retry`].
 ///
 /// Note that idempotency is only guaranteed as long as the payment is still pending. Once the
 /// payment completes or fails, no idempotency guarantees are made.
 ///
-/// You should ensure that the [`Invoice::payment_hash`] is unique and the same [`PaymentHash`]
-/// has never been paid before.
+/// You should ensure that the [`Bolt11Invoice::payment_hash`] is unique and the same
+/// [`PaymentHash`] has never been paid before.
 ///
 /// See [`pay_zero_value_invoice`] for a variant which uses the [`PaymentHash`] for the
 /// idempotency token.
 pub fn pay_zero_value_invoice_with_id<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
-       invoice: &Invoice, amount_msats: u64, payment_id: PaymentId, retry_strategy: Retry,
+       invoice: &Bolt11Invoice, amount_msats: u64, payment_id: PaymentId, retry_strategy: Retry,
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>
 ) -> Result<(), PaymentError>
 where
@@ -141,7 +142,7 @@ where
 }
 
 fn pay_invoice_using_amount<P: Deref>(
-       invoice: &Invoice, amount_msats: u64, payment_id: PaymentId, retry_strategy: Retry,
+       invoice: &Bolt11Invoice, amount_msats: u64, payment_id: PaymentId, retry_strategy: Retry,
        payer: P
 ) -> Result<(), PaymentError> where P::Target: Payer {
        let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner());
@@ -164,20 +165,20 @@ fn pay_invoice_using_amount<P: Deref>(
        payer.send_payment(payment_hash, recipient_onion, payment_id, route_params, retry_strategy)
 }
 
-fn expiry_time_from_unix_epoch(invoice: &Invoice) -> Duration {
+fn expiry_time_from_unix_epoch(invoice: &Bolt11Invoice) -> Duration {
        invoice.signed_invoice.raw_invoice.data.timestamp.0 + invoice.expiry_time()
 }
 
 /// An error that may occur when making a payment.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum PaymentError {
-       /// An error resulting from the provided [`Invoice`] or payment hash.
+       /// An error resulting from the provided [`Bolt11Invoice`] or payment hash.
        Invoice(&'static str),
        /// An error occurring when sending a payment.
        Sending(RetryableSendFailure),
 }
 
-/// A trait defining behavior of an [`Invoice`] payer.
+/// A trait defining behavior of a [`Bolt11Invoice`] payer.
 ///
 /// Useful for unit testing internal methods.
 trait Payer {
@@ -283,7 +284,7 @@ mod tests {
                duration_since_epoch
        }
 
-       fn invoice(payment_preimage: PaymentPreimage) -> Invoice {
+       fn invoice(payment_preimage: PaymentPreimage) -> Bolt11Invoice {
                let payment_hash = Sha256::hash(&payment_preimage.0);
                let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
 
@@ -300,7 +301,7 @@ mod tests {
                        .unwrap()
        }
 
-       fn zero_value_invoice(payment_preimage: PaymentPreimage) -> Invoice {
+       fn zero_value_invoice(payment_preimage: PaymentPreimage) -> Bolt11Invoice {
                let payment_hash = Sha256::hash(&payment_preimage.0);
                let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
 
index 0dca180cab370a79e9358b89d7f1e1d2e51a8c95..dc5dba45da0fe46c24bbf6f8b664dbef76f175b5 100644 (file)
@@ -3,8 +3,8 @@ use core::fmt::{Display, Formatter};
 use bech32::{ToBase32, u5, WriteBase32, Base32Len};
 use crate::prelude::*;
 
-use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
-       PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, constants, SignedRawInvoice, RawDataPart};
+use super::{Bolt11Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, Bolt11InvoiceSignature, PositiveTimestamp,
+       PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, constants, SignedRawBolt11Invoice, RawDataPart};
 
 /// Converts a stream of bytes written to it to base32. On finalization the according padding will
 /// be applied. That means the results of writing two data blocks with one or two `BytesToBase32`
@@ -106,13 +106,13 @@ fn bytes_size_to_base32_size(byte_size: usize) -> usize {
        }
 }
 
-impl Display for Invoice {
+impl Display for Bolt11Invoice {
        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
                self.signed_invoice.fmt(f)
        }
 }
 
-impl Display for SignedRawInvoice {
+impl Display for SignedRawBolt11Invoice {
        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
                let hrp = self.raw_invoice.hrp.to_string();
                let mut data  = self.raw_invoice.data.to_base32();
@@ -456,7 +456,7 @@ impl ToBase32 for TaggedField {
        }
 }
 
-impl ToBase32 for InvoiceSignature {
+impl ToBase32 for Bolt11InvoiceSignature {
        fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
                let mut converter = BytesToBase32::new(writer);
                let (recovery_id, signature) = self.0.serialize_compact();
index d8e7bf12726454cfec9ac0134e7f3ab9fd6a1406..25a7cf77d5e981bfc68b662a9cce862432fbcaa8 100644 (file)
@@ -1,8 +1,8 @@
 //! Convenient utilities to create an invoice.
 
-use crate::{CreationError, Currency, Invoice, InvoiceBuilder, SignOrCreationError};
+use crate::{Bolt11Invoice, CreationError, Currency, InvoiceBuilder, SignOrCreationError};
 
-use crate::{prelude::*, Description, InvoiceDescription, Sha256};
+use crate::{prelude::*, Description, Bolt11InvoiceDescription, Sha256};
 use bech32::ToBase32;
 use bitcoin_hashes::Hash;
 use lightning::chain;
@@ -64,14 +64,14 @@ pub fn create_phantom_invoice<ES: Deref, NS: Deref, L: Deref>(
        amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, description: String,
        invoice_expiry_delta_secs: u32, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
        node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>, duration_since_epoch: Duration,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
 where
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
        L::Target: Logger,
 {
        let description = Description::new(description).map_err(SignOrCreationError::CreationError)?;
-       let description = InvoiceDescription::Direct(&description,);
+       let description = Bolt11InvoiceDescription::Direct(&description,);
        _create_phantom_invoice::<ES, NS, L>(
                amt_msat, payment_hash, description, invoice_expiry_delta_secs, phantom_route_hints,
                entropy_source, node_signer, logger, network, min_final_cltv_expiry_delta, duration_since_epoch,
@@ -120,14 +120,14 @@ pub fn create_phantom_invoice_with_description_hash<ES: Deref, NS: Deref, L: Der
        amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, invoice_expiry_delta_secs: u32,
        description_hash: Sha256, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
        node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>, duration_since_epoch: Duration,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
 where
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
        L::Target: Logger,
 {
        _create_phantom_invoice::<ES, NS, L>(
-               amt_msat, payment_hash, InvoiceDescription::Hash(&description_hash),
+               amt_msat, payment_hash, Bolt11InvoiceDescription::Hash(&description_hash),
                invoice_expiry_delta_secs, phantom_route_hints, entropy_source, node_signer, logger, network,
                min_final_cltv_expiry_delta, duration_since_epoch,
        )
@@ -136,10 +136,10 @@ where
 const MAX_CHANNEL_HINTS: usize = 3;
 
 fn _create_phantom_invoice<ES: Deref, NS: Deref, L: Deref>(
-       amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, description: InvoiceDescription,
+       amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, description: Bolt11InvoiceDescription,
        invoice_expiry_delta_secs: u32, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
        node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>, duration_since_epoch: Duration,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
 where
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -157,10 +157,10 @@ where
        }
 
        let invoice = match description {
-               InvoiceDescription::Direct(description) => {
+               Bolt11InvoiceDescription::Direct(description) => {
                        InvoiceBuilder::new(network).description(description.0.clone())
                }
-               InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
+               Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
        };
 
        // If we ever see performance here being too slow then we should probably take this ExpandedKey as a parameter instead.
@@ -219,7 +219,7 @@ where
        let data_without_signature = raw_invoice.data.to_base32();
        let signed_raw_invoice = raw_invoice.sign(|_| node_signer.sign_invoice(hrp_bytes, &data_without_signature, Recipient::PhantomNode));
        match signed_raw_invoice {
-               Ok(inv) => Ok(Invoice::from_signed(inv).unwrap()),
+               Ok(inv) => Ok(Bolt11Invoice::from_signed(inv).unwrap()),
                Err(e) => Err(SignOrCreationError::SignError(e))
        }
 }
@@ -333,7 +333,7 @@ pub fn create_invoice_from_channelmanager<M: Deref, T: Deref, ES: Deref, NS: Der
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
        network: Currency, amt_msat: Option<u64>, description: String, invoice_expiry_delta_secs: u32,
        min_final_cltv_expiry_delta: Option<u16>,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
 where
        M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
        T::Target: BroadcasterInterface,
@@ -374,7 +374,7 @@ pub fn create_invoice_from_channelmanager_with_description_hash<M: Deref, T: Der
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
        network: Currency, amt_msat: Option<u64>, description_hash: Sha256,
        invoice_expiry_delta_secs: u32, min_final_cltv_expiry_delta: Option<u16>,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
 where
        M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
        T::Target: BroadcasterInterface,
@@ -404,7 +404,7 @@ pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_sin
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
        network: Currency, amt_msat: Option<u64>, description_hash: Sha256,
        duration_since_epoch: Duration, invoice_expiry_delta_secs: u32, min_final_cltv_expiry_delta: Option<u16>,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
                where
                        M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
                        T::Target: BroadcasterInterface,
@@ -417,7 +417,7 @@ pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_sin
 {
        _create_invoice_from_channelmanager_and_duration_since_epoch(
                channelmanager, node_signer, logger, network, amt_msat,
-               InvoiceDescription::Hash(&description_hash),
+               Bolt11InvoiceDescription::Hash(&description_hash),
                duration_since_epoch, invoice_expiry_delta_secs, min_final_cltv_expiry_delta,
        )
 }
@@ -429,7 +429,7 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T:
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
        network: Currency, amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
        invoice_expiry_delta_secs: u32, min_final_cltv_expiry_delta: Option<u16>,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
                where
                        M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
                        T::Target: BroadcasterInterface,
@@ -442,7 +442,7 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T:
 {
        _create_invoice_from_channelmanager_and_duration_since_epoch(
                channelmanager, node_signer, logger, network, amt_msat,
-               InvoiceDescription::Direct(
+               Bolt11InvoiceDescription::Direct(
                        &Description::new(description).map_err(SignOrCreationError::CreationError)?,
                ),
                duration_since_epoch, invoice_expiry_delta_secs, min_final_cltv_expiry_delta,
@@ -451,9 +451,9 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T:
 
 fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
-       network: Currency, amt_msat: Option<u64>, description: InvoiceDescription,
+       network: Currency, amt_msat: Option<u64>, description: Bolt11InvoiceDescription,
        duration_since_epoch: Duration, invoice_expiry_delta_secs: u32, min_final_cltv_expiry_delta: Option<u16>,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
                where
                        M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
                        T::Target: BroadcasterInterface,
@@ -486,7 +486,7 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
        network: Currency, amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
        invoice_expiry_delta_secs: u32, payment_hash: PaymentHash, min_final_cltv_expiry_delta: Option<u16>,
-) -> Result<Invoice, SignOrCreationError<()>>
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
        where
                M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
                T::Target: BroadcasterInterface,
@@ -503,7 +503,7 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_
                .map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
        _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
                channelmanager, node_signer, logger, network, amt_msat,
-               InvoiceDescription::Direct(
+               Bolt11InvoiceDescription::Direct(
                        &Description::new(description).map_err(SignOrCreationError::CreationError)?,
                ),
                duration_since_epoch, invoice_expiry_delta_secs, payment_hash, payment_secret,
@@ -513,10 +513,10 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_
 
 fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
        channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
-       network: Currency, amt_msat: Option<u64>, description: InvoiceDescription, duration_since_epoch: Duration,
-       invoice_expiry_delta_secs: u32, payment_hash: PaymentHash, payment_secret: PaymentSecret,
-       min_final_cltv_expiry_delta: Option<u16>,
-) -> Result<Invoice, SignOrCreationError<()>>
+       network: Currency, amt_msat: Option<u64>, description: Bolt11InvoiceDescription,
+       duration_since_epoch: Duration, invoice_expiry_delta_secs: u32, payment_hash: PaymentHash,
+       payment_secret: PaymentSecret, min_final_cltv_expiry_delta: Option<u16>,
+) -> Result<Bolt11Invoice, SignOrCreationError<()>>
        where
                M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
                T::Target: BroadcasterInterface,
@@ -537,10 +537,10 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
        log_trace!(logger, "Creating invoice with payment hash {}", log_bytes!(payment_hash.0));
 
        let invoice = match description {
-               InvoiceDescription::Direct(description) => {
+               Bolt11InvoiceDescription::Direct(description) => {
                        InvoiceBuilder::new(network).description(description.0.clone())
                }
-               InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
+               Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
        };
 
        let mut invoice = invoice
@@ -571,7 +571,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
        let data_without_signature = raw_invoice.data.to_base32();
        let signed_raw_invoice = raw_invoice.sign(|_| node_signer.sign_invoice(hrp_bytes, &data_without_signature, Recipient::Node));
        match signed_raw_invoice {
-               Ok(inv) => Ok(Invoice::from_signed(inv).unwrap()),
+               Ok(inv) => Ok(Bolt11Invoice::from_signed(inv).unwrap()),
                Err(e) => Err(SignOrCreationError::SignError(e))
        }
 }
@@ -792,12 +792,13 @@ fn prefer_current_channel(min_inbound_capacity_msat: Option<u64>, current_channe
 
 #[cfg(test)]
 mod test {
+       use core::cell::RefCell;
        use core::time::Duration;
-       use crate::{Currency, Description, InvoiceDescription, SignOrCreationError, CreationError};
+       use crate::{Currency, Description, Bolt11InvoiceDescription, SignOrCreationError, CreationError};
        use bitcoin_hashes::{Hash, sha256};
        use bitcoin_hashes::sha256::Hash as Sha256;
        use lightning::sign::PhantomKeysManager;
-       use lightning::events::{MessageSendEvent, MessageSendEventsProvider, Event};
+       use lightning::events::{MessageSendEvent, MessageSendEventsProvider, Event, EventsProvider};
        use lightning::ln::{PaymentPreimage, PaymentHash};
        use lightning::ln::channelmanager::{PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY_DELTA, PaymentId, RecipientOnionFields, Retry};
        use lightning::ln::functional_test_utils::*;
@@ -851,7 +852,7 @@ mod test {
                assert_eq!(invoice.amount_pico_btc(), Some(100_000));
                // If no `min_final_cltv_expiry_delta` is specified, then it should be `MIN_FINAL_CLTV_EXPIRY_DELTA`.
                assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
-               assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
+               assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description("test".to_string())));
                assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
 
                // Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
@@ -947,7 +948,7 @@ mod test {
                ).unwrap();
                assert_eq!(invoice.amount_pico_btc(), Some(100_000));
                assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
-               assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Testing description_hash".as_bytes()))));
+               assert_eq!(invoice.description(), Bolt11InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Testing description_hash".as_bytes()))));
        }
 
        #[test]
@@ -964,7 +965,7 @@ mod test {
                ).unwrap();
                assert_eq!(invoice.amount_pico_btc(), Some(100_000));
                assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
-               assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
+               assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description("test".to_string())));
                assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
        }
 
@@ -1299,13 +1300,14 @@ mod test {
                } else {
                        None
                };
+               let genesis_timestamp = bitcoin::blockdata::constants::genesis_block(bitcoin::Network::Testnet).header.time as u64;
                let non_default_invoice_expiry_secs = 4200;
 
                let invoice =
                        crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestLogger>(
                                Some(payment_amt), payment_hash, "test".to_string(), non_default_invoice_expiry_secs,
                                route_hints, nodes[1].keys_manager, nodes[1].keys_manager, nodes[1].logger,
-                               Currency::BitcoinTestnet, None, Duration::from_secs(1234567)
+                               Currency::BitcoinTestnet, None, Duration::from_secs(genesis_timestamp)
                        ).unwrap();
                let (payment_hash, payment_secret) = (PaymentHash(invoice.payment_hash().into_inner()), *invoice.payment_secret());
                let payment_preimage = if user_generated_pmt_hash {
@@ -1315,7 +1317,7 @@ mod test {
                };
 
                assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
-               assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
+               assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description("test".to_string())));
                assert_eq!(invoice.route_hints().len(), 2);
                assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
                assert!(!invoice.features().unwrap().supports_basic_mpp());
@@ -1356,13 +1358,20 @@ mod test {
                // Note that we have to "forward pending HTLCs" twice before we see the PaymentClaimable as
                // this "emulates" the payment taking two hops, providing some privacy to make phantom node
                // payments "look real" by taking more time.
-               expect_pending_htlcs_forwardable_ignore!(nodes[fwd_idx]);
-               nodes[fwd_idx].node.process_pending_htlc_forwards();
-               expect_pending_htlcs_forwardable_ignore!(nodes[fwd_idx]);
-               nodes[fwd_idx].node.process_pending_htlc_forwards();
+               let other_events = RefCell::new(Vec::new());
+               let forward_event_handler = |event: Event| {
+                       if let Event::PendingHTLCsForwardable { .. } = event {
+                               nodes[fwd_idx].node.process_pending_htlc_forwards();
+                       } else {
+                               other_events.borrow_mut().push(event);
+                       }
+               };
+               nodes[fwd_idx].node.process_pending_events(&forward_event_handler);
+               nodes[fwd_idx].node.process_pending_events(&forward_event_handler);
 
                let payment_preimage_opt = if user_generated_pmt_hash { None } else { Some(payment_preimage) };
-               expect_payment_claimable!(&nodes[fwd_idx], payment_hash, payment_secret, payment_amt, payment_preimage_opt, invoice.recover_payee_pub_key());
+               assert_eq!(other_events.borrow().len(), 1);
+               check_payment_claimable(&other_events.borrow()[0], payment_hash, payment_secret, payment_amt, payment_preimage_opt, invoice.recover_payee_pub_key());
                do_claim_payment_along_route(&nodes[0], &[&vec!(&nodes[fwd_idx])[..]], false, payment_preimage);
                let events = nodes[0].node.get_and_clear_pending_events();
                assert_eq!(events.len(), 2);
@@ -1446,7 +1455,7 @@ mod test {
                assert_eq!(invoice.amount_pico_btc(), Some(200_000));
                assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
                assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
-               assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Description hash phantom invoice".as_bytes()))));
+               assert_eq!(invoice.description(), Bolt11InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Description hash phantom invoice".as_bytes()))));
        }
 
        #[test]
index ef5a4d32b30a0caa7c397217fb808a64ca2be877..e21b82eae3c7e0053b9efc5f02383716574f026f 100644 (file)
@@ -19,7 +19,7 @@ use std::collections::HashSet;
 use std::time::Duration;
 use std::str::FromStr;
 
-fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
+fn get_test_tuples() -> Vec<(String, SignedRawBolt11Invoice, bool, bool)> {
        vec![
                (
                        "lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql".to_owned(),
@@ -389,7 +389,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
 fn invoice_deserialize() {
        for (serialized, deserialized, ignore_feature_diff, ignore_unknown_fields) in get_test_tuples() {
                eprintln!("Testing invoice {}...", serialized);
-               let parsed = serialized.parse::<SignedRawInvoice>().unwrap();
+               let parsed = serialized.parse::<SignedRawBolt11Invoice>().unwrap();
 
                let (parsed_invoice, _, parsed_sig) = parsed.into_parts();
                let (deserialized_invoice, _, deserialized_sig) = deserialized.into_parts();
@@ -412,35 +412,35 @@ fn invoice_deserialize() {
                }
                assert_eq!(deserialized_hunks, parsed_hunks);
 
-               Invoice::from_signed(serialized.parse::<SignedRawInvoice>().unwrap()).unwrap();
+               Bolt11Invoice::from_signed(serialized.parse::<SignedRawBolt11Invoice>().unwrap()).unwrap();
        }
 }
 
 #[test]
 fn test_bolt_invalid_invoices() {
        // Tests the BOLT 11 invalid invoice test vectors
-       assert_eq!(Invoice::from_str(
+       assert_eq!(Bolt11Invoice::from_str(
                "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372"
-               ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidFeatures)));
-       assert_eq!(Invoice::from_str(
+               ), Err(ParseOrSemanticError::SemanticError(Bolt11SemanticError::InvalidFeatures)));
+       assert_eq!(Bolt11Invoice::from_str(
                "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt"
-               ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::InvalidChecksum))));
-       assert_eq!(Invoice::from_str(
+               ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::InvalidChecksum))));
+       assert_eq!(Bolt11Invoice::from_str(
                "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
-               ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MissingSeparator))));
-       assert_eq!(Invoice::from_str(
+               ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::MissingSeparator))));
+       assert_eq!(Bolt11Invoice::from_str(
                "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
-               ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MixedCase))));
-       assert_eq!(Invoice::from_str(
+               ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::MixedCase))));
+       assert_eq!(Bolt11Invoice::from_str(
                "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2"
-               ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidSignature)));
-       assert_eq!(Invoice::from_str(
+               ), Err(ParseOrSemanticError::SemanticError(Bolt11SemanticError::InvalidSignature)));
+       assert_eq!(Bolt11Invoice::from_str(
                "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh"
-               ), Err(ParseOrSemanticError::ParseError(ParseError::TooShortDataPart)));
-       assert_eq!(Invoice::from_str(
+               ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::TooShortDataPart)));
+       assert_eq!(Bolt11Invoice::from_str(
                "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqrrzc4cvfue4zp3hggxp47ag7xnrlr8vgcmkjxk3j5jqethnumgkpqp23z9jclu3v0a7e0aruz366e9wqdykw6dxhdzcjjhldxq0w6wgqcnu43j"
-               ), Err(ParseOrSemanticError::ParseError(ParseError::UnknownSiPrefix)));
-       assert_eq!(Invoice::from_str(
+               ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::UnknownSiPrefix)));
+       assert_eq!(Bolt11Invoice::from_str(
                "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x"
-               ), Err(ParseOrSemanticError::SemanticError(SemanticError::ImpreciseAmount)));
+               ), Err(ParseOrSemanticError::SemanticError(Bolt11SemanticError::ImpreciseAmount)));
 }
index a0fdcf8399d8865134c00ced502d0bc476fe3575..0e5b285993b47966f2b0e69817549fc51672a4a1 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-net-tokio"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
@@ -16,9 +16,9 @@ rustdoc-args = ["--cfg", "docsrs"]
 
 [dependencies]
 bitcoin = "0.29.0"
-lightning = { version = "0.0.115", path = "../lightning" }
-tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] }
+lightning = { version = "0.0.116-rc1", path = "../lightning" }
+tokio = { version = "1.0", features = [ "io-util", "rt", "sync", "net", "time" ] }
 
 [dev-dependencies]
 tokio = { version = "1.14", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] }
-lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.116-rc1", path = "../lightning", features = ["_test_utils"] }
index 724a57fb15c19bb1ba9c9c09bd3fbe44fc3a6478..d6d8004164bf9ab54db94ee64b55ef63f5f57e74 100644 (file)
@@ -42,16 +42,79 @@ use lightning::ln::peer_handler::APeerManager;
 use lightning::ln::msgs::NetAddress;
 
 use std::ops::Deref;
-use std::task;
+use std::task::{self, Poll};
+use std::future::Future;
 use std::net::SocketAddr;
 use std::net::TcpStream as StdTcpStream;
 use std::sync::{Arc, Mutex};
 use std::sync::atomic::{AtomicU64, Ordering};
 use std::time::Duration;
+use std::pin::Pin;
 use std::hash::Hash;
 
 static ID_COUNTER: AtomicU64 = AtomicU64::new(0);
 
+// We only need to select over multiple futures in one place, and taking on the full `tokio/macros`
+// dependency tree in order to do so (which has broken our MSRV before) is excessive. Instead, we
+// define a trivial two- and three- select macro with the specific types we need and just use that.
+
+pub(crate) enum SelectorOutput {
+       A(Option<()>), B(Option<()>), C(tokio::io::Result<usize>),
+}
+
+pub(crate) struct TwoSelector<
+       A: Future<Output=Option<()>> + Unpin, B: Future<Output=Option<()>> + Unpin
+> {
+       pub a: A,
+       pub b: B,
+}
+
+impl<
+       A: Future<Output=Option<()>> + Unpin, B: Future<Output=Option<()>> + Unpin
+> Future for TwoSelector<A, B> {
+       type Output = SelectorOutput;
+       fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<SelectorOutput> {
+               match Pin::new(&mut self.a).poll(ctx) {
+                       Poll::Ready(res) => { return Poll::Ready(SelectorOutput::A(res)); },
+                       Poll::Pending => {},
+               }
+               match Pin::new(&mut self.b).poll(ctx) {
+                       Poll::Ready(res) => { return Poll::Ready(SelectorOutput::B(res)); },
+                       Poll::Pending => {},
+               }
+               Poll::Pending
+       }
+}
+
+pub(crate) struct ThreeSelector<
+       A: Future<Output=Option<()>> + Unpin, B: Future<Output=Option<()>> + Unpin, C: Future<Output=tokio::io::Result<usize>> + Unpin
+> {
+       pub a: A,
+       pub b: B,
+       pub c: C,
+}
+
+impl<
+       A: Future<Output=Option<()>> + Unpin, B: Future<Output=Option<()>> + Unpin, C: Future<Output=tokio::io::Result<usize>> + Unpin
+> Future for ThreeSelector<A, B, C> {
+       type Output = SelectorOutput;
+       fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<SelectorOutput> {
+               match Pin::new(&mut self.a).poll(ctx) {
+                       Poll::Ready(res) => { return Poll::Ready(SelectorOutput::A(res)); },
+                       Poll::Pending => {},
+               }
+               match Pin::new(&mut self.b).poll(ctx) {
+                       Poll::Ready(res) => { return Poll::Ready(SelectorOutput::B(res)); },
+                       Poll::Pending => {},
+               }
+               match Pin::new(&mut self.c).poll(ctx) {
+                       Poll::Ready(res) => { return Poll::Ready(SelectorOutput::C(res)); },
+                       Poll::Pending => {},
+               }
+               Poll::Pending
+       }
+}
+
 /// Connection contains all our internal state for a connection - we hold a reference to the
 /// Connection object (in an Arc<Mutex<>>) in each SocketDescriptor we create as well as in the
 /// read future (which is returned by schedule_read).
@@ -127,29 +190,44 @@ impl Connection {
                                }
                                us_lock.read_paused
                        };
-                       tokio::select! {
-                               v = write_avail_receiver.recv() => {
+                       // TODO: Drop the Box'ing of the futures once Rust has pin-on-stack support.
+                       let select_result = if read_paused {
+                               TwoSelector {
+                                       a: Box::pin(write_avail_receiver.recv()),
+                                       b: Box::pin(read_wake_receiver.recv()),
+                               }.await
+                       } else {
+                               ThreeSelector {
+                                       a: Box::pin(write_avail_receiver.recv()),
+                                       b: Box::pin(read_wake_receiver.recv()),
+                                       c: Box::pin(reader.read(&mut buf)),
+                               }.await
+                       };
+                       match select_result {
+                               SelectorOutput::A(v) => {
                                        assert!(v.is_some()); // We can't have dropped the sending end, its in the us Arc!
                                        if peer_manager.as_ref().write_buffer_space_avail(&mut our_descriptor).is_err() {
                                                break Disconnect::CloseConnection;
                                        }
                                },
-                               _ = read_wake_receiver.recv() => {},
-                               read = reader.read(&mut buf), if !read_paused => match read {
-                                       Ok(0) => break Disconnect::PeerDisconnected,
-                                       Ok(len) => {
-                                               let read_res = peer_manager.as_ref().read_event(&mut our_descriptor, &buf[0..len]);
-                                               let mut us_lock = us.lock().unwrap();
-                                               match read_res {
-                                                       Ok(pause_read) => {
-                                                               if pause_read {
-                                                                       us_lock.read_paused = true;
-                                                               }
-                                                       },
-                                                       Err(_) => break Disconnect::CloseConnection,
-                                               }
-                                       },
-                                       Err(_) => break Disconnect::PeerDisconnected,
+                               SelectorOutput::B(_) => {},
+                               SelectorOutput::C(read) => {
+                                       match read {
+                                               Ok(0) => break Disconnect::PeerDisconnected,
+                                               Ok(len) => {
+                                                       let read_res = peer_manager.as_ref().read_event(&mut our_descriptor, &buf[0..len]);
+                                                       let mut us_lock = us.lock().unwrap();
+                                                       match read_res {
+                                                               Ok(pause_read) => {
+                                                                       if pause_read {
+                                                                               us_lock.read_paused = true;
+                                                                       }
+                                                               },
+                                                               Err(_) => break Disconnect::CloseConnection,
+                                                       }
+                                               },
+                                               Err(_) => break Disconnect::PeerDisconnected,
+                                       }
                                },
                        }
                        let _ = event_waker.try_send(());
index 22d4b16c42dde8a4828fb424ad64ab5da52ad326..a10d32f90d8cf104c2cc3024689a5be224df9568 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-persister"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Valentine Wallace", "Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
@@ -15,7 +15,7 @@ rustdoc-args = ["--cfg", "docsrs"]
 
 [dependencies]
 bitcoin = "0.29.0"
-lightning = { version = "0.0.115", path = "../lightning" }
+lightning = { version = "0.0.116-rc1", path = "../lightning" }
 libc = "0.2"
 
 [target.'cfg(windows)'.dependencies]
@@ -25,4 +25,4 @@ winapi = { version = "0.3", features = ["winbase"] }
 criterion = { version = "0.4", optional = true, default-features = false }
 
 [dev-dependencies]
-lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.116-rc1", path = "../lightning", features = ["_test_utils"] }
index 73a68751128809a694ac8eaeede95fb58754d2b8..cb4922fa7392397d2aa1be4e8c56c669a4f02b7f 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-rapid-gossip-sync"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Arik Sosman <git@arik.io>"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning"
@@ -15,11 +15,11 @@ no-std = ["lightning/no-std"]
 std = ["lightning/std"]
 
 [dependencies]
-lightning = { version = "0.0.115", path = "../lightning", default-features = false }
+lightning = { version = "0.0.116-rc1", path = "../lightning", default-features = false }
 bitcoin = { version = "0.29.0", default-features = false }
 
 [target.'cfg(ldk_bench)'.dependencies]
 criterion = { version = "0.4", optional = true, default-features = false }
 
 [dev-dependencies]
-lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.116-rc1", path = "../lightning", features = ["_test_utils"] }
index 2e9e13296b6c993e1622c84370e20a2cd97e88b0..2db3fc69747c4204b5d3bb6995ec4db161461dba 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-transaction-sync"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Elias Rohrer"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -21,7 +21,7 @@ esplora-blocking = ["esplora-client/blocking"]
 async-interface = []
 
 [dependencies]
-lightning = { version = "0.0.115", path = "../lightning", default-features = false }
+lightning = { version = "0.0.116-rc1", path = "../lightning", default-features = false }
 bitcoin = { version = "0.29.0", default-features = false }
 bdk-macros = "0.6"
 futures = { version = "0.3", optional = true }
@@ -29,7 +29,7 @@ esplora-client = { version = "0.4", default-features = false, optional = true }
 reqwest = { version = "0.11", optional = true, default-features = false, features = ["json"] }
 
 [dev-dependencies]
-lightning = { version = "0.0.115", path = "../lightning", features = ["std"] }
+lightning = { version = "0.0.116-rc1", path = "../lightning", features = ["std"] }
 electrsd = { version = "0.22.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_23_0"] }
 electrum-client = "0.12.0"
 tokio = { version = "1.14.0", features = ["full"] }
index efaa82d2031ba27e2a40cd930f367780f26efb71..09a76109aeba829f334ed7c16238ec8b3ce71e4b 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning"
-version = "0.0.115"
+version = "0.0.116-rc1"
 authors = ["Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
index d875dcce3e128c1443a2deaa46f1a8465a7cd06b..913fa007d378e91ba5666e3d34ae11c15010ce13 100644 (file)
 //! disconnections, transaction broadcasting, and feerate information requests.
 
 use core::{cmp, ops::Deref};
+use core::convert::TryInto;
 
 use bitcoin::blockdata::transaction::Transaction;
 
+// TODO: Define typed abstraction over feerates to handle their conversions.
+pub(crate) fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 {
+       (fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value())
+}
+pub(crate) const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 {
+       ((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000
+}
+
 /// An interface to send a transaction to the Bitcoin network.
 pub trait BroadcasterInterface {
        /// Sends a list of transactions out to (hopefully) be mined.
@@ -35,21 +44,35 @@ pub trait BroadcasterInterface {
        fn broadcast_transactions(&self, txs: &[&Transaction]);
 }
 
-/// An enum that represents the speed at which we want a transaction to confirm used for feerate
+/// An enum that represents the priority at which we want a transaction to confirm used for feerate
 /// estimation.
 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
 pub enum ConfirmationTarget {
-       /// We are happy with this transaction confirming slowly when feerate drops some.
+       /// We'd like a transaction to confirm in the future, but don't want to commit most of the fees
+       /// required to do so yet. The remaining fees will come via a Child-Pays-For-Parent (CPFP) fee
+       /// bump of the transaction.
+       ///
+       /// The feerate returned should be the absolute minimum feerate required to enter most node
+       /// mempools across the network. Note that if you are not able to obtain this feerate estimate,
+       /// you should likely use the furthest-out estimate allowed by your fee estimator.
+       MempoolMinimum,
+       /// We are happy with a transaction confirming slowly, at least within a day or so worth of
+       /// blocks.
        Background,
-       /// We'd like this transaction to confirm without major delay, but 12-18 blocks is fine.
+       /// We'd like a transaction to confirm without major delayed, i.e., within the next 12-24 blocks.
        Normal,
-       /// We'd like this transaction to confirm in the next few blocks.
+       /// We'd like a transaction to confirm in the next few blocks.
        HighPriority,
 }
 
 /// A trait which should be implemented to provide feerate information on a number of time
 /// horizons.
 ///
+/// If access to a local mempool is not feasible, feerate estimates should be fetched from a set of
+/// third-parties hosting them. Note that this enables them to affect the propagation of your
+/// pre-signed transactions at any time and therefore endangers the safety of channels funds. It
+/// should be considered carefully as a deployment.
+///
 /// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're
 /// called from inside the library in response to chain events, P2P events, or timer events).
 pub trait FeeEstimator {
index 261e5593b5b4600ad661142a4579308b68903316..2cc71a2ecc7ce7a77e99abee6fc0a135a058c7bc 100644 (file)
@@ -502,7 +502,7 @@ where C::Target: chain::Filter,
                self.event_notifier.notify();
        }
 
-       #[cfg(any(test, fuzzing, feature = "_test_utils"))]
+       #[cfg(any(test, feature = "_test_utils"))]
        pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
                use crate::events::EventsProvider;
                let events = core::cell::RefCell::new(Vec::new());
@@ -520,12 +520,13 @@ where C::Target: chain::Filter,
        pub async fn process_pending_events_async<Future: core::future::Future, H: Fn(Event) -> Future>(
                &self, handler: H
        ) {
-               let mut pending_events = Vec::new();
-               for monitor_state in self.monitors.read().unwrap().values() {
-                       pending_events.append(&mut monitor_state.monitor.get_and_clear_pending_events());
-               }
-               for event in pending_events {
-                       handler(event).await;
+               // Sadly we can't hold the monitors read lock through an async call. Thus we have to do a
+               // crazy dance to process a monitor's events then only remove them once we've done so.
+               let mons_to_process = self.monitors.read().unwrap().keys().cloned().collect::<Vec<_>>();
+               for funding_txo in mons_to_process {
+                       let mut ev;
+                       super::channelmonitor::process_events_body!(
+                               self.monitors.read().unwrap().get(&funding_txo).map(|m| &m.monitor), ev, handler(ev).await);
                }
        }
 
@@ -782,30 +783,13 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner, C: Deref, T: Deref, F: Deref, L
              L::Target: Logger,
              P::Target: Persist<ChannelSigner>,
 {
-       #[cfg(not(anchors))]
-       /// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity.
-       ///
-       /// An [`EventHandler`] may safely call back to the provider, though this shouldn't be needed in
-       /// order to handle these events.
-       ///
-       /// [`SpendableOutputs`]: events::Event::SpendableOutputs
-       fn process_pending_events<H: Deref>(&self, handler: H) where H::Target: EventHandler {
-               let mut pending_events = Vec::new();
-               for monitor_state in self.monitors.read().unwrap().values() {
-                       pending_events.append(&mut monitor_state.monitor.get_and_clear_pending_events());
-               }
-               for event in pending_events {
-                       handler.handle_event(event);
-               }
-       }
-       #[cfg(anchors)]
        /// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity.
        ///
        /// For channels featuring anchor outputs, this method will also process [`BumpTransaction`]
        /// events produced from each [`ChannelMonitor`] while there is a balance to claim onchain
        /// within each channel. As the confirmation of a commitment transaction may be critical to the
-       /// safety of funds, this method must be invoked frequently, ideally once for every chain tip
-       /// update (block connected or disconnected).
+       /// safety of funds, we recommend invoking this every 30 seconds, or lower if running in an
+       /// environment with spotty connections, like on mobile.
        ///
        /// An [`EventHandler`] may safely call back to the provider, though this shouldn't be needed in
        /// order to handle these events.
@@ -813,12 +797,8 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner, C: Deref, T: Deref, F: Deref, L
        /// [`SpendableOutputs`]: events::Event::SpendableOutputs
        /// [`BumpTransaction`]: events::Event::BumpTransaction
        fn process_pending_events<H: Deref>(&self, handler: H) where H::Target: EventHandler {
-               let mut pending_events = Vec::new();
                for monitor_state in self.monitors.read().unwrap().values() {
-                       pending_events.append(&mut monitor_state.monitor.get_and_clear_pending_events());
-               }
-               for event in pending_events {
-                       handler.handle_event(event);
+                       monitor_state.monitor.process_pending_events(&handler);
                }
        }
 }
index d3052b5fed4087f6de9ccd9dd7fc3047106fbf60..f98c0bcac8c0ef453d281b700272b8ac69dd4d06 100644 (file)
@@ -43,17 +43,14 @@ use crate::chain::{BestBlock, WatchedOutput};
 use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
 use crate::chain::transaction::{OutPoint, TransactionData};
 use crate::sign::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, WriteableEcdsaChannelSigner, SignerProvider, EntropySource};
-#[cfg(anchors)]
-use crate::chain::onchaintx::ClaimEvent;
-use crate::chain::onchaintx::OnchainTxHandler;
+use crate::chain::onchaintx::{ClaimEvent, OnchainTxHandler};
 use crate::chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput};
 use crate::chain::Filter;
 use crate::util::logger::Logger;
 use crate::util::ser::{Readable, ReadableArgs, RequiredWrapper, MaybeReadable, UpgradableRequired, Writer, Writeable, U48};
 use crate::util::byte_utils;
-use crate::events::Event;
-#[cfg(anchors)]
-use crate::events::bump_transaction::{AnchorDescriptor, HTLCDescriptor, BumpTransactionEvent};
+use crate::events::{Event, EventHandler};
+use crate::events::bump_transaction::{ChannelDerivationParameters, AnchorDescriptor, HTLCDescriptor, BumpTransactionEvent};
 
 use crate::prelude::*;
 use core::{cmp, mem};
@@ -265,10 +262,9 @@ impl_writeable_tlv_based!(HolderSignedTx, {
        (8, delayed_payment_key, required),
        (10, per_commitment_point, required),
        (12, feerate_per_kw, required),
-       (14, htlc_outputs, vec_type)
+       (14, htlc_outputs, required_vec)
 });
 
-#[cfg(anchors)]
 impl HolderSignedTx {
        fn non_dust_htlcs(&self) -> Vec<HTLCOutputInCommitment> {
                self.htlc_outputs.iter().filter_map(|(htlc, _, _)| {
@@ -542,15 +538,15 @@ impl ChannelMonitorUpdateStep {
 impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
        (0, LatestHolderCommitmentTXInfo) => {
                (0, commitment_tx, required),
-               (1, claimed_htlcs, vec_type),
-               (2, htlc_outputs, vec_type),
+               (1, claimed_htlcs, optional_vec),
+               (2, htlc_outputs, required_vec),
                (4, nondust_htlc_sources, optional_vec),
        },
        (1, LatestCounterpartyCommitmentTXInfo) => {
                (0, commitment_txid, required),
                (2, commitment_number, required),
                (4, their_per_commitment_point, required),
-               (6, htlc_outputs, vec_type),
+               (6, htlc_outputs, required_vec),
        },
        (2, PaymentPreimage) => {
                (0, payment_preimage, required),
@@ -742,11 +738,6 @@ impl Readable for IrrevocablyResolvedHTLC {
 /// You MUST ensure that no ChannelMonitors for a given channel anywhere contain out-of-date
 /// information and are actively monitoring the chain.
 ///
-/// Pending Events or updated HTLCs which have not yet been read out by
-/// get_and_clear_pending_monitor_events or get_and_clear_pending_events are serialized to disk and
-/// reloaded at deserialize-time. Thus, you must ensure that, when handling events, all events
-/// gotten are fully handled before re-serializing the new state.
-///
 /// Note that the deserializer is only implemented for (BlockHash, ChannelMonitor), which
 /// tells you the last block hash which was block_connect()ed. You MUST rescan any blocks along
 /// the "reorg path" (ie disconnecting blocks until you find a common ancestor from both the
@@ -756,7 +747,7 @@ pub struct ChannelMonitor<Signer: WriteableEcdsaChannelSigner> {
        #[cfg(test)]
        pub(crate) inner: Mutex<ChannelMonitorImpl<Signer>>,
        #[cfg(not(test))]
-       inner: Mutex<ChannelMonitorImpl<Signer>>,
+       pub(super) inner: Mutex<ChannelMonitorImpl<Signer>>,
 }
 
 #[derive(PartialEq)]
@@ -833,7 +824,8 @@ pub(crate) struct ChannelMonitorImpl<Signer: WriteableEcdsaChannelSigner> {
        // we further MUST NOT generate events during block/transaction-disconnection.
        pending_monitor_events: Vec<MonitorEvent>,
 
-       pending_events: Vec<Event>,
+       pub(super) pending_events: Vec<Event>,
+       pub(super) is_processing_pending_events: bool,
 
        // Used to track on-chain events (i.e., transactions part of channels confirmed on chain) on
        // which to take actions once they reach enough confirmations. Each entry includes the
@@ -1079,12 +1071,12 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signe
 
                write_tlv_fields!(writer, {
                        (1, self.funding_spend_confirmed, option),
-                       (3, self.htlcs_resolved_on_chain, vec_type),
-                       (5, self.pending_monitor_events, vec_type),
+                       (3, self.htlcs_resolved_on_chain, required_vec),
+                       (5, self.pending_monitor_events, required_vec),
                        (7, self.funding_spend_seen, required),
                        (9, self.counterparty_node_id, option),
                        (11, self.confirmed_commitment_tx_counterparty_output, option),
-                       (13, self.spendable_txids_confirmed, vec_type),
+                       (13, self.spendable_txids_confirmed, required_vec),
                        (15, self.counterparty_fulfilled_htlcs, required),
                });
 
@@ -1092,6 +1084,42 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signe
        }
 }
 
+macro_rules! _process_events_body {
+       ($self_opt: expr, $event_to_handle: expr, $handle_event: expr) => {
+               loop {
+                       let (pending_events, repeated_events);
+                       if let Some(us) = $self_opt {
+                               let mut inner = us.inner.lock().unwrap();
+                               if inner.is_processing_pending_events {
+                                       break;
+                               }
+                               inner.is_processing_pending_events = true;
+
+                               pending_events = inner.pending_events.clone();
+                               repeated_events = inner.get_repeated_events();
+                       } else { break; }
+                       let num_events = pending_events.len();
+
+                       for event in pending_events.into_iter().chain(repeated_events.into_iter()) {
+                               $event_to_handle = event;
+                               $handle_event;
+                       }
+
+                       if let Some(us) = $self_opt {
+                               let mut inner = us.inner.lock().unwrap();
+                               inner.pending_events.drain(..num_events);
+                               inner.is_processing_pending_events = false;
+                               if !inner.pending_events.is_empty() {
+                                       // If there's more events to process, go ahead and do so.
+                                       continue;
+                               }
+                       }
+                       break;
+               }
+       }
+}
+pub(super) use _process_events_body as process_events_body;
+
 impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
        /// For lockorder enforcement purposes, we need to have a single site which constructs the
        /// `inner` mutex, otherwise cases where we lock two monitors at the same time (eg in our
@@ -1183,6 +1211,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
                        payment_preimages: HashMap::new(),
                        pending_monitor_events: Vec::new(),
                        pending_events: Vec::new(),
+                       is_processing_pending_events: false,
 
                        onchain_events_awaiting_threshold_conf: Vec::new(),
                        outputs_to_watch,
@@ -1310,16 +1339,41 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
                self.inner.lock().unwrap().get_and_clear_pending_monitor_events()
        }
 
-       /// Gets the list of pending events which were generated by previous actions, clearing the list
-       /// in the process.
+       /// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity.
+       ///
+       /// For channels featuring anchor outputs, this method will also process [`BumpTransaction`]
+       /// events produced from each [`ChannelMonitor`] while there is a balance to claim onchain
+       /// within each channel. As the confirmation of a commitment transaction may be critical to the
+       /// safety of funds, we recommend invoking this every 30 seconds, or lower if running in an
+       /// environment with spotty connections, like on mobile.
        ///
-       /// This is called by the [`EventsProvider::process_pending_events`] implementation for
-       /// [`ChainMonitor`].
+       /// An [`EventHandler`] may safely call back to the provider, though this shouldn't be needed in
+       /// order to handle these events.
        ///
-       /// [`EventsProvider::process_pending_events`]: crate::events::EventsProvider::process_pending_events
-       /// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor
+       /// [`SpendableOutputs`]: crate::events::Event::SpendableOutputs
+       /// [`BumpTransaction`]: crate::events::Event::BumpTransaction
+       pub fn process_pending_events<H: Deref>(&self, handler: &H) where H::Target: EventHandler {
+               let mut ev;
+               process_events_body!(Some(self), ev, handler.handle_event(ev));
+       }
+
+       /// Processes any events asynchronously.
+       ///
+       /// See [`Self::process_pending_events`] for more information.
+       pub async fn process_pending_events_async<Future: core::future::Future, H: Fn(Event) -> Future>(
+               &self, handler: &H
+       ) {
+               let mut ev;
+               process_events_body!(Some(self), ev, { handler(ev).await });
+       }
+
+       #[cfg(test)]
        pub fn get_and_clear_pending_events(&self) -> Vec<Event> {
-               self.inner.lock().unwrap().get_and_clear_pending_events()
+               let mut ret = Vec::new();
+               let mut lck = self.inner.lock().unwrap();
+               mem::swap(&mut ret, &mut lck.pending_events);
+               ret.append(&mut lck.get_repeated_events());
+               ret
        }
 
        pub(crate) fn get_min_seen_secret(&self) -> u64 {
@@ -1600,7 +1654,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                        debug_assert!(htlc_input_idx_opt.is_some());
                                        BitcoinOutPoint::new(*txid, htlc_input_idx_opt.unwrap_or(0))
                                } else {
-                                       debug_assert!(!self.onchain_tx_handler.opt_anchors());
+                                       debug_assert!(!self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx());
                                        BitcoinOutPoint::new(*txid, 0)
                                }
                        } else {
@@ -2459,10 +2513,10 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                // If the channel supports anchor outputs, we'll need to emit an external
                                                // event to be consumed such that a child transaction is broadcast with a
                                                // high enough feerate for the parent commitment transaction to confirm.
-                                               if self.onchain_tx_handler.opt_anchors() {
+                                               if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
                                                        let funding_output = HolderFundingOutput::build(
                                                                self.funding_redeemscript.clone(), self.channel_value_satoshis,
-                                                               self.onchain_tx_handler.opt_anchors(),
+                                                               self.onchain_tx_handler.channel_type_features().clone(),
                                                        );
                                                        let best_block_height = self.best_block.height();
                                                        let commitment_package = PackageTemplate::build_package(
@@ -2535,11 +2589,13 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                ret
        }
 
-       pub fn get_and_clear_pending_events(&mut self) -> Vec<Event> {
-               let mut ret = Vec::new();
-               mem::swap(&mut ret, &mut self.pending_events);
-               #[cfg(anchors)]
-               for claim_event in self.onchain_tx_handler.get_and_clear_pending_claim_events().drain(..) {
+       /// Gets the set of events that are repeated regularly (e.g. those which RBF bump
+       /// transactions). We're okay if we lose these on restart as they'll be regenerated for us at
+       /// some regular interval via [`ChannelMonitor::rebroadcast_pending_claims`].
+       pub(super) fn get_repeated_events(&mut self) -> Vec<Event> {
+               let pending_claim_events = self.onchain_tx_handler.get_and_clear_pending_claim_events();
+               let mut ret = Vec::with_capacity(pending_claim_events.len());
+               for (claim_id, claim_event) in pending_claim_events {
                        match claim_event {
                                ClaimEvent::BumpCommitment {
                                        package_target_feerate_sat_per_1000_weight, commitment_tx, anchor_output_idx,
@@ -2550,12 +2606,16 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                        let commitment_tx_fee_satoshis = self.channel_value_satoshis -
                                                commitment_tx.output.iter().fold(0u64, |sum, output| sum + output.value);
                                        ret.push(Event::BumpTransaction(BumpTransactionEvent::ChannelClose {
+                                               claim_id,
                                                package_target_feerate_sat_per_1000_weight,
                                                commitment_tx,
                                                commitment_tx_fee_satoshis,
                                                anchor_descriptor: AnchorDescriptor {
-                                                       channel_keys_id: self.channel_keys_id,
-                                                       channel_value_satoshis: self.channel_value_satoshis,
+                                                       channel_derivation_parameters: ChannelDerivationParameters {
+                                                               keys_id: self.channel_keys_id,
+                                                               value_satoshis: self.channel_value_satoshis,
+                                                               transaction_parameters: self.onchain_tx_handler.channel_transaction_parameters.clone(),
+                                                       },
                                                        outpoint: BitcoinOutPoint {
                                                                txid: commitment_txid,
                                                                vout: anchor_output_idx,
@@ -2570,17 +2630,23 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                        let mut htlc_descriptors = Vec::with_capacity(htlcs.len());
                                        for htlc in htlcs {
                                                htlc_descriptors.push(HTLCDescriptor {
-                                                       channel_keys_id: self.channel_keys_id,
-                                                       channel_value_satoshis: self.channel_value_satoshis,
-                                                       channel_parameters: self.onchain_tx_handler.channel_transaction_parameters.clone(),
+                                                       channel_derivation_parameters: ChannelDerivationParameters {
+                                                               keys_id: self.channel_keys_id,
+                                                               value_satoshis: self.channel_value_satoshis,
+                                                               transaction_parameters: self.onchain_tx_handler.channel_transaction_parameters.clone(),
+                                                       },
                                                        commitment_txid: htlc.commitment_txid,
                                                        per_commitment_number: htlc.per_commitment_number,
+                                                       per_commitment_point: self.onchain_tx_handler.signer.get_per_commitment_point(
+                                                               htlc.per_commitment_number, &self.onchain_tx_handler.secp_ctx,
+                                                       ),
                                                        htlc: htlc.htlc,
                                                        preimage: htlc.preimage,
                                                        counterparty_sig: htlc.counterparty_sig,
                                                });
                                        }
                                        ret.push(Event::BumpTransaction(BumpTransactionEvent::HTLCResolution {
+                                               claim_id,
                                                target_feerate_sat_per_1000_weight,
                                                htlc_descriptors,
                                                tx_lock_time,
@@ -2651,7 +2717,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        // First, process non-htlc outputs (to_holder & to_counterparty)
                        for (idx, outp) in tx.output.iter().enumerate() {
                                if outp.script_pubkey == revokeable_p2wsh {
-                                       let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv, self.onchain_tx_handler.opt_anchors());
+                                       let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv, self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx());
                                        let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, height);
                                        claimable_outpoints.push(justice_package);
                                        to_counterparty_output_info =
@@ -2669,7 +2735,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                        return (claimable_outpoints, (commitment_txid, watch_outputs),
                                                                to_counterparty_output_info);
                                                }
-                                               let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_some());
+                                               let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), &self.onchain_tx_handler.channel_transaction_parameters.channel_type_features);
                                                let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, height);
                                                claimable_outpoints.push(justice_package);
                                        }
@@ -2787,13 +2853,13 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                        CounterpartyOfferedHTLCOutput::build(*per_commitment_point,
                                                                self.counterparty_commitment_params.counterparty_delayed_payment_base_key,
                                                                self.counterparty_commitment_params.counterparty_htlc_base_key,
-                                                               preimage.unwrap(), htlc.clone(), self.onchain_tx_handler.opt_anchors()))
+                                                               preimage.unwrap(), htlc.clone(), self.onchain_tx_handler.channel_type_features().clone()))
                                        } else {
                                                PackageSolvingData::CounterpartyReceivedHTLCOutput(
                                                        CounterpartyReceivedHTLCOutput::build(*per_commitment_point,
                                                                self.counterparty_commitment_params.counterparty_delayed_payment_base_key,
                                                                self.counterparty_commitment_params.counterparty_htlc_base_key,
-                                                               htlc.clone(), self.onchain_tx_handler.opt_anchors()))
+                                                               htlc.clone(), self.onchain_tx_handler.channel_type_features().clone()))
                                        };
                                        let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry, 0);
                                        claimable_outpoints.push(counterparty_package);
@@ -2864,7 +2930,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        if let Some(transaction_output_index) = htlc.transaction_output_index {
                                let htlc_output = if htlc.offered {
                                        let htlc_output = HolderHTLCOutput::build_offered(
-                                               htlc.amount_msat, htlc.cltv_expiry, self.onchain_tx_handler.opt_anchors()
+                                               htlc.amount_msat, htlc.cltv_expiry, self.onchain_tx_handler.channel_type_features().clone()
                                        );
                                        htlc_output
                                } else {
@@ -2875,7 +2941,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                continue;
                                        };
                                        let htlc_output = HolderHTLCOutput::build_accepted(
-                                               payment_preimage, htlc.amount_msat, self.onchain_tx_handler.opt_anchors()
+                                               payment_preimage, htlc.amount_msat, self.onchain_tx_handler.channel_type_features().clone()
                                        );
                                        htlc_output
                                };
@@ -2959,7 +3025,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                let mut holder_transactions = vec![commitment_tx];
                // When anchor outputs are present, the HTLC transactions are only valid once the commitment
                // transaction confirms.
-               if self.onchain_tx_handler.opt_anchors() {
+               if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
                        return holder_transactions;
                }
                for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
@@ -2997,7 +3063,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                let mut holder_transactions = vec![commitment_tx];
                // When anchor outputs are present, the HTLC transactions are only final once the commitment
                // transaction confirms due to the CSV 1 encumberance.
-               if self.onchain_tx_handler.opt_anchors() {
+               if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
                        return holder_transactions;
                }
                for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
@@ -3221,7 +3287,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
 
                let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
                if should_broadcast {
-                       let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.opt_anchors());
+                       let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.channel_type_features().clone());
                        let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), self.best_block.height());
                        claimable_outpoints.push(commitment_package);
                        self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
@@ -3230,7 +3296,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        // We can't broadcast our HTLC transactions while the commitment transaction is
                        // unconfirmed. We'll delay doing so until we detect the confirmed commitment in
                        // `transactions_confirmed`.
-                       if !self.onchain_tx_handler.opt_anchors() {
+                       if !self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
                                // Because we're broadcasting a commitment transaction, we should construct the package
                                // assuming it gets confirmed in the next block. Sadly, we have code which considers
                                // "not yet confirmed" things as discardable, so we cannot do that here.
@@ -4054,12 +4120,12 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
                let mut counterparty_fulfilled_htlcs = Some(HashMap::new());
                read_tlv_fields!(reader, {
                        (1, funding_spend_confirmed, option),
-                       (3, htlcs_resolved_on_chain, vec_type),
-                       (5, pending_monitor_events, vec_type),
+                       (3, htlcs_resolved_on_chain, optional_vec),
+                       (5, pending_monitor_events, optional_vec),
                        (7, funding_spend_seen, option),
                        (9, counterparty_node_id, option),
                        (11, confirmed_commitment_tx_counterparty_output, option),
-                       (13, spendable_txids_confirmed, vec_type),
+                       (13, spendable_txids_confirmed, optional_vec),
                        (15, counterparty_fulfilled_htlcs, option),
                });
 
@@ -4099,6 +4165,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
                        payment_preimages,
                        pending_monitor_events: pending_monitor_events.unwrap(),
                        pending_events,
+                       is_processing_pending_events: false,
 
                        onchain_events_awaiting_threshold_conf,
                        outputs_to_watch,
@@ -4158,6 +4225,7 @@ mod tests {
        use crate::sync::{Arc, Mutex};
        use crate::io;
        use bitcoin::{PackedLockTime, Sequence, Witness};
+       use crate::ln::features::ChannelTypeFeatures;
        use crate::prelude::*;
 
        fn do_test_funding_spend_refuses_updates(use_local_txn: bool) {
@@ -4331,8 +4399,7 @@ mod tests {
                                selected_contest_delay: 67,
                        }),
                        funding_outpoint: Some(funding_outpoint),
-                       opt_anchors: None,
-                       opt_non_zero_fee_anchors: None,
+                       channel_type_features: ChannelTypeFeatures::only_static_remote_key()
                };
                // Prune with one old state and a holder commitment tx holding a few overlaps with the
                // old state.
@@ -4448,7 +4515,7 @@ mod tests {
                let txid = Txid::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap();
 
                // Justice tx with 1 to_holder, 2 revoked offered HTLCs, 1 revoked received HTLCs
-               for &opt_anchors in [false, true].iter() {
+               for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() {
                        let mut claim_tx = Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() };
                        let mut sum_actual_sigs = 0;
                        for i in 0..4 {
@@ -4467,12 +4534,12 @@ mod tests {
                                value: 0,
                        });
                        let base_weight = claim_tx.weight();
-                       let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, weight_revoked_offered_htlc(opt_anchors), weight_revoked_offered_htlc(opt_anchors), weight_revoked_received_htlc(opt_anchors)];
+                       let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, weight_revoked_offered_htlc(channel_type_features), weight_revoked_offered_htlc(channel_type_features), weight_revoked_received_htlc(channel_type_features)];
                        let mut inputs_total_weight = 2; // count segwit flags
                        {
                                let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx);
                                for (idx, inp) in inputs_weight.iter().enumerate() {
-                                       sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors);
+                                       sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, channel_type_features);
                                        inputs_total_weight += inp;
                                }
                        }
@@ -4480,7 +4547,7 @@ mod tests {
                }
 
                // Claim tx with 1 offered HTLCs, 3 received HTLCs
-               for &opt_anchors in [false, true].iter() {
+               for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() {
                        let mut claim_tx = Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() };
                        let mut sum_actual_sigs = 0;
                        for i in 0..4 {
@@ -4499,12 +4566,12 @@ mod tests {
                                value: 0,
                        });
                        let base_weight = claim_tx.weight();
-                       let inputs_weight = vec![weight_offered_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors)];
+                       let inputs_weight = vec![weight_offered_htlc(channel_type_features), weight_received_htlc(channel_type_features), weight_received_htlc(channel_type_features), weight_received_htlc(channel_type_features)];
                        let mut inputs_total_weight = 2; // count segwit flags
                        {
                                let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx);
                                for (idx, inp) in inputs_weight.iter().enumerate() {
-                                       sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors);
+                                       sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, channel_type_features);
                                        inputs_total_weight += inp;
                                }
                        }
@@ -4512,7 +4579,7 @@ mod tests {
                }
 
                // Justice tx with 1 revoked HTLC-Success tx output
-               for &opt_anchors in [false, true].iter() {
+               for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() {
                        let mut claim_tx = Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() };
                        let mut sum_actual_sigs = 0;
                        claim_tx.input.push(TxIn {
@@ -4534,7 +4601,7 @@ mod tests {
                        {
                                let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx);
                                for (idx, inp) in inputs_weight.iter().enumerate() {
-                                       sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors);
+                                       sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, channel_type_features);
                                        inputs_total_weight += inp;
                                }
                        }
index abd888b3cf28bc12847e149f0dae1d59a2d4aecb..236b10a7b19d1288b5d74f784d066c2a8bacc169 100644 (file)
@@ -389,3 +389,9 @@ where
                self.1.block_disconnected(header, height);
        }
 }
+
+/// A unique identifier to track each pending output claim within a [`ChannelMonitor`].
+///
+/// This is not exported to bindings users as we just use [u8; 32] directly.
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ClaimId(pub [u8; 32]);
index 45968c57e537077c2d583a24fe9702300d19a8cb..6ac4973a74441de88461576d26c9f8b69545d1c8 100644 (file)
 //! OnchainTxHandler objects are fully-part of ChannelMonitor and encapsulates all
 //! building, tracking, bumping and notifications functions.
 
-#[cfg(anchors)]
 use bitcoin::PackedLockTime;
 use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
 use bitcoin::blockdata::script::Script;
-
+use bitcoin::hashes::{Hash, HashEngine};
+use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::hash_types::{Txid, BlockHash};
-
 use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
 use bitcoin::secp256k1;
 
+use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
 use crate::sign::{ChannelSigner, EntropySource, SignerProvider};
 use crate::ln::msgs::DecodeError;
 use crate::ln::PaymentPreimage;
-#[cfg(anchors)]
-use crate::ln::chan_utils::{self, HTLCOutputInCommitment};
-use crate::ln::chan_utils::{ChannelTransactionParameters, HolderCommitmentTransaction};
-#[cfg(anchors)]
-use crate::chain::chaininterface::ConfirmationTarget;
-use crate::chain::chaininterface::{FeeEstimator, BroadcasterInterface, LowerBoundedFeeEstimator};
+use crate::ln::chan_utils::{self, ChannelTransactionParameters, HTLCOutputInCommitment, HolderCommitmentTransaction};
+use crate::chain::ClaimId;
+use crate::chain::chaininterface::{ConfirmationTarget, FeeEstimator, BroadcasterInterface, LowerBoundedFeeEstimator};
 use crate::chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER};
 use crate::sign::WriteableEcdsaChannelSigner;
-#[cfg(anchors)]
-use crate::chain::package::PackageSolvingData;
-use crate::chain::package::PackageTemplate;
+use crate::chain::package::{PackageSolvingData, PackageTemplate};
 use crate::util::logger::Logger;
 use crate::util::ser::{Readable, ReadableArgs, MaybeReadable, UpgradableRequired, Writer, Writeable, VecWriter};
 
@@ -46,9 +41,8 @@ use alloc::collections::BTreeMap;
 use core::cmp;
 use core::ops::Deref;
 use core::mem::replace;
-#[cfg(anchors)]
 use core::mem::swap;
-use bitcoin::hashes::Hash;
+use crate::ln::features::ChannelTypeFeatures;
 
 const MAX_ALLOC_SIZE: usize = 64*1024;
 
@@ -83,7 +77,7 @@ enum OnchainEvent {
        /// transaction has met [`ANTI_REORG_DELAY`] confirmations, we consider it final and remove the
        /// pending request.
        Claim {
-               package_id: PackageID,
+               claim_id: ClaimId,
        },
        /// The counterparty has claimed an outpoint from one of our pending requests through a
        /// different transaction than ours. If our transaction was attempting to claim multiple
@@ -126,7 +120,7 @@ impl MaybeReadable for OnchainEventEntry {
 
 impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
        (0, Claim) => {
-               (0, package_id, required),
+               (0, claim_id, required),
        },
        (1, ContentiousOutpoint) => {
                (0, package, required),
@@ -177,7 +171,6 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
        }
 }
 
-#[cfg(anchors)]
 /// The claim commonly referred to as the pre-signed second-stage HTLC transaction.
 pub(crate) struct ExternalHTLCClaim {
        pub(crate) commitment_txid: Txid,
@@ -189,7 +182,6 @@ pub(crate) struct ExternalHTLCClaim {
 
 // Represents the different types of claims for which events are yielded externally to satisfy said
 // claims.
-#[cfg(anchors)]
 pub(crate) enum ClaimEvent {
        /// Event yielded to signal that the commitment transaction fee must be bumped to claim any
        /// encumbered funds and proceed to HTLC resolution, if any HTLCs exist.
@@ -212,15 +204,11 @@ pub(crate) enum ClaimEvent {
 pub(crate) enum OnchainClaim {
        /// A finalized transaction pending confirmation spending the output to claim.
        Tx(Transaction),
-       #[cfg(anchors)]
        /// An event yielded externally to signal additional inputs must be added to a transaction
        /// pending confirmation spending the output to claim.
        Event(ClaimEvent),
 }
 
-/// An internal identifier to track pending package claims within the `OnchainTxHandler`.
-type PackageID = [u8; 32];
-
 /// OnchainTxHandler receives claiming requests, aggregates them if it's sound, broadcast and
 /// do RBF bumping if possible.
 pub struct OnchainTxHandler<ChannelSigner: WriteableEcdsaChannelSigner> {
@@ -248,13 +236,13 @@ pub struct OnchainTxHandler<ChannelSigner: WriteableEcdsaChannelSigner> {
        // us and is immutable until all outpoint of the claimable set are post-anti-reorg-delay solved.
        // Entry is cache of elements need to generate a bumped claiming transaction (see ClaimTxBumpMaterial)
        #[cfg(test)] // Used in functional_test to verify sanitization
-       pub(crate) pending_claim_requests: HashMap<PackageID, PackageTemplate>,
+       pub(crate) pending_claim_requests: HashMap<ClaimId, PackageTemplate>,
        #[cfg(not(test))]
-       pending_claim_requests: HashMap<PackageID, PackageTemplate>,
+       pending_claim_requests: HashMap<ClaimId, PackageTemplate>,
 
        // Used to track external events that need to be forwarded to the `ChainMonitor`. This `Vec`
        // essentially acts as an insertion-ordered `HashMap` â€“ there should only ever be one occurrence
-       // of a `PackageID`, which tracks its latest `ClaimEvent`, i.e., if a pending claim exists, and
+       // of a `ClaimId`, which tracks its latest `ClaimEvent`, i.e., if a pending claim exists, and
        // a new block has been connected, resulting in a new claim, the previous will be replaced with
        // the new.
        //
@@ -262,8 +250,7 @@ pub struct OnchainTxHandler<ChannelSigner: WriteableEcdsaChannelSigner> {
        //      - A channel has been force closed by broadcasting the holder's latest commitment transaction
        //      - A block being connected/disconnected
        //      - Learning the preimage for an HTLC we can claim onchain
-       #[cfg(anchors)]
-       pending_claim_events: Vec<(PackageID, ClaimEvent)>,
+       pending_claim_events: Vec<(ClaimId, ClaimEvent)>,
 
        // Used to link outpoints claimed in a connected block to a pending claim request. The keys
        // represent the outpoints that our `ChannelMonitor` has detected we have keys/scripts to
@@ -272,9 +259,9 @@ pub struct OnchainTxHandler<ChannelSigner: WriteableEcdsaChannelSigner> {
        // [`ANTI_REORG_DELAY`]. The initial confirmation block height is used to remove the entry if
        // the block gets disconnected.
        #[cfg(test)] // Used in functional_test to verify sanitization
-       pub claimable_outpoints: HashMap<BitcoinOutPoint, (PackageID, u32)>,
+       pub claimable_outpoints: HashMap<BitcoinOutPoint, (ClaimId, u32)>,
        #[cfg(not(test))]
-       claimable_outpoints: HashMap<BitcoinOutPoint, (PackageID, u32)>,
+       claimable_outpoints: HashMap<BitcoinOutPoint, (ClaimId, u32)>,
 
        locktimed_packages: BTreeMap<u32, Vec<PackageTemplate>>,
 
@@ -439,7 +426,6 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
                        locktimed_packages,
                        pending_claim_requests,
                        onchain_events_awaiting_threshold_conf,
-                       #[cfg(anchors)]
                        pending_claim_events: Vec::new(),
                        secp_ctx,
                })
@@ -460,7 +446,6 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                        claimable_outpoints: HashMap::new(),
                        locktimed_packages: BTreeMap::new(),
                        onchain_events_awaiting_threshold_conf: Vec::new(),
-                       #[cfg(anchors)]
                        pending_claim_events: Vec::new(),
                        secp_ctx,
                }
@@ -474,11 +459,10 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                self.holder_commitment.to_broadcaster_value_sat()
        }
 
-       #[cfg(anchors)]
-       pub(crate) fn get_and_clear_pending_claim_events(&mut self) -> Vec<ClaimEvent> {
+       pub(crate) fn get_and_clear_pending_claim_events(&mut self) -> Vec<(ClaimId, ClaimEvent)> {
                let mut events = Vec::new();
                swap(&mut events, &mut self.pending_claim_events);
-               events.into_iter().map(|(_, event)| event).collect()
+               events
        }
 
        /// Triggers rebroadcasts/fee-bumps of pending claims from a force-closed channel. This is
@@ -496,16 +480,16 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                L::Target: Logger,
        {
                let mut bump_requests = Vec::with_capacity(self.pending_claim_requests.len());
-               for (package_id, request) in self.pending_claim_requests.iter() {
+               for (claim_id, request) in self.pending_claim_requests.iter() {
                        let inputs = request.outpoints();
                        log_info!(logger, "Triggering rebroadcast/fee-bump for request with inputs {:?}", inputs);
-                       bump_requests.push((*package_id, request.clone()));
+                       bump_requests.push((*claim_id, request.clone()));
                }
-               for (package_id, request) in bump_requests {
+               for (claim_id, request) in bump_requests {
                        self.generate_claim(current_height, &request, false /* force_feerate_bump */, fee_estimator, logger)
                                .map(|(_, new_feerate, claim)| {
                                        let mut bumped_feerate = false;
-                                       if let Some(mut_request) = self.pending_claim_requests.get_mut(&package_id) {
+                                       if let Some(mut_request) = self.pending_claim_requests.get_mut(&claim_id) {
                                                bumped_feerate = request.previous_feerate() > new_feerate;
                                                mut_request.set_feerate(new_feerate);
                                        }
@@ -515,7 +499,6 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                        log_info!(logger, "{} onchain {}", log_start, log_tx!(tx));
                                                        broadcaster.broadcast_transactions(&[&tx]);
                                                },
-                                               #[cfg(anchors)]
                                                OnchainClaim::Event(event) => {
                                                        let log_start = if bumped_feerate { "Yielding fee-bumped" } else { "Replaying" };
                                                        log_info!(logger, "{} onchain event to spend inputs {:?}", log_start,
@@ -523,11 +506,11 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                        #[cfg(debug_assertions)] {
                                                                debug_assert!(request.requires_external_funding());
                                                                let num_existing = self.pending_claim_events.iter()
-                                                                       .filter(|entry| entry.0 == package_id).count();
+                                                                       .filter(|entry| entry.0 == claim_id).count();
                                                                assert!(num_existing == 0 || num_existing == 1);
                                                        }
-                                                       self.pending_claim_events.retain(|event| event.0 != package_id);
-                                                       self.pending_claim_events.push((package_id, event));
+                                                       self.pending_claim_events.retain(|event| event.0 != claim_id);
+                                                       self.pending_claim_events.push((claim_id, event));
                                                }
                                        }
                                });
@@ -564,12 +547,12 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                // transaction is reorged out.
                let mut all_inputs_have_confirmed_spend = true;
                for outpoint in request_outpoints.iter() {
-                       if let Some((request_package_id, _)) = self.claimable_outpoints.get(*outpoint) {
+                       if let Some((request_claim_id, _)) = self.claimable_outpoints.get(*outpoint) {
                                // We check for outpoint spends within claims individually rather than as a set
                                // since requests can have outpoints split off.
                                if !self.onchain_events_awaiting_threshold_conf.iter()
-                                       .any(|event_entry| if let OnchainEvent::Claim { package_id } = event_entry.event {
-                                               *request_package_id == package_id
+                                       .any(|event_entry| if let OnchainEvent::Claim { claim_id } = event_entry.event {
+                                               *request_claim_id == claim_id
                                        } else {
                                                // The onchain event is not a claim, keep seeking until we find one.
                                                false
@@ -592,25 +575,22 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                // didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
                let new_timer = cached_request.get_height_timer(cur_height);
                if cached_request.is_malleable() {
-                       #[cfg(anchors)]
-                       { // Attributes are not allowed on if expressions on our current MSRV of 1.41.
-                               if cached_request.requires_external_funding() {
-                                       let target_feerate_sat_per_1000_weight = cached_request.compute_package_feerate(
-                                               fee_estimator, ConfirmationTarget::HighPriority, force_feerate_bump
-                                       );
-                                       if let Some(htlcs) = cached_request.construct_malleable_package_with_external_funding(self) {
-                                               return Some((
-                                                       new_timer,
-                                                       target_feerate_sat_per_1000_weight as u64,
-                                                       OnchainClaim::Event(ClaimEvent::BumpHTLC {
-                                                               target_feerate_sat_per_1000_weight,
-                                                               htlcs,
-                                                               tx_lock_time: PackedLockTime(cached_request.package_locktime(cur_height)),
-                                                       }),
-                                               ));
-                                       } else {
-                                               return None;
-                                       }
+                       if cached_request.requires_external_funding() {
+                               let target_feerate_sat_per_1000_weight = cached_request.compute_package_feerate(
+                                       fee_estimator, ConfirmationTarget::HighPriority, force_feerate_bump
+                               );
+                               if let Some(htlcs) = cached_request.construct_malleable_package_with_external_funding(self) {
+                                       return Some((
+                                               new_timer,
+                                               target_feerate_sat_per_1000_weight as u64,
+                                               OnchainClaim::Event(ClaimEvent::BumpHTLC {
+                                                       target_feerate_sat_per_1000_weight,
+                                                       htlcs,
+                                                       tx_lock_time: PackedLockTime(cached_request.package_locktime(cur_height)),
+                                               }),
+                                       ));
+                               } else {
+                                       return None;
                                }
                        }
 
@@ -632,9 +612,6 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                        // Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
                        // packages may support fee bumping through Child-Pays-For-Parent, indicated by those
                        // which require external funding.
-                       #[cfg(not(anchors))]
-                       let inputs = cached_request.inputs();
-                       #[cfg(anchors)]
                        let mut inputs = cached_request.inputs();
                        debug_assert_eq!(inputs.len(), 1);
                        let tx = match cached_request.finalize_untractable_package(self, logger) {
@@ -644,13 +621,28 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                        if !cached_request.requires_external_funding() {
                                return Some((new_timer, 0, OnchainClaim::Tx(tx)));
                        }
-                       #[cfg(anchors)]
                        return inputs.find_map(|input| match input {
                                // Commitment inputs with anchors support are the only untractable inputs supported
                                // thus far that require external funding.
-                               PackageSolvingData::HolderFundingOutput(..) => {
+                               PackageSolvingData::HolderFundingOutput(output) => {
                                        debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
                                                "Holder commitment transaction mismatch");
+
+                                       let conf_target = ConfirmationTarget::HighPriority;
+                                       let package_target_feerate_sat_per_1000_weight = cached_request
+                                               .compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
+                                       if let Some(input_amount_sat) = output.funding_amount {
+                                               let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
+                                               let commitment_tx_feerate_sat_per_1000_weight =
+                                                       compute_feerate_sat_per_1000_weight(fee_sat, tx.weight() as u64);
+                                               if commitment_tx_feerate_sat_per_1000_weight >= package_target_feerate_sat_per_1000_weight {
+                                                       log_debug!(logger, "Pre-signed {} already has feerate {} sat/kW above required {} sat/kW",
+                                                               log_tx!(tx), commitment_tx_feerate_sat_per_1000_weight,
+                                                               package_target_feerate_sat_per_1000_weight);
+                                                       return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
+                                               }
+                                       }
+
                                        // We'll locate an anchor output we can spend within the commitment transaction.
                                        let funding_pubkey = &self.channel_transaction_parameters.holder_pubkeys.funding_pubkey;
                                        match chan_utils::get_anchor_output(&tx, funding_pubkey) {
@@ -658,9 +650,6 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                Some((idx, _)) => {
                                                        // TODO: Use a lower confirmation target when both our and the
                                                        // counterparty's latest commitment don't have any HTLCs present.
-                                                       let conf_target = ConfirmationTarget::HighPriority;
-                                                       let package_target_feerate_sat_per_1000_weight = cached_request
-                                                               .compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
                                                        Some((
                                                                new_timer,
                                                                package_target_feerate_sat_per_1000_weight as u64,
@@ -764,39 +753,47 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                        ) {
                                req.set_timer(new_timer);
                                req.set_feerate(new_feerate);
-                               let package_id = match claim {
+                               // Once a pending claim has an id assigned, it remains fixed until the claim is
+                               // satisfied, regardless of whether the claim switches between different variants of
+                               // `OnchainClaim`.
+                               let claim_id = match claim {
                                        OnchainClaim::Tx(tx) => {
                                                log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
                                                broadcaster.broadcast_transactions(&[&tx]);
-                                               tx.txid().into_inner()
+                                               ClaimId(tx.txid().into_inner())
                                        },
-                                       #[cfg(anchors)]
                                        OnchainClaim::Event(claim_event) => {
                                                log_info!(logger, "Yielding onchain event to spend inputs {:?}", req.outpoints());
-                                               let package_id = match claim_event {
-                                                       ClaimEvent::BumpCommitment { ref commitment_tx, .. } => commitment_tx.txid().into_inner(),
+                                               let claim_id = match claim_event {
+                                                       ClaimEvent::BumpCommitment { ref commitment_tx, .. } =>
+                                                               // For commitment claims, we can just use their txid as it should
+                                                               // already be unique.
+                                                               ClaimId(commitment_tx.txid().into_inner()),
                                                        ClaimEvent::BumpHTLC { ref htlcs, .. } => {
-                                                               // Use the same construction as a lightning channel id to generate
-                                                               // the package id for this request based on the first HTLC. It
-                                                               // doesn't matter what we use as long as it's unique per request.
-                                                               let mut package_id = [0; 32];
-                                                               package_id[..].copy_from_slice(&htlcs[0].commitment_txid[..]);
-                                                               let htlc_output_index = htlcs[0].htlc.transaction_output_index.unwrap();
-                                                               package_id[30] ^= ((htlc_output_index >> 8) & 0xff) as u8;
-                                                               package_id[31] ^= ((htlc_output_index >> 0) & 0xff) as u8;
-                                                               package_id
+                                                               // For HTLC claims, commit to the entire set of HTLC outputs to
+                                                               // claim, which will always be unique per request. Once a claim ID
+                                                               // is generated, it is assigned and remains unchanged, even if the
+                                                               // underlying set of HTLCs changes.
+                                                               let mut engine = Sha256::engine();
+                                                               for htlc in htlcs {
+                                                                       engine.input(&htlc.commitment_txid.into_inner());
+                                                                       engine.input(&htlc.htlc.transaction_output_index.unwrap().to_be_bytes());
+                                                               }
+                                                               ClaimId(Sha256::from_engine(engine).into_inner())
                                                        },
                                                };
-                                               debug_assert_eq!(self.pending_claim_events.iter().filter(|entry| entry.0 == package_id).count(), 0);
-                                               self.pending_claim_events.push((package_id, claim_event));
-                                               package_id
+                                               debug_assert!(self.pending_claim_requests.get(&claim_id).is_none());
+                                               debug_assert_eq!(self.pending_claim_events.iter().filter(|entry| entry.0 == claim_id).count(), 0);
+                                               self.pending_claim_events.push((claim_id, claim_event));
+                                               claim_id
                                        },
                                };
+                               debug_assert!(self.pending_claim_requests.get(&claim_id).is_none());
                                for k in req.outpoints() {
                                        log_info!(logger, "Registering claiming request for {}:{}", k.txid, k.vout);
-                                       self.claimable_outpoints.insert(k.clone(), (package_id, conf_height));
+                                       self.claimable_outpoints.insert(k.clone(), (claim_id, conf_height));
                                }
-                               self.pending_claim_requests.insert(package_id, req);
+                               self.pending_claim_requests.insert(claim_id, req);
                        }
                }
        }
@@ -823,9 +820,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                        // Scan all input to verify is one of the outpoint spent is of interest for us
                        let mut claimed_outputs_material = Vec::new();
                        for inp in &tx.input {
-                               if let Some((package_id, _)) = self.claimable_outpoints.get(&inp.previous_output) {
+                               if let Some((claim_id, _)) = self.claimable_outpoints.get(&inp.previous_output) {
                                        // If outpoint has claim request pending on it...
-                                       if let Some(request) = self.pending_claim_requests.get_mut(package_id) {
+                                       if let Some(request) = self.pending_claim_requests.get_mut(claim_id) {
                                                //... we need to verify equality between transaction outpoints and claim request
                                                // outpoints to know if transaction is the original claim or a bumped one issued
                                                // by us.
@@ -845,7 +842,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                                        txid: tx.txid(),
                                                                        height: conf_height,
                                                                        block_hash: Some(conf_hash),
-                                                                       event: OnchainEvent::Claim { package_id: *package_id }
+                                                                       event: OnchainEvent::Claim { claim_id: *claim_id }
                                                                };
                                                                if !self.onchain_events_awaiting_threshold_conf.contains(&entry) {
                                                                        self.onchain_events_awaiting_threshold_conf.push(entry);
@@ -872,21 +869,19 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                        }
                                                        //TODO: recompute soonest_timelock to avoid wasting a bit on fees
                                                        if at_least_one_drop {
-                                                               bump_candidates.insert(*package_id, request.clone());
+                                                               bump_candidates.insert(*claim_id, request.clone());
                                                                // If we have any pending claim events for the request being updated
                                                                // that have yet to be consumed, we'll remove them since they will
                                                                // end up producing an invalid transaction by double spending
                                                                // input(s) that already have a confirmed spend. If such spend is
                                                                // reorged out of the chain, then we'll attempt to re-spend the
                                                                // inputs once we see it.
-                                                               #[cfg(anchors)] {
-                                                                       #[cfg(debug_assertions)] {
-                                                                               let existing = self.pending_claim_events.iter()
-                                                                                       .filter(|entry| entry.0 == *package_id).count();
-                                                                               assert!(existing == 0 || existing == 1);
-                                                                       }
-                                                                       self.pending_claim_events.retain(|entry| entry.0 != *package_id);
+                                                               #[cfg(debug_assertions)] {
+                                                                       let existing = self.pending_claim_events.iter()
+                                                                               .filter(|entry| entry.0 == *claim_id).count();
+                                                                       assert!(existing == 0 || existing == 1);
                                                                }
+                                                               self.pending_claim_events.retain(|entry| entry.0 != *claim_id);
                                                        }
                                                }
                                                break; //No need to iterate further, either tx is our or their
@@ -914,23 +909,21 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                for entry in onchain_events_awaiting_threshold_conf {
                        if entry.has_reached_confirmation_threshold(cur_height) {
                                match entry.event {
-                                       OnchainEvent::Claim { package_id } => {
+                                       OnchainEvent::Claim { claim_id } => {
                                                // We may remove a whole set of claim outpoints here, as these one may have
                                                // been aggregated in a single tx and claimed so atomically
-                                               if let Some(request) = self.pending_claim_requests.remove(&package_id) {
+                                               if let Some(request) = self.pending_claim_requests.remove(&claim_id) {
                                                        for outpoint in request.outpoints() {
                                                                log_debug!(logger, "Removing claim tracking for {} due to maturation of claim package {}.",
-                                                                       outpoint, log_bytes!(package_id));
+                                                                       outpoint, log_bytes!(claim_id.0));
                                                                self.claimable_outpoints.remove(outpoint);
                                                        }
-                                                       #[cfg(anchors)] {
-                                                               #[cfg(debug_assertions)] {
-                                                                       let num_existing = self.pending_claim_events.iter()
-                                                                               .filter(|entry| entry.0 == package_id).count();
-                                                                       assert!(num_existing == 0 || num_existing == 1);
-                                                               }
-                                                               self.pending_claim_events.retain(|(id, _)| *id != package_id);
+                                                       #[cfg(debug_assertions)] {
+                                                               let num_existing = self.pending_claim_events.iter()
+                                                                       .filter(|entry| entry.0 == claim_id).count();
+                                                               assert!(num_existing == 0 || num_existing == 1);
                                                        }
+                                                       self.pending_claim_events.retain(|(id, _)| *id != claim_id);
                                                }
                                        },
                                        OnchainEvent::ContentiousOutpoint { package } => {
@@ -945,15 +938,15 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                }
 
                // Check if any pending claim request must be rescheduled
-               for (package_id, request) in self.pending_claim_requests.iter() {
+               for (claim_id, request) in self.pending_claim_requests.iter() {
                        if cur_height >= request.timer() {
-                               bump_candidates.insert(*package_id, request.clone());
+                               bump_candidates.insert(*claim_id, request.clone());
                        }
                }
 
                // Build, bump and rebroadcast tx accordingly
                log_trace!(logger, "Bumping {} candidates", bump_candidates.len());
-               for (package_id, request) in bump_candidates.iter() {
+               for (claim_id, request) in bump_candidates.iter() {
                        if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
                                cur_height, &request, true /* force_feerate_bump */, &*fee_estimator, &*logger,
                        ) {
@@ -962,19 +955,18 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx));
                                                broadcaster.broadcast_transactions(&[&bump_tx]);
                                        },
-                                       #[cfg(anchors)]
                                        OnchainClaim::Event(claim_event) => {
                                                log_info!(logger, "Yielding RBF-bumped onchain event to spend inputs {:?}", request.outpoints());
                                                #[cfg(debug_assertions)] {
                                                        let num_existing = self.pending_claim_events.iter().
-                                                               filter(|entry| entry.0 == *package_id).count();
+                                                               filter(|entry| entry.0 == *claim_id).count();
                                                        assert!(num_existing == 0 || num_existing == 1);
                                                }
-                                               self.pending_claim_events.retain(|event| event.0 != *package_id);
-                                               self.pending_claim_events.push((*package_id, claim_event));
+                                               self.pending_claim_events.retain(|event| event.0 != *claim_id);
+                                               self.pending_claim_events.push((*claim_id, claim_event));
                                        },
                                }
-                               if let Some(request) = self.pending_claim_requests.get_mut(package_id) {
+                               if let Some(request) = self.pending_claim_requests.get_mut(claim_id) {
                                        request.set_timer(new_timer);
                                        request.set_feerate(new_feerate);
                                }
@@ -1035,7 +1027,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                self.onchain_events_awaiting_threshold_conf.push(entry);
                        }
                }
-               for ((_package_id, _), ref mut request) in bump_candidates.iter_mut() {
+               for ((_claim_id, _), ref mut request) in bump_candidates.iter_mut() {
                        // `height` is the height being disconnected, so our `current_height` is 1 lower.
                        let current_height = height - 1;
                        if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
@@ -1048,16 +1040,15 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
                                                broadcaster.broadcast_transactions(&[&bump_tx]);
                                        },
-                                       #[cfg(anchors)]
                                        OnchainClaim::Event(claim_event) => {
                                                log_info!(logger, "Yielding onchain event after reorg to spend inputs {:?}", request.outpoints());
                                                #[cfg(debug_assertions)] {
                                                        let num_existing = self.pending_claim_events.iter()
-                                                               .filter(|entry| entry.0 == *_package_id).count();
+                                                               .filter(|entry| entry.0 == *_claim_id).count();
                                                        assert!(num_existing == 0 || num_existing == 1);
                                                }
-                                               self.pending_claim_events.retain(|event| event.0 != *_package_id);
-                                               self.pending_claim_events.push((*_package_id, claim_event));
+                                               self.pending_claim_events.retain(|event| event.0 != *_claim_id);
+                                               self.pending_claim_events.push((*_claim_id, claim_event));
                                        },
                                }
                        }
@@ -1130,7 +1121,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
        }
 
        //TODO: getting lastest holder transactions should be infallible and result in us "force-closing the channel", but we may
-       // have empty holder commitment transaction if a ChannelMonitor is asked to force-close just after Channel::get_outbound_funding_created,
+       // have empty holder commitment transaction if a ChannelMonitor is asked to force-close just after OutboundV1Channel::get_funding_created,
        // before providing a initial commitment transaction. For outbound channel, init ChannelMonitor at Channel::funding_signed, there is nothing
        // to monitor before.
        pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction {
@@ -1178,7 +1169,6 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                htlc_tx
        }
 
-       #[cfg(anchors)]
        pub(crate) fn generate_external_htlc_claim(
                &self, outp: &::bitcoin::OutPoint, preimage: &Option<PaymentPreimage>
        ) -> Option<ExternalHTLCClaim> {
@@ -1209,8 +1199,8 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                        .or_else(|| self.prev_holder_commitment.as_ref().map(|c| find_htlc(c)).flatten())
        }
 
-       pub(crate) fn opt_anchors(&self) -> bool {
-               self.channel_transaction_parameters.opt_anchors.is_some()
+       pub(crate) fn channel_type_features(&self) -> &ChannelTypeFeatures {
+               &self.channel_transaction_parameters.channel_type_features
        }
 
        #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
index 4604a164cd634534169e46f0df40670f346172c3..b66a2f70d3369f4aff6e012025b3e995d6918a9e 100644 (file)
@@ -26,52 +26,74 @@ use crate::ln::chan_utils;
 use crate::ln::msgs::DecodeError;
 use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
 use crate::sign::WriteableEcdsaChannelSigner;
-#[cfg(anchors)]
-use crate::chain::onchaintx::ExternalHTLCClaim;
-use crate::chain::onchaintx::OnchainTxHandler;
+use crate::chain::onchaintx::{ExternalHTLCClaim, OnchainTxHandler};
 use crate::util::logger::Logger;
-use crate::util::ser::{Readable, Writer, Writeable};
+use crate::util::ser::{Readable, Writer, Writeable, RequiredWrapper};
 
 use crate::io;
 use crate::prelude::*;
 use core::cmp;
-#[cfg(anchors)]
 use core::convert::TryInto;
 use core::mem;
 use core::ops::Deref;
 use bitcoin::{PackedLockTime, Sequence, Witness};
+use crate::ln::features::ChannelTypeFeatures;
 
 use super::chaininterface::LowerBoundedFeeEstimator;
 
 const MAX_ALLOC_SIZE: usize = 64*1024;
 
 
-pub(crate) fn weight_revoked_offered_htlc(opt_anchors: bool) -> u64 {
+pub(crate) fn weight_revoked_offered_htlc(channel_type_features: &ChannelTypeFeatures) -> u64 {
        // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script
        const WEIGHT_REVOKED_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 + 133;
        const WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS: u64 = WEIGHT_REVOKED_OFFERED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP
-       if opt_anchors { WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS } else { WEIGHT_REVOKED_OFFERED_HTLC }
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() { WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS } else { WEIGHT_REVOKED_OFFERED_HTLC }
 }
 
-pub(crate) fn weight_revoked_received_htlc(opt_anchors: bool) -> u64 {
+pub(crate) fn weight_revoked_received_htlc(channel_type_features: &ChannelTypeFeatures) -> u64 {
        // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script
        const WEIGHT_REVOKED_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 +  139;
        const WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS: u64 = WEIGHT_REVOKED_RECEIVED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP
-       if opt_anchors { WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS } else { WEIGHT_REVOKED_RECEIVED_HTLC }
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() { WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS } else { WEIGHT_REVOKED_RECEIVED_HTLC }
 }
 
-pub(crate) fn weight_offered_htlc(opt_anchors: bool) -> u64 {
+pub(crate) fn weight_offered_htlc(channel_type_features: &ChannelTypeFeatures) -> u64 {
        // number_of_witness_elements + sig_length + counterpartyhtlc_sig  + preimage_length + preimage + witness_script_length + witness_script
        const WEIGHT_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 32 + 1 + 133;
        const WEIGHT_OFFERED_HTLC_ANCHORS: u64 = WEIGHT_OFFERED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP
-       if opt_anchors { WEIGHT_OFFERED_HTLC_ANCHORS } else { WEIGHT_OFFERED_HTLC }
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() { WEIGHT_OFFERED_HTLC_ANCHORS } else { WEIGHT_OFFERED_HTLC }
 }
 
-pub(crate) fn weight_received_htlc(opt_anchors: bool) -> u64 {
+pub(crate) fn weight_received_htlc(channel_type_features: &ChannelTypeFeatures) -> u64 {
        // number_of_witness_elements + sig_length + counterpartyhtlc_sig + empty_vec_length + empty_vec + witness_script_length + witness_script
        const WEIGHT_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 1 + 1 + 139;
        const WEIGHT_RECEIVED_HTLC_ANCHORS: u64 = WEIGHT_RECEIVED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP
-       if opt_anchors { WEIGHT_RECEIVED_HTLC_ANCHORS } else { WEIGHT_RECEIVED_HTLC }
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() { WEIGHT_RECEIVED_HTLC_ANCHORS } else { WEIGHT_RECEIVED_HTLC }
+}
+
+/// Verifies deserializable channel type features
+pub(crate) fn verify_channel_type_features(channel_type_features: &Option<ChannelTypeFeatures>, additional_permitted_features: Option<&ChannelTypeFeatures>) -> Result<(), DecodeError> {
+       if let Some(features) = channel_type_features.as_ref() {
+               if features.requires_unknown_bits() {
+                       return Err(DecodeError::UnknownRequiredFeature);
+               }
+
+               let mut supported_feature_set = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
+               supported_feature_set.set_scid_privacy_required();
+               supported_feature_set.set_zero_conf_required();
+
+               // allow the passing of an additional necessary permitted flag
+               if let Some(additional_permitted_features) = additional_permitted_features {
+                       supported_feature_set |= additional_permitted_features;
+               }
+
+               if !features.is_subset(&supported_feature_set) {
+                       return Err(DecodeError::UnknownRequiredFeature);
+               }
+       }
+
+       Ok(())
 }
 
 // number_of_witness_elements + sig_length + revocation_sig + true_length + op_true + witness_script_length + witness_script
@@ -147,8 +169,8 @@ pub(crate) struct RevokedHTLCOutput {
 }
 
 impl RevokedHTLCOutput {
-       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self {
-               let weight = if htlc.offered { weight_revoked_offered_htlc(opt_anchors) } else { weight_revoked_received_htlc(opt_anchors) };
+       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures) -> Self {
+               let weight = if htlc.offered { weight_revoked_offered_htlc(channel_type_features) } else { weight_revoked_received_htlc(channel_type_features) };
                RevokedHTLCOutput {
                        per_commitment_point,
                        counterparty_delayed_payment_base_key,
@@ -177,6 +199,8 @@ impl_writeable_tlv_based!(RevokedHTLCOutput, {
 /// witnessScript.
 ///
 /// The preimage is used as part of the witness.
+///
+/// Note that on upgrades, some features of existing outputs may be missed.
 #[derive(Clone, PartialEq, Eq)]
 pub(crate) struct CounterpartyOfferedHTLCOutput {
        per_commitment_point: PublicKey,
@@ -184,146 +208,278 @@ pub(crate) struct CounterpartyOfferedHTLCOutput {
        counterparty_htlc_base_key: PublicKey,
        preimage: PaymentPreimage,
        htlc: HTLCOutputInCommitment,
-       opt_anchors: Option<()>,
+       channel_type_features: ChannelTypeFeatures,
 }
 
 impl CounterpartyOfferedHTLCOutput {
-       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self {
+       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures) -> Self {
                CounterpartyOfferedHTLCOutput {
                        per_commitment_point,
                        counterparty_delayed_payment_base_key,
                        counterparty_htlc_base_key,
                        preimage,
                        htlc,
-                       opt_anchors: if opt_anchors { Some(()) } else { None },
+                       channel_type_features,
                }
        }
+}
 
-       fn opt_anchors(&self) -> bool {
-               self.opt_anchors.is_some()
+impl Writeable for CounterpartyOfferedHTLCOutput {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               let legacy_deserialization_prevention_marker = chan_utils::legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features);
+               write_tlv_fields!(writer, {
+                       (0, self.per_commitment_point, required),
+                       (2, self.counterparty_delayed_payment_base_key, required),
+                       (4, self.counterparty_htlc_base_key, required),
+                       (6, self.preimage, required),
+                       (8, self.htlc, required),
+                       (10, legacy_deserialization_prevention_marker, option),
+                       (11, self.channel_type_features, required),
+               });
+               Ok(())
        }
 }
 
-impl_writeable_tlv_based!(CounterpartyOfferedHTLCOutput, {
-       (0, per_commitment_point, required),
-       (2, counterparty_delayed_payment_base_key, required),
-       (4, counterparty_htlc_base_key, required),
-       (6, preimage, required),
-       (8, htlc, required),
-       (10, opt_anchors, option),
-});
+impl Readable for CounterpartyOfferedHTLCOutput {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               let mut per_commitment_point = RequiredWrapper(None);
+               let mut counterparty_delayed_payment_base_key = RequiredWrapper(None);
+               let mut counterparty_htlc_base_key = RequiredWrapper(None);
+               let mut preimage = RequiredWrapper(None);
+               let mut htlc = RequiredWrapper(None);
+               let mut _legacy_deserialization_prevention_marker: Option<()> = None;
+               let mut channel_type_features = None;
+
+               read_tlv_fields!(reader, {
+                       (0, per_commitment_point, required),
+                       (2, counterparty_delayed_payment_base_key, required),
+                       (4, counterparty_htlc_base_key, required),
+                       (6, preimage, required),
+                       (8, htlc, required),
+                       (10, _legacy_deserialization_prevention_marker, option),
+                       (11, channel_type_features, option),
+               });
+
+               verify_channel_type_features(&channel_type_features, None)?;
+
+               Ok(Self {
+                       per_commitment_point: per_commitment_point.0.unwrap(),
+                       counterparty_delayed_payment_base_key: counterparty_delayed_payment_base_key.0.unwrap(),
+                       counterparty_htlc_base_key: counterparty_htlc_base_key.0.unwrap(),
+                       preimage: preimage.0.unwrap(),
+                       htlc: htlc.0.unwrap(),
+                       channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key())
+               })
+       }
+}
 
 /// A struct to describe a HTLC output on a counterparty commitment transaction.
 ///
 /// HTLCOutputInCommitment (hash, timelock, directon) and pubkeys are used to generate a suitable
 /// witnessScript.
+///
+/// Note that on upgrades, some features of existing outputs may be missed.
 #[derive(Clone, PartialEq, Eq)]
 pub(crate) struct CounterpartyReceivedHTLCOutput {
        per_commitment_point: PublicKey,
        counterparty_delayed_payment_base_key: PublicKey,
        counterparty_htlc_base_key: PublicKey,
        htlc: HTLCOutputInCommitment,
-       opt_anchors: Option<()>,
+       channel_type_features: ChannelTypeFeatures,
 }
 
 impl CounterpartyReceivedHTLCOutput {
-       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self {
+       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment, channel_type_features: ChannelTypeFeatures) -> Self {
                CounterpartyReceivedHTLCOutput {
                        per_commitment_point,
                        counterparty_delayed_payment_base_key,
                        counterparty_htlc_base_key,
                        htlc,
-                       opt_anchors: if opt_anchors { Some(()) } else { None },
+                       channel_type_features
                }
        }
+}
 
-       fn opt_anchors(&self) -> bool {
-               self.opt_anchors.is_some()
+impl Writeable for CounterpartyReceivedHTLCOutput {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               let legacy_deserialization_prevention_marker = chan_utils::legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features);
+               write_tlv_fields!(writer, {
+                       (0, self.per_commitment_point, required),
+                       (2, self.counterparty_delayed_payment_base_key, required),
+                       (4, self.counterparty_htlc_base_key, required),
+                       (6, self.htlc, required),
+                       (8, legacy_deserialization_prevention_marker, option),
+                       (9, self.channel_type_features, required),
+               });
+               Ok(())
        }
 }
 
-impl_writeable_tlv_based!(CounterpartyReceivedHTLCOutput, {
-       (0, per_commitment_point, required),
-       (2, counterparty_delayed_payment_base_key, required),
-       (4, counterparty_htlc_base_key, required),
-       (6, htlc, required),
-       (8, opt_anchors, option),
-});
+impl Readable for CounterpartyReceivedHTLCOutput {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               let mut per_commitment_point = RequiredWrapper(None);
+               let mut counterparty_delayed_payment_base_key = RequiredWrapper(None);
+               let mut counterparty_htlc_base_key = RequiredWrapper(None);
+               let mut htlc = RequiredWrapper(None);
+               let mut _legacy_deserialization_prevention_marker: Option<()> = None;
+               let mut channel_type_features = None;
+
+               read_tlv_fields!(reader, {
+                       (0, per_commitment_point, required),
+                       (2, counterparty_delayed_payment_base_key, required),
+                       (4, counterparty_htlc_base_key, required),
+                       (6, htlc, required),
+                       (8, _legacy_deserialization_prevention_marker, option),
+                       (9, channel_type_features, option),
+               });
+
+               verify_channel_type_features(&channel_type_features, None)?;
+
+               Ok(Self {
+                       per_commitment_point: per_commitment_point.0.unwrap(),
+                       counterparty_delayed_payment_base_key: counterparty_delayed_payment_base_key.0.unwrap(),
+                       counterparty_htlc_base_key: counterparty_htlc_base_key.0.unwrap(),
+                       htlc: htlc.0.unwrap(),
+                       channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key())
+               })
+       }
+}
 
 /// A struct to describe a HTLC output on holder commitment transaction.
 ///
 /// Either offered or received, the amount is always used as part of the bip143 sighash.
 /// Preimage is only included as part of the witness in former case.
+///
+/// Note that on upgrades, some features of existing outputs may be missed.
 #[derive(Clone, PartialEq, Eq)]
 pub(crate) struct HolderHTLCOutput {
        preimage: Option<PaymentPreimage>,
        amount_msat: u64,
        /// Defaults to 0 for HTLC-Success transactions, which have no expiry
        cltv_expiry: u32,
-       opt_anchors: Option<()>,
+       channel_type_features: ChannelTypeFeatures,
 }
 
 impl HolderHTLCOutput {
-       pub(crate) fn build_offered(amount_msat: u64, cltv_expiry: u32, opt_anchors: bool) -> Self {
+       pub(crate) fn build_offered(amount_msat: u64, cltv_expiry: u32, channel_type_features: ChannelTypeFeatures) -> Self {
                HolderHTLCOutput {
                        preimage: None,
                        amount_msat,
                        cltv_expiry,
-                       opt_anchors: if opt_anchors { Some(()) } else { None } ,
+                       channel_type_features,
                }
        }
 
-       pub(crate) fn build_accepted(preimage: PaymentPreimage, amount_msat: u64, opt_anchors: bool) -> Self {
+       pub(crate) fn build_accepted(preimage: PaymentPreimage, amount_msat: u64, channel_type_features: ChannelTypeFeatures) -> Self {
                HolderHTLCOutput {
                        preimage: Some(preimage),
                        amount_msat,
                        cltv_expiry: 0,
-                       opt_anchors: if opt_anchors { Some(()) } else { None } ,
+                       channel_type_features,
                }
        }
+}
 
-       fn opt_anchors(&self) -> bool {
-               self.opt_anchors.is_some()
+impl Writeable for HolderHTLCOutput {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               let legacy_deserialization_prevention_marker = chan_utils::legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features);
+               write_tlv_fields!(writer, {
+                       (0, self.amount_msat, required),
+                       (2, self.cltv_expiry, required),
+                       (4, self.preimage, option),
+                       (6, legacy_deserialization_prevention_marker, option),
+                       (7, self.channel_type_features, required),
+               });
+               Ok(())
        }
 }
 
-impl_writeable_tlv_based!(HolderHTLCOutput, {
-       (0, amount_msat, required),
-       (2, cltv_expiry, required),
-       (4, preimage, option),
-       (6, opt_anchors, option)
-});
+impl Readable for HolderHTLCOutput {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               let mut amount_msat = RequiredWrapper(None);
+               let mut cltv_expiry = RequiredWrapper(None);
+               let mut preimage = None;
+               let mut _legacy_deserialization_prevention_marker: Option<()> = None;
+               let mut channel_type_features = None;
+
+               read_tlv_fields!(reader, {
+                       (0, amount_msat, required),
+                       (2, cltv_expiry, required),
+                       (4, preimage, option),
+                       (6, _legacy_deserialization_prevention_marker, option),
+                       (7, channel_type_features, option),
+               });
+
+               verify_channel_type_features(&channel_type_features, None)?;
+
+               Ok(Self {
+                       amount_msat: amount_msat.0.unwrap(),
+                       cltv_expiry: cltv_expiry.0.unwrap(),
+                       preimage,
+                       channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key())
+               })
+       }
+}
 
 /// A struct to describe the channel output on the funding transaction.
 ///
 /// witnessScript is used as part of the witness redeeming the funding utxo.
+///
+/// Note that on upgrades, some features of existing outputs may be missed.
 #[derive(Clone, PartialEq, Eq)]
 pub(crate) struct HolderFundingOutput {
        funding_redeemscript: Script,
-       funding_amount: Option<u64>,
-       opt_anchors: Option<()>,
+       pub(crate) funding_amount: Option<u64>,
+       channel_type_features: ChannelTypeFeatures,
 }
 
 
 impl HolderFundingOutput {
-       pub(crate) fn build(funding_redeemscript: Script, funding_amount: u64, opt_anchors: bool) -> Self {
+       pub(crate) fn build(funding_redeemscript: Script, funding_amount: u64, channel_type_features: ChannelTypeFeatures) -> Self {
                HolderFundingOutput {
                        funding_redeemscript,
                        funding_amount: Some(funding_amount),
-                       opt_anchors: if opt_anchors { Some(()) } else { None },
+                       channel_type_features,
                }
        }
+}
 
-       fn opt_anchors(&self) -> bool {
-               self.opt_anchors.is_some()
+impl Writeable for HolderFundingOutput {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               let legacy_deserialization_prevention_marker = chan_utils::legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features);
+               write_tlv_fields!(writer, {
+                       (0, self.funding_redeemscript, required),
+                       (1, self.channel_type_features, required),
+                       (2, legacy_deserialization_prevention_marker, option),
+                       (3, self.funding_amount, option),
+               });
+               Ok(())
        }
 }
 
-impl_writeable_tlv_based!(HolderFundingOutput, {
-       (0, funding_redeemscript, required),
-       (2, opt_anchors, option),
-       (3, funding_amount, option),
-});
+impl Readable for HolderFundingOutput {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               let mut funding_redeemscript = RequiredWrapper(None);
+               let mut _legacy_deserialization_prevention_marker: Option<()> = None;
+               let mut channel_type_features = None;
+               let mut funding_amount = None;
+
+               read_tlv_fields!(reader, {
+                       (0, funding_redeemscript, required),
+                       (1, channel_type_features, option),
+                       (2, _legacy_deserialization_prevention_marker, option),
+                       (3, funding_amount, option)
+               });
+
+               verify_channel_type_features(&channel_type_features, None)?;
+
+               Ok(Self {
+                       funding_redeemscript: funding_redeemscript.0.unwrap(),
+                       channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key()),
+                       funding_amount
+               })
+       }
+}
 
 /// A wrapper encapsulating all in-protocol differing outputs types.
 ///
@@ -347,11 +503,11 @@ impl PackageSolvingData {
                        PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => outp.htlc.amount_msat / 1000,
                        PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => outp.htlc.amount_msat / 1000,
                        PackageSolvingData::HolderHTLCOutput(ref outp) => {
-                               debug_assert!(outp.opt_anchors());
+                               debug_assert!(outp.channel_type_features.supports_anchors_zero_fee_htlc_tx());
                                outp.amount_msat / 1000
                        },
                        PackageSolvingData::HolderFundingOutput(ref outp) => {
-                               debug_assert!(outp.opt_anchors());
+                               debug_assert!(outp.channel_type_features.supports_anchors_zero_fee_htlc_tx());
                                outp.funding_amount.unwrap()
                        }
                };
@@ -361,14 +517,14 @@ impl PackageSolvingData {
                match self {
                        PackageSolvingData::RevokedOutput(ref outp) => outp.weight as usize,
                        PackageSolvingData::RevokedHTLCOutput(ref outp) => outp.weight as usize,
-                       PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => weight_offered_htlc(outp.opt_anchors()) as usize,
-                       PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => weight_received_htlc(outp.opt_anchors()) as usize,
+                       PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => weight_offered_htlc(&outp.channel_type_features) as usize,
+                       PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => weight_received_htlc(&outp.channel_type_features) as usize,
                        PackageSolvingData::HolderHTLCOutput(ref outp) => {
-                               debug_assert!(outp.opt_anchors());
+                               debug_assert!(outp.channel_type_features.supports_anchors_zero_fee_htlc_tx());
                                if outp.preimage.is_none() {
-                                       weight_offered_htlc(true) as usize
+                                       weight_offered_htlc(&outp.channel_type_features) as usize
                                } else {
-                                       weight_received_htlc(true) as usize
+                                       weight_received_htlc(&outp.channel_type_features) as usize
                                }
                        },
                        // Since HolderFundingOutput maps to an untractable package that is already signed, its
@@ -411,7 +567,7 @@ impl PackageSolvingData {
                        },
                        PackageSolvingData::RevokedHTLCOutput(ref outp) => {
                                let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
-                               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
+                               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
                                //TODO: should we panic on signer failure ?
                                if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(&bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) {
                                        let mut ser_sig = sig.serialize_der().to_vec();
@@ -423,7 +579,7 @@ impl PackageSolvingData {
                        },
                        PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => {
                                let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
-                               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
+                               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
 
                                if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {
                                        let mut ser_sig = sig.serialize_der().to_vec();
@@ -435,7 +591,7 @@ impl PackageSolvingData {
                        },
                        PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => {
                                let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
-                               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
+                               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
 
                                if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {
                                        let mut ser_sig = sig.serialize_der().to_vec();
@@ -453,7 +609,7 @@ impl PackageSolvingData {
        fn get_finalized_tx<Signer: WriteableEcdsaChannelSigner>(&self, outpoint: &BitcoinOutPoint, onchain_handler: &mut OnchainTxHandler<Signer>) -> Option<Transaction> {
                match self {
                        PackageSolvingData::HolderHTLCOutput(ref outp) => {
-                               debug_assert!(!outp.opt_anchors());
+                               debug_assert!(!outp.channel_type_features.supports_anchors_zero_fee_htlc_tx());
                                return onchain_handler.get_fully_signed_htlc_tx(outpoint, &outp.preimage);
                        }
                        PackageSolvingData::HolderFundingOutput(ref outp) => {
@@ -491,7 +647,7 @@ impl PackageSolvingData {
                        PackageSolvingData::RevokedHTLCOutput(..) => { (PackageMalleability::Malleable, true) },
                        PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { (PackageMalleability::Malleable, true) },
                        PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { (PackageMalleability::Malleable, false) },
-                       PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.opt_anchors() {
+                       PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
                                (PackageMalleability::Malleable, outp.preimage.is_some())
                        } else {
                                (PackageMalleability::Untractable, false)
@@ -707,7 +863,6 @@ impl PackageTemplate {
                let output_weight = (8 + 1 + destination_script.len()) * WITNESS_SCALE_FACTOR;
                inputs_weight + witnesses_weight + transaction_weight + output_weight
        }
-       #[cfg(anchors)]
        pub(crate) fn construct_malleable_package_with_external_funding<Signer: WriteableEcdsaChannelSigner>(
                &self, onchain_handler: &mut OnchainTxHandler<Signer>,
        ) -> Option<Vec<ExternalHTLCClaim>> {
@@ -716,7 +871,7 @@ impl PackageTemplate {
                for (previous_output, input) in &self.inputs {
                        match input {
                                PackageSolvingData::HolderHTLCOutput(ref outp) => {
-                                       debug_assert!(outp.opt_anchors());
+                                       debug_assert!(outp.channel_type_features.supports_anchors_zero_fee_htlc_tx());
                                        onchain_handler.generate_external_htlc_claim(&previous_output, &outp.preimage).map(|htlc| {
                                                htlcs.get_or_insert_with(|| Vec::with_capacity(self.inputs.len())).push(htlc);
                                        });
@@ -812,7 +967,6 @@ impl PackageTemplate {
                None
        }
 
-       #[cfg(anchors)]
        /// Computes a feerate based on the given confirmation target. If a previous feerate was used,
        /// the new feerate is below it, and `force_feerate_bump` is set, we'll use a 25% increase of
        /// the previous feerate instead of the new feerate.
@@ -840,8 +994,8 @@ impl PackageTemplate {
        /// attached to help the spending transaction reach confirmation.
        pub(crate) fn requires_external_funding(&self) -> bool {
                self.inputs.iter().find(|input| match input.1 {
-                       PackageSolvingData::HolderFundingOutput(ref outp) => outp.opt_anchors(),
-                       PackageSolvingData::HolderHTLCOutput(ref outp) => outp.opt_anchors(),
+                       PackageSolvingData::HolderFundingOutput(ref outp) => outp.channel_type_features.supports_anchors_zero_fee_htlc_tx(),
+                       PackageSolvingData::HolderHTLCOutput(ref outp) => outp.channel_type_features.supports_anchors_zero_fee_htlc_tx(),
                        _ => false,
                }).is_some()
        }
@@ -1025,6 +1179,7 @@ mod tests {
 
        use bitcoin::secp256k1::{PublicKey,SecretKey};
        use bitcoin::secp256k1::Secp256k1;
+       use crate::ln::features::ChannelTypeFeatures;
 
        macro_rules! dumb_revk_output {
                ($secp_ctx: expr, $is_counterparty_balance_on_anchors: expr) => {
@@ -1065,7 +1220,7 @@ mod tests {
                () => {
                        {
                                let preimage = PaymentPreimage([2;32]);
-                               PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build_accepted(preimage, 0, false))
+                               PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build_accepted(preimage, 0, ChannelTypeFeatures::only_static_remote_key()))
                        }
                }
        }
@@ -1153,7 +1308,7 @@ mod tests {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
                let revk_outp = dumb_revk_output!(secp_ctx, false);
-               let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0, false);
+               let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0, ChannelTypeFeatures::only_static_remote_key());
 
                let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, 100);
                let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, 100);
@@ -1214,7 +1369,7 @@ mod tests {
        fn test_package_amounts() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, false);
+               let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, ChannelTypeFeatures::only_static_remote_key());
 
                let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100);
                assert_eq!(package.package_amount(), 1000);
@@ -1235,18 +1390,18 @@ mod tests {
                }
 
                {
-                       for &opt_anchors in [false, true].iter() {
-                               let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, opt_anchors);
+                       for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() {
+                               let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, channel_type_features.clone());
                                let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100);
-                               assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_received_htlc(opt_anchors) as usize);
+                               assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_received_htlc(channel_type_features) as usize);
                        }
                }
 
                {
-                       for &opt_anchors in [false, true].iter() {
-                               let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000, opt_anchors);
+                       for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() {
+                               let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000, channel_type_features.clone());
                                let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100);
-                               assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_offered_htlc(opt_anchors) as usize);
+                               assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_offered_htlc(channel_type_features) as usize);
                        }
                }
        }
index 950a31af37d8480a6eb080fc6d874360c19798cd..5963da8e9f213efd023a21f6570369b8775ee2a5 100644 (file)
 // You may not use this file except in accordance with one or both of these
 // licenses.
 
-//! Utitilies for bumping transactions originating from [`super::Event`]s.
+//! Utilities for bumping transactions originating from [`Event`]s.
+//!
+//! [`Event`]: crate::events::Event
 
-use crate::ln::PaymentPreimage;
+use alloc::collections::BTreeMap;
+use core::ops::Deref;
+
+use crate::chain::chaininterface::{BroadcasterInterface, compute_feerate_sat_per_1000_weight, fee_for_weight, FEERATE_FLOOR_SATS_PER_KW};
+use crate::chain::ClaimId;
+use crate::io_extras::sink;
+use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
 use crate::ln::chan_utils;
-use crate::ln::chan_utils::{ChannelTransactionParameters, HTLCOutputInCommitment};
+use crate::ln::chan_utils::{
+       ANCHOR_INPUT_WITNESS_WEIGHT, HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT,
+       HTLC_TIMEOUT_INPUT_ANCHOR_WITNESS_WEIGHT, ChannelTransactionParameters, HTLCOutputInCommitment
+};
+use crate::ln::features::ChannelTypeFeatures;
+use crate::ln::PaymentPreimage;
+use crate::prelude::*;
+use crate::sign::{ChannelSigner, EcdsaChannelSigner, SignerProvider, WriteableEcdsaChannelSigner};
+use crate::sync::Mutex;
+use crate::util::logger::Logger;
 
-use bitcoin::{OutPoint, PackedLockTime, Script, Transaction, Txid, TxIn, TxOut, Witness};
+use bitcoin::{OutPoint, PackedLockTime, PubkeyHash, Sequence, Script, Transaction, Txid, TxIn, TxOut, Witness, WPubkeyHash};
+use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR;
+use bitcoin::consensus::Encodable;
 use bitcoin::secp256k1;
 use bitcoin::secp256k1::{PublicKey, Secp256k1};
 use bitcoin::secp256k1::ecdsa::Signature;
 
+const EMPTY_SCRIPT_SIG_WEIGHT: u64 = 1 /* empty script_sig */ * WITNESS_SCALE_FACTOR as u64;
+
+const BASE_INPUT_SIZE: u64 = 32 /* txid */ + 4 /* vout */ + 4 /* sequence */;
+
+const BASE_INPUT_WEIGHT: u64 = BASE_INPUT_SIZE * WITNESS_SCALE_FACTOR as u64;
+
+/// The parameters required to derive a channel signer via [`SignerProvider`].
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct ChannelDerivationParameters {
+       /// The value in satoshis of the channel we're attempting to spend the anchor output of.
+       pub value_satoshis: u64,
+       /// The unique identifier to re-derive the signer for the associated channel.
+       pub keys_id: [u8; 32],
+       /// The necessary channel parameters that need to be provided to the re-derived signer through
+       /// [`ChannelSigner::provide_channel_parameters`].
+       ///
+       /// [`ChannelSigner::provide_channel_parameters`]: crate::sign::ChannelSigner::provide_channel_parameters
+       pub transaction_parameters: ChannelTransactionParameters,
+}
+
 /// A descriptor used to sign for a commitment transaction's anchor output.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct AnchorDescriptor {
-       /// A unique identifier used along with `channel_value_satoshis` to re-derive the
-       /// [`InMemorySigner`] required to sign `input`.
-       ///
-       /// [`InMemorySigner`]: crate::sign::InMemorySigner
-       pub channel_keys_id: [u8; 32],
-       /// The value in satoshis of the channel we're attempting to spend the anchor output of. This is
-       /// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign
-       /// `input`.
-       ///
-       /// [`InMemorySigner`]: crate::sign::InMemorySigner
-       pub channel_value_satoshis: u64,
+       /// The parameters required to derive the signer for the anchor input.
+       pub channel_derivation_parameters: ChannelDerivationParameters,
        /// The transaction input's outpoint corresponding to the commitment transaction's anchor
        /// output.
        pub outpoint: OutPoint,
 }
 
+impl AnchorDescriptor {
+       /// Returns the UTXO to be spent by the anchor input, which can be obtained via
+       /// [`Self::unsigned_tx_input`].
+       pub fn previous_utxo(&self) -> TxOut {
+               TxOut {
+                       script_pubkey: self.witness_script().to_v0_p2wsh(),
+                       value: ANCHOR_OUTPUT_VALUE_SATOSHI,
+               }
+       }
+
+       /// Returns the unsigned transaction input spending the anchor output in the commitment
+       /// transaction.
+       pub fn unsigned_tx_input(&self) -> TxIn {
+               TxIn {
+                       previous_output: self.outpoint.clone(),
+                       script_sig: Script::new(),
+                       sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
+                       witness: Witness::new(),
+               }
+       }
+
+       /// Returns the witness script of the anchor output in the commitment transaction.
+       pub fn witness_script(&self) -> Script {
+               let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable();
+               chan_utils::get_anchor_redeemscript(&channel_params.broadcaster_pubkeys().funding_pubkey)
+       }
+
+       /// Returns the fully signed witness required to spend the anchor output in the commitment
+       /// transaction.
+       pub fn tx_input_witness(&self, signature: &Signature) -> Witness {
+               let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable();
+               chan_utils::build_anchor_input_witness(&channel_params.broadcaster_pubkeys().funding_pubkey, signature)
+       }
+
+       /// Derives the channel signer required to sign the anchor input.
+       pub fn derive_channel_signer<S: WriteableEcdsaChannelSigner, SP: Deref>(&self, signer_provider: &SP) -> S
+       where
+               SP::Target: SignerProvider<Signer = S>
+       {
+               let mut signer = signer_provider.derive_channel_signer(
+                       self.channel_derivation_parameters.value_satoshis,
+                       self.channel_derivation_parameters.keys_id,
+               );
+               signer.provide_channel_parameters(&self.channel_derivation_parameters.transaction_parameters);
+               signer
+       }
+}
+
 /// A descriptor used to sign for a commitment transaction's HTLC output.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct HTLCDescriptor {
-       /// A unique identifier used along with `channel_value_satoshis` to re-derive the
-       /// [`InMemorySigner`] required to sign `input`.
-       ///
-       /// [`InMemorySigner`]: crate::sign::InMemorySigner
-       pub channel_keys_id: [u8; 32],
-       /// The value in satoshis of the channel we're attempting to spend the anchor output of. This is
-       /// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign
-       /// `input`.
-       ///
-       /// [`InMemorySigner`]: crate::sign::InMemorySigner
-       pub channel_value_satoshis: u64,
-       /// The necessary channel parameters that need to be provided to the re-derived
-       /// [`InMemorySigner`] through [`ChannelSigner::provide_channel_parameters`].
-       ///
-       /// [`InMemorySigner`]: crate::sign::InMemorySigner
-       /// [`ChannelSigner::provide_channel_parameters`]: crate::sign::ChannelSigner::provide_channel_parameters
-       pub channel_parameters: ChannelTransactionParameters,
+       /// The parameters required to derive the signer for the HTLC input.
+       pub channel_derivation_parameters: ChannelDerivationParameters,
        /// The txid of the commitment transaction in which the HTLC output lives.
        pub commitment_txid: Txid,
        /// The number of the commitment transaction in which the HTLC output lives.
        pub per_commitment_number: u64,
+       /// The key tweak corresponding to the number of the commitment transaction in which the HTLC
+       /// output lives. This tweak is applied to all the basepoints for both parties in the channel to
+       /// arrive at unique keys per commitment.
+       ///
+       /// See <https://github.com/lightning/bolts/blob/master/03-transactions.md#keys> for more info.
+       pub per_commitment_point: PublicKey,
        /// The details of the HTLC as it appears in the commitment transaction.
        pub htlc: HTLCOutputInCommitment,
        /// The preimage, if `Some`, to claim the HTLC output with. If `None`, the timeout path must be
@@ -71,50 +140,64 @@ pub struct HTLCDescriptor {
 }
 
 impl HTLCDescriptor {
+       /// Returns the outpoint of the HTLC output in the commitment transaction. This is the outpoint
+       /// being spent by the HTLC input in the HTLC transaction.
+       pub fn outpoint(&self) -> OutPoint {
+               OutPoint {
+                       txid: self.commitment_txid,
+                       vout: self.htlc.transaction_output_index.unwrap(),
+               }
+       }
+
+       /// Returns the UTXO to be spent by the HTLC input, which can be obtained via
+       /// [`Self::unsigned_tx_input`].
+       pub fn previous_utxo<C: secp256k1::Signing + secp256k1::Verification>(&self, secp: &Secp256k1<C>) -> TxOut {
+               TxOut {
+                       script_pubkey: self.witness_script(secp).to_v0_p2wsh(),
+                       value: self.htlc.amount_msat / 1000,
+               }
+       }
+
        /// Returns the unsigned transaction input spending the HTLC output in the commitment
        /// transaction.
        pub fn unsigned_tx_input(&self) -> TxIn {
-               chan_utils::build_htlc_input(&self.commitment_txid, &self.htlc, true /* opt_anchors */)
+               chan_utils::build_htlc_input(&self.commitment_txid, &self.htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies())
        }
 
        /// Returns the delayed output created as a result of spending the HTLC output in the commitment
        /// transaction.
-       pub fn tx_output<C: secp256k1::Signing + secp256k1::Verification>(
-               &self, per_commitment_point: &PublicKey, secp: &Secp256k1<C>
-       ) -> TxOut {
-               let channel_params = self.channel_parameters.as_holder_broadcastable();
+       pub fn tx_output<C: secp256k1::Signing + secp256k1::Verification>(&self, secp: &Secp256k1<C>) -> TxOut {
+               let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable();
                let broadcaster_keys = channel_params.broadcaster_pubkeys();
                let counterparty_keys = channel_params.countersignatory_pubkeys();
                let broadcaster_delayed_key = chan_utils::derive_public_key(
-                       secp, per_commitment_point, &broadcaster_keys.delayed_payment_basepoint
+                       secp, &self.per_commitment_point, &broadcaster_keys.delayed_payment_basepoint
                );
                let counterparty_revocation_key = chan_utils::derive_public_revocation_key(
-                       secp, per_commitment_point, &counterparty_keys.revocation_basepoint
+                       secp, &self.per_commitment_point, &counterparty_keys.revocation_basepoint
                );
                chan_utils::build_htlc_output(
-                       0 /* feerate_per_kw */, channel_params.contest_delay(), &self.htlc, true /* opt_anchors */,
-                       false /* use_non_zero_fee_anchors */, &broadcaster_delayed_key, &counterparty_revocation_key
+                       0 /* feerate_per_kw */, channel_params.contest_delay(), &self.htlc,
+                       &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &broadcaster_delayed_key, &counterparty_revocation_key
                )
        }
 
        /// Returns the witness script of the HTLC output in the commitment transaction.
-       pub fn witness_script<C: secp256k1::Signing + secp256k1::Verification>(
-               &self, per_commitment_point: &PublicKey, secp: &Secp256k1<C>
-       ) -> Script {
-               let channel_params = self.channel_parameters.as_holder_broadcastable();
+       pub fn witness_script<C: secp256k1::Signing + secp256k1::Verification>(&self, secp: &Secp256k1<C>) -> Script {
+               let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable();
                let broadcaster_keys = channel_params.broadcaster_pubkeys();
                let counterparty_keys = channel_params.countersignatory_pubkeys();
                let broadcaster_htlc_key = chan_utils::derive_public_key(
-                       secp, per_commitment_point, &broadcaster_keys.htlc_basepoint
+                       secp, &self.per_commitment_point, &broadcaster_keys.htlc_basepoint
                );
                let counterparty_htlc_key = chan_utils::derive_public_key(
-                       secp, per_commitment_point, &counterparty_keys.htlc_basepoint
+                       secp, &self.per_commitment_point, &counterparty_keys.htlc_basepoint
                );
                let counterparty_revocation_key = chan_utils::derive_public_revocation_key(
-                       secp, per_commitment_point, &counterparty_keys.revocation_basepoint
+                       secp, &self.per_commitment_point, &counterparty_keys.revocation_basepoint
                );
                chan_utils::get_htlc_redeemscript_with_explicit_keys(
-                       &self.htlc, true /* opt_anchors */, &broadcaster_htlc_key, &counterparty_htlc_key,
+                       &self.htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &broadcaster_htlc_key, &counterparty_htlc_key,
                        &counterparty_revocation_key,
                )
        }
@@ -123,9 +206,22 @@ impl HTLCDescriptor {
        /// transaction.
        pub fn tx_input_witness(&self, signature: &Signature, witness_script: &Script) -> Witness {
                chan_utils::build_htlc_input_witness(
-                       signature, &self.counterparty_sig, &self.preimage, witness_script, true /* opt_anchors */
+                       signature, &self.counterparty_sig, &self.preimage, witness_script, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies() /* opt_anchors */
                )
        }
+
+       /// Derives the channel signer required to sign the HTLC input.
+       pub fn derive_channel_signer<S: WriteableEcdsaChannelSigner, SP: Deref>(&self, signer_provider: &SP) -> S
+       where
+               SP::Target: SignerProvider<Signer = S>
+       {
+               let mut signer = signer_provider.derive_channel_signer(
+                       self.channel_derivation_parameters.value_satoshis,
+                       self.channel_derivation_parameters.keys_id,
+               );
+               signer.provide_channel_parameters(&self.channel_derivation_parameters.transaction_parameters);
+               signer
+       }
 }
 
 /// Represents the different types of transactions, originating from LDK, to be bumped.
@@ -144,12 +240,11 @@ pub enum BumpTransactionEvent {
        /// broadcast first, as the child anchor transaction depends on it.
        ///
        /// The consumer should be able to sign for any of the additional inputs included within the
-       /// child anchor transaction. To sign its anchor input, an [`InMemorySigner`] should be
-       /// re-derived through [`KeysManager::derive_channel_keys`] with the help of
-       /// [`AnchorDescriptor::channel_keys_id`] and [`AnchorDescriptor::channel_value_satoshis`]. The
-       /// anchor input signature can be computed with [`EcdsaChannelSigner::sign_holder_anchor_input`],
-       /// which can then be provided to [`build_anchor_input_witness`] along with the `funding_pubkey`
-       /// to obtain the full witness required to spend.
+       /// child anchor transaction. To sign its anchor input, an [`EcdsaChannelSigner`] should be
+       /// re-derived through [`AnchorDescriptor::derive_channel_signer`]. The anchor input signature
+       /// can be computed with [`EcdsaChannelSigner::sign_holder_anchor_input`], which can then be
+       /// provided to [`build_anchor_input_witness`] along with the `funding_pubkey` to obtain the
+       /// full witness required to spend.
        ///
        /// It is possible to receive more than one instance of this event if a valid child anchor
        /// transaction is never broadcast or is but not with a sufficient fee to be mined. Care should
@@ -168,11 +263,16 @@ pub enum BumpTransactionEvent {
        /// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
        /// be not urgent.
        ///
-       /// [`InMemorySigner`]: crate::sign::InMemorySigner
-       /// [`KeysManager::derive_channel_keys`]: crate::sign::KeysManager::derive_channel_keys
+       /// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
        /// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input
        /// [`build_anchor_input_witness`]: crate::ln::chan_utils::build_anchor_input_witness
        ChannelClose {
+               /// The unique identifier for the claim of the anchor output in the commitment transaction.
+               ///
+               /// The identifier must map to the set of external UTXOs assigned to the claim, such that
+               /// they can be reused when a new claim with the same identifier needs to be made, resulting
+               /// in a fee-bumping attempt.
+               claim_id: ClaimId,
                /// The target feerate that the transaction package, which consists of the commitment
                /// transaction and the to-be-crafted child anchor transaction, must meet.
                package_target_feerate_sat_per_1000_weight: u32,
@@ -201,11 +301,11 @@ pub enum BumpTransactionEvent {
        /// broadcast by the consumer of the event.
        ///
        /// The consumer should be able to sign for any of the non-HTLC inputs added to the resulting
-       /// HTLC transaction. To sign HTLC inputs, an [`InMemorySigner`] should be re-derived through
-       /// [`KeysManager::derive_channel_keys`] with the help of `channel_keys_id` and
-       /// `channel_value_satoshis`. Each HTLC input's signature can be computed with
-       /// [`EcdsaChannelSigner::sign_holder_htlc_transaction`], which can then be provided to
-       /// [`HTLCDescriptor::tx_input_witness`] to obtain the fully signed witness required to spend.
+       /// HTLC transaction. To sign HTLC inputs, an [`EcdsaChannelSigner`] should be re-derived
+       /// through [`HTLCDescriptor::derive_channel_signer`]. Each HTLC input's signature can be
+       /// computed with [`EcdsaChannelSigner::sign_holder_htlc_transaction`], which can then be
+       /// provided to [`HTLCDescriptor::tx_input_witness`] to obtain the fully signed witness required
+       /// to spend.
        ///
        /// It is possible to receive more than one instance of this event if a valid HTLC transaction
        /// is never broadcast or is but not with a sufficient fee to be mined. Care should be taken by
@@ -217,11 +317,17 @@ pub enum BumpTransactionEvent {
        /// longer able to commit external confirmed funds to the HTLC transaction or the fee committed
        /// to the HTLC transaction is greater in value than the HTLCs being claimed.
        ///
-       /// [`InMemorySigner`]: crate::sign::InMemorySigner
-       /// [`KeysManager::derive_channel_keys`]: crate::sign::KeysManager::derive_channel_keys
+       /// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner
        /// [`EcdsaChannelSigner::sign_holder_htlc_transaction`]: crate::sign::EcdsaChannelSigner::sign_holder_htlc_transaction
        /// [`HTLCDescriptor::tx_input_witness`]: HTLCDescriptor::tx_input_witness
        HTLCResolution {
+               /// The unique identifier for the claim of the HTLCs in the confirmed commitment
+               /// transaction.
+               ///
+               /// The identifier must map to the set of external UTXOs assigned to the claim, such that
+               /// they can be reused when a new claim with the same identifier needs to be made, resulting
+               /// in a fee-bumping attempt.
+               claim_id: ClaimId,
                /// The target feerate that the resulting HTLC transaction must meet.
                target_feerate_sat_per_1000_weight: u32,
                /// The set of pending HTLCs on the confirmed commitment that need to be claimed, preferably
@@ -231,3 +337,541 @@ pub enum BumpTransactionEvent {
                tx_lock_time: PackedLockTime,
        },
 }
+
+/// An input that must be included in a transaction when performing coin selection through
+/// [`CoinSelectionSource::select_confirmed_utxos`]. It is guaranteed to be a SegWit input, so it
+/// must have an empty [`TxIn::script_sig`] when spent.
+#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Input {
+       /// The unique identifier of the input.
+       pub outpoint: OutPoint,
+       /// The UTXO being spent by the input.
+       pub previous_utxo: TxOut,
+       /// The upper-bound weight consumed by the input's full [`TxIn::script_sig`] and
+       /// [`TxIn::witness`], each with their lengths included, required to satisfy the output's
+       /// script.
+       pub satisfaction_weight: u64,
+}
+
+/// An unspent transaction output that is available to spend resulting from a successful
+/// [`CoinSelection`] attempt.
+#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Utxo {
+       /// The unique identifier of the output.
+       pub outpoint: OutPoint,
+       /// The output to spend.
+       pub output: TxOut,
+       /// The upper-bound weight consumed by the input's full [`TxIn::script_sig`] and [`TxIn::witness`], each
+       /// with their lengths included, required to satisfy the output's script. The weight consumed by
+       /// the input's `script_sig` must account for [`WITNESS_SCALE_FACTOR`].
+       pub satisfaction_weight: u64,
+}
+
+impl Utxo {
+       const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ +
+               1 /* sig length */ +
+               73 /* sig including sighash flag */ +
+               1 /* pubkey length */ +
+               33 /* pubkey */;
+
+       /// Returns a `Utxo` with the `satisfaction_weight` estimate for a legacy P2PKH output.
+       pub fn new_p2pkh(outpoint: OutPoint, value: u64, pubkey_hash: &PubkeyHash) -> Self {
+               let script_sig_size = 1 /* script_sig length */ +
+                       1 /* OP_PUSH73 */ +
+                       73 /* sig including sighash flag */ +
+                       1 /* OP_PUSH33 */ +
+                       33 /* pubkey */;
+               Self {
+                       outpoint,
+                       output: TxOut {
+                               value,
+                               script_pubkey: Script::new_p2pkh(pubkey_hash),
+                       },
+                       satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64 + 1 /* empty witness */,
+               }
+       }
+
+       /// Returns a `Utxo` with the `satisfaction_weight` estimate for a P2WPKH nested in P2SH output.
+       pub fn new_nested_p2wpkh(outpoint: OutPoint, value: u64, pubkey_hash: &WPubkeyHash) -> Self {
+               let script_sig_size = 1 /* script_sig length */ +
+                       1 /* OP_0 */ +
+                       1 /* OP_PUSH20 */ +
+                       20 /* pubkey_hash */;
+               Self {
+                       outpoint,
+                       output: TxOut {
+                               value,
+                               script_pubkey: Script::new_p2sh(&Script::new_v0_p2wpkh(pubkey_hash).script_hash()),
+                       },
+                       satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64 + Self::P2WPKH_WITNESS_WEIGHT,
+               }
+       }
+
+       /// Returns a `Utxo` with the `satisfaction_weight` estimate for a SegWit v0 P2WPKH output.
+       pub fn new_v0_p2wpkh(outpoint: OutPoint, value: u64, pubkey_hash: &WPubkeyHash) -> Self {
+               Self {
+                       outpoint,
+                       output: TxOut {
+                               value,
+                               script_pubkey: Script::new_v0_p2wpkh(pubkey_hash),
+                       },
+                       satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + Self::P2WPKH_WITNESS_WEIGHT,
+               }
+       }
+}
+
+/// The result of a successful coin selection attempt for a transaction requiring additional UTXOs
+/// to cover its fees.
+#[derive(Clone, Debug)]
+pub struct CoinSelection {
+       /// The set of UTXOs (with at least 1 confirmation) to spend and use within a transaction
+       /// requiring additional fees.
+       pub confirmed_utxos: Vec<Utxo>,
+       /// An additional output tracking whether any change remained after coin selection. This output
+       /// should always have a value above dust for its given `script_pubkey`. It should not be
+       /// spent until the transaction it belongs to confirms to ensure mempool descendant limits are
+       /// not met. This implies no other party should be able to spend it except us.
+       pub change_output: Option<TxOut>,
+}
+
+/// An abstraction over a bitcoin wallet that can perform coin selection over a set of UTXOs and can
+/// sign for them. The coin selection method aims to mimic Bitcoin Core's `fundrawtransaction` RPC,
+/// which most wallets should be able to satisfy. Otherwise, consider implementing [`WalletSource`],
+/// which can provide a default implementation of this trait when used with [`Wallet`].
+pub trait CoinSelectionSource {
+       /// Performs coin selection of a set of UTXOs, with at least 1 confirmation each, that are
+       /// available to spend. Implementations are free to pick their coin selection algorithm of
+       /// choice, as long as the following requirements are met:
+       ///
+       /// 1. `must_spend` contains a set of [`Input`]s that must be included in the transaction
+       ///    throughout coin selection, but must not be returned as part of the result.
+       /// 2. `must_pay_to` contains a set of [`TxOut`]s that must be included in the transaction
+       ///    throughout coin selection. In some cases, like when funding an anchor transaction, this
+       ///    set is empty. Implementations should ensure they handle this correctly on their end,
+       ///    e.g., Bitcoin Core's `fundrawtransaction` RPC requires at least one output to be
+       ///    provided, in which case a zero-value empty OP_RETURN output can be used instead.
+       /// 3. Enough inputs must be selected/contributed for the resulting transaction (including the
+       ///    inputs and outputs noted above) to meet `target_feerate_sat_per_1000_weight`.
+       ///
+       /// Implementations must take note that [`Input::satisfaction_weight`] only tracks the weight of
+       /// the input's `script_sig` and `witness`. Some wallets, like Bitcoin Core's, may require
+       /// providing the full input weight. Failing to do so may lead to underestimating fee bumps and
+       /// delaying block inclusion.
+       ///
+       /// The `claim_id` must map to the set of external UTXOs assigned to the claim, such that they
+       /// can be re-used within new fee-bumped iterations of the original claiming transaction,
+       /// ensuring that claims don't double spend each other. If a specific `claim_id` has never had a
+       /// transaction associated with it, and all of the available UTXOs have already been assigned to
+       /// other claims, implementations must be willing to double spend their UTXOs. The choice of
+       /// which UTXOs to double spend is left to the implementation, but it must strive to keep the
+       /// set of other claims being double spent to a minimum.
+       fn select_confirmed_utxos(
+               &self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &[TxOut],
+               target_feerate_sat_per_1000_weight: u32,
+       ) -> Result<CoinSelection, ()>;
+       /// Signs and provides the full witness for all inputs within the transaction known to the
+       /// trait (i.e., any provided via [`CoinSelectionSource::select_confirmed_utxos`]).
+       fn sign_tx(&self, tx: Transaction) -> Result<Transaction, ()>;
+}
+
+/// An alternative to [`CoinSelectionSource`] that can be implemented and used along [`Wallet`] to
+/// provide a default implementation to [`CoinSelectionSource`].
+pub trait WalletSource {
+       /// Returns all UTXOs, with at least 1 confirmation each, that are available to spend.
+       fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()>;
+       /// Returns a script to use for change above dust resulting from a successful coin selection
+       /// attempt.
+       fn get_change_script(&self) -> Result<Script, ()>;
+       /// Signs and provides the full [`TxIn::script_sig`] and [`TxIn::witness`] for all inputs within
+       /// the transaction known to the wallet (i.e., any provided via
+       /// [`WalletSource::list_confirmed_utxos`]).
+       fn sign_tx(&self, tx: Transaction) -> Result<Transaction, ()>;
+}
+
+/// A wrapper over [`WalletSource`] that implements [`CoinSelection`] by preferring UTXOs that would
+/// avoid conflicting double spends. If not enough UTXOs are available to do so, conflicting double
+/// spends may happen.
+pub struct Wallet<W: Deref, L: Deref>
+where
+       W::Target: WalletSource,
+       L::Target: Logger
+{
+       source: W,
+       logger: L,
+       // TODO: Do we care about cleaning this up once the UTXOs have a confirmed spend? We can do so
+       // by checking whether any UTXOs that exist in the map are no longer returned in
+       // `list_confirmed_utxos`.
+       locked_utxos: Mutex<HashMap<OutPoint, ClaimId>>,
+}
+
+impl<W: Deref, L: Deref> Wallet<W, L>
+where
+       W::Target: WalletSource,
+       L::Target: Logger
+{
+       /// Returns a new instance backed by the given [`WalletSource`] that serves as an implementation
+       /// of [`CoinSelectionSource`].
+       pub fn new(source: W, logger: L) -> Self {
+               Self { source, logger, locked_utxos: Mutex::new(HashMap::new()) }
+       }
+
+       /// Performs coin selection on the set of UTXOs obtained from
+       /// [`WalletSource::list_confirmed_utxos`]. Its algorithm can be described as "smallest
+       /// above-dust-after-spend first", with a slight twist: we may skip UTXOs that are above dust at
+       /// the target feerate after having spent them in a separate claim transaction if
+       /// `force_conflicting_utxo_spend` is unset to avoid producing conflicting transactions. If
+       /// `tolerate_high_network_feerates` is set, we'll attempt to spend UTXOs that contribute at
+       /// least 1 satoshi at the current feerate, otherwise, we'll only attempt to spend those which
+       /// contribute at least twice their fee.
+       fn select_confirmed_utxos_internal(
+               &self, utxos: &[Utxo], claim_id: ClaimId, force_conflicting_utxo_spend: bool,
+               tolerate_high_network_feerates: bool, target_feerate_sat_per_1000_weight: u32,
+               preexisting_tx_weight: u64, target_amount_sat: u64,
+       ) -> Result<CoinSelection, ()> {
+               let mut locked_utxos = self.locked_utxos.lock().unwrap();
+               let mut eligible_utxos = utxos.iter().filter_map(|utxo| {
+                       if let Some(utxo_claim_id) = locked_utxos.get(&utxo.outpoint) {
+                               if *utxo_claim_id != claim_id && !force_conflicting_utxo_spend {
+                                       log_trace!(self.logger, "Skipping UTXO {} to prevent conflicting spend", utxo.outpoint);
+                                       return None;
+                               }
+                       }
+                       let fee_to_spend_utxo = fee_for_weight(
+                               target_feerate_sat_per_1000_weight, BASE_INPUT_WEIGHT as u64 + utxo.satisfaction_weight,
+                       );
+                       let should_spend = if tolerate_high_network_feerates {
+                               utxo.output.value > fee_to_spend_utxo
+                       } else {
+                               utxo.output.value >= fee_to_spend_utxo * 2
+                       };
+                       if should_spend {
+                               Some((utxo, fee_to_spend_utxo))
+                       } else {
+                               log_trace!(self.logger, "Skipping UTXO {} due to dust proximity after spend", utxo.outpoint);
+                               None
+                       }
+               }).collect::<Vec<_>>();
+               eligible_utxos.sort_unstable_by_key(|(utxo, _)| utxo.output.value);
+
+               let mut selected_amount = 0;
+               let mut total_fees = fee_for_weight(target_feerate_sat_per_1000_weight, preexisting_tx_weight);
+               let mut selected_utxos = Vec::new();
+               for (utxo, fee_to_spend_utxo) in eligible_utxos {
+                       if selected_amount >= target_amount_sat + total_fees {
+                               break;
+                       }
+                       selected_amount += utxo.output.value;
+                       total_fees += fee_to_spend_utxo;
+                       selected_utxos.push(utxo.clone());
+               }
+               if selected_amount < target_amount_sat + total_fees {
+                       log_debug!(self.logger, "Insufficient funds to meet target feerate {} sat/kW",
+                               target_feerate_sat_per_1000_weight);
+                       return Err(());
+               }
+               for utxo in &selected_utxos {
+                       locked_utxos.insert(utxo.outpoint, claim_id);
+               }
+               core::mem::drop(locked_utxos);
+
+               let remaining_amount = selected_amount - target_amount_sat - total_fees;
+               let change_script = self.source.get_change_script()?;
+               let change_output_fee = fee_for_weight(
+                       target_feerate_sat_per_1000_weight,
+                       (8 /* value */ + change_script.consensus_encode(&mut sink()).unwrap() as u64) *
+                               WITNESS_SCALE_FACTOR as u64,
+               );
+               let change_output_amount = remaining_amount.saturating_sub(change_output_fee);
+               let change_output = if change_output_amount < change_script.dust_value().to_sat() {
+                       log_debug!(self.logger, "Coin selection attempt did not yield change output");
+                       None
+               } else {
+                       Some(TxOut { script_pubkey: change_script, value: change_output_amount })
+               };
+
+               Ok(CoinSelection {
+                       confirmed_utxos: selected_utxos,
+                       change_output,
+               })
+       }
+}
+
+impl<W: Deref, L: Deref> CoinSelectionSource for Wallet<W, L>
+where
+       W::Target: WalletSource,
+       L::Target: Logger
+{
+       fn select_confirmed_utxos(
+               &self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &[TxOut],
+               target_feerate_sat_per_1000_weight: u32,
+       ) -> Result<CoinSelection, ()> {
+               let utxos = self.source.list_confirmed_utxos()?;
+               // TODO: Use fee estimation utils when we upgrade to bitcoin v0.30.0.
+               const BASE_TX_SIZE: u64 = 4 /* version */ + 1 /* input count */ + 1 /* output count */ + 4 /* locktime */;
+               let total_output_size: u64 = must_pay_to.iter().map(|output|
+                       8 /* value */ + 1 /* script len */ + output.script_pubkey.len() as u64
+               ).sum();
+               let total_satisfaction_weight: u64 = must_spend.iter().map(|input| input.satisfaction_weight).sum();
+               let total_input_weight = (BASE_INPUT_WEIGHT * must_spend.len() as u64) + total_satisfaction_weight;
+
+               let preexisting_tx_weight = 2 /* segwit marker & flag */ + total_input_weight +
+                       ((BASE_TX_SIZE + total_output_size) * WITNESS_SCALE_FACTOR as u64);
+               let target_amount_sat = must_pay_to.iter().map(|output| output.value).sum();
+               let do_coin_selection = |force_conflicting_utxo_spend: bool, tolerate_high_network_feerates: bool| {
+                       log_debug!(self.logger, "Attempting coin selection targeting {} sat/kW (force_conflicting_utxo_spend = {}, tolerate_high_network_feerates = {})",
+                               target_feerate_sat_per_1000_weight, force_conflicting_utxo_spend, tolerate_high_network_feerates);
+                       self.select_confirmed_utxos_internal(
+                               &utxos, claim_id, force_conflicting_utxo_spend, tolerate_high_network_feerates,
+                               target_feerate_sat_per_1000_weight, preexisting_tx_weight, target_amount_sat,
+                       )
+               };
+               do_coin_selection(false, false)
+                       .or_else(|_| do_coin_selection(false, true))
+                       .or_else(|_| do_coin_selection(true, false))
+                       .or_else(|_| do_coin_selection(true, true))
+       }
+
+       fn sign_tx(&self, tx: Transaction) -> Result<Transaction, ()> {
+               self.source.sign_tx(tx)
+       }
+}
+
+/// A handler for [`Event::BumpTransaction`] events that sources confirmed UTXOs from a
+/// [`CoinSelectionSource`] to fee bump transactions via Child-Pays-For-Parent (CPFP) or
+/// Replace-By-Fee (RBF).
+///
+/// [`Event::BumpTransaction`]: crate::events::Event::BumpTransaction
+pub struct BumpTransactionEventHandler<B: Deref, C: Deref, SP: Deref, L: Deref>
+where
+       B::Target: BroadcasterInterface,
+       C::Target: CoinSelectionSource,
+       SP::Target: SignerProvider,
+       L::Target: Logger,
+{
+       broadcaster: B,
+       utxo_source: C,
+       signer_provider: SP,
+       logger: L,
+       secp: Secp256k1<secp256k1::All>,
+}
+
+impl<B: Deref, C: Deref, SP: Deref, L: Deref> BumpTransactionEventHandler<B, C, SP, L>
+where
+       B::Target: BroadcasterInterface,
+       C::Target: CoinSelectionSource,
+       SP::Target: SignerProvider,
+       L::Target: Logger,
+{
+       /// Returns a new instance capable of handling [`Event::BumpTransaction`] events.
+       ///
+       /// [`Event::BumpTransaction`]: crate::events::Event::BumpTransaction
+       pub fn new(broadcaster: B, utxo_source: C, signer_provider: SP, logger: L) -> Self {
+               Self {
+                       broadcaster,
+                       utxo_source,
+                       signer_provider,
+                       logger,
+                       secp: Secp256k1::new(),
+               }
+       }
+
+       /// Updates a transaction with the result of a successful coin selection attempt.
+       fn process_coin_selection(&self, tx: &mut Transaction, mut coin_selection: CoinSelection) {
+               for utxo in coin_selection.confirmed_utxos.drain(..) {
+                       tx.input.push(TxIn {
+                               previous_output: utxo.outpoint,
+                               script_sig: Script::new(),
+                               sequence: Sequence::ZERO,
+                               witness: Witness::new(),
+                       });
+               }
+               if let Some(change_output) = coin_selection.change_output.take() {
+                       tx.output.push(change_output);
+               } else if tx.output.is_empty() {
+                       // We weren't provided a change output, likely because the input set was a perfect
+                       // match, but we still need to have at least one output in the transaction for it to be
+                       // considered standard. We choose to go with an empty OP_RETURN as it is the cheapest
+                       // way to include a dummy output.
+                       log_debug!(self.logger, "Including dummy OP_RETURN output since an output is needed and a change output was not provided");
+                       tx.output.push(TxOut {
+                               value: 0,
+                               script_pubkey: Script::new_op_return(&[]),
+                       });
+               }
+       }
+
+       /// Handles a [`BumpTransactionEvent::ChannelClose`] event variant by producing a fully-signed
+       /// transaction spending an anchor output of the commitment transaction to bump its fee and
+       /// broadcasts them to the network as a package.
+       fn handle_channel_close(
+               &self, claim_id: ClaimId, package_target_feerate_sat_per_1000_weight: u32,
+               commitment_tx: &Transaction, commitment_tx_fee_sat: u64, anchor_descriptor: &AnchorDescriptor,
+       ) -> Result<(), ()> {
+               // Our commitment transaction already has fees allocated to it, so we should take them into
+               // account. We compute its feerate and subtract it from the package target, using the result
+               // as the target feerate for our anchor transaction. Unfortunately, this results in users
+               // overpaying by a small margin since we don't yet know the anchor transaction size, and
+               // avoiding the small overpayment only makes our API even more complex.
+               let commitment_tx_sat_per_1000_weight: u32 = compute_feerate_sat_per_1000_weight(
+                       commitment_tx_fee_sat, commitment_tx.weight() as u64,
+               );
+               let anchor_target_feerate_sat_per_1000_weight = core::cmp::max(
+                       package_target_feerate_sat_per_1000_weight - commitment_tx_sat_per_1000_weight,
+                       FEERATE_FLOOR_SATS_PER_KW,
+               );
+
+               log_debug!(self.logger, "Peforming coin selection for anchor transaction targeting {} sat/kW",
+                       anchor_target_feerate_sat_per_1000_weight);
+               let must_spend = vec![Input {
+                       outpoint: anchor_descriptor.outpoint,
+                       previous_utxo: anchor_descriptor.previous_utxo(),
+                       satisfaction_weight: commitment_tx.weight() as u64 + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT,
+               }];
+               let coin_selection = self.utxo_source.select_confirmed_utxos(
+                       claim_id, must_spend, &[], anchor_target_feerate_sat_per_1000_weight,
+               )?;
+
+               let mut anchor_tx = Transaction {
+                       version: 2,
+                       lock_time: PackedLockTime::ZERO, // TODO: Use next best height.
+                       input: vec![anchor_descriptor.unsigned_tx_input()],
+                       output: vec![],
+               };
+               #[cfg(debug_assertions)]
+               let total_satisfaction_weight =
+                       coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::<u64>() +
+                               ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT;
+
+               self.process_coin_selection(&mut anchor_tx, coin_selection);
+               let anchor_txid = anchor_tx.txid();
+
+               debug_assert_eq!(anchor_tx.output.len(), 1);
+               #[cfg(debug_assertions)]
+               let unsigned_tx_weight = anchor_tx.weight() as u64 - (anchor_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
+
+               log_debug!(self.logger, "Signing anchor transaction {}", anchor_txid);
+               anchor_tx = self.utxo_source.sign_tx(anchor_tx)?;
+
+               let signer = anchor_descriptor.derive_channel_signer(&self.signer_provider);
+               let anchor_sig = signer.sign_holder_anchor_input(&anchor_tx, 0, &self.secp)?;
+               anchor_tx.input[0].witness = anchor_descriptor.tx_input_witness(&anchor_sig);
+
+               #[cfg(debug_assertions)] {
+                       let signed_tx_weight = anchor_tx.weight() as u64;
+                       let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight;
+                       // Our estimate should be within a 1% error margin of the actual weight and we should
+                       // never underestimate.
+                       assert!(expected_signed_tx_weight >= signed_tx_weight &&
+                               expected_signed_tx_weight - (expected_signed_tx_weight / 100) <= signed_tx_weight);
+               }
+
+               log_info!(self.logger, "Broadcasting anchor transaction {} to bump channel close with txid {}",
+                       anchor_txid, commitment_tx.txid());
+               self.broadcaster.broadcast_transactions(&[&commitment_tx, &anchor_tx]);
+               Ok(())
+       }
+
+       /// Handles a [`BumpTransactionEvent::HTLCResolution`] event variant by producing a
+       /// fully-signed, fee-bumped HTLC transaction that is broadcast to the network.
+       fn handle_htlc_resolution(
+               &self, claim_id: ClaimId, target_feerate_sat_per_1000_weight: u32,
+               htlc_descriptors: &[HTLCDescriptor], tx_lock_time: PackedLockTime,
+       ) -> Result<(), ()> {
+               let mut htlc_tx = Transaction {
+                       version: 2,
+                       lock_time: tx_lock_time,
+                       input: vec![],
+                       output: vec![],
+               };
+               let mut must_spend = Vec::with_capacity(htlc_descriptors.len());
+               for htlc_descriptor in htlc_descriptors {
+                       let htlc_input = htlc_descriptor.unsigned_tx_input();
+                       must_spend.push(Input {
+                               outpoint: htlc_input.previous_output.clone(),
+                               previous_utxo: htlc_descriptor.previous_utxo(&self.secp),
+                               satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + if htlc_descriptor.preimage.is_some() {
+                                       HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT
+                               } else {
+                                       HTLC_TIMEOUT_INPUT_ANCHOR_WITNESS_WEIGHT
+                               },
+                       });
+                       htlc_tx.input.push(htlc_input);
+                       let htlc_output = htlc_descriptor.tx_output(&self.secp);
+                       htlc_tx.output.push(htlc_output);
+               }
+
+               log_debug!(self.logger, "Peforming coin selection for HTLC transaction targeting {} sat/kW",
+                       target_feerate_sat_per_1000_weight);
+               #[cfg(debug_assertions)]
+               let must_spend_satisfaction_weight =
+                       must_spend.iter().map(|input| input.satisfaction_weight).sum::<u64>();
+               let coin_selection = self.utxo_source.select_confirmed_utxos(
+                       claim_id, must_spend, &htlc_tx.output, target_feerate_sat_per_1000_weight,
+               )?;
+               #[cfg(debug_assertions)]
+               let total_satisfaction_weight =
+                       coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::<u64>() +
+                               must_spend_satisfaction_weight;
+               self.process_coin_selection(&mut htlc_tx, coin_selection);
+
+               #[cfg(debug_assertions)]
+               let unsigned_tx_weight = htlc_tx.weight() as u64 - (htlc_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
+
+               log_debug!(self.logger, "Signing HTLC transaction {}", htlc_tx.txid());
+               htlc_tx = self.utxo_source.sign_tx(htlc_tx)?;
+
+               let mut signers = BTreeMap::new();
+               for (idx, htlc_descriptor) in htlc_descriptors.iter().enumerate() {
+                       let signer = signers.entry(htlc_descriptor.channel_derivation_parameters.keys_id)
+                               .or_insert_with(|| htlc_descriptor.derive_channel_signer(&self.signer_provider));
+                       let htlc_sig = signer.sign_holder_htlc_transaction(&htlc_tx, idx, htlc_descriptor, &self.secp)?;
+                       let witness_script = htlc_descriptor.witness_script(&self.secp);
+                       htlc_tx.input[idx].witness = htlc_descriptor.tx_input_witness(&htlc_sig, &witness_script);
+               }
+
+               #[cfg(debug_assertions)] {
+                       let signed_tx_weight = htlc_tx.weight() as u64;
+                       let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight;
+                       // Our estimate should be within a 1% error margin of the actual weight and we should
+                       // never underestimate.
+                       assert!(expected_signed_tx_weight >= signed_tx_weight &&
+                               expected_signed_tx_weight - (expected_signed_tx_weight / 100) <= signed_tx_weight);
+               }
+
+               log_info!(self.logger, "Broadcasting {}", log_tx!(htlc_tx));
+               self.broadcaster.broadcast_transactions(&[&htlc_tx]);
+               Ok(())
+       }
+
+       /// Handles all variants of [`BumpTransactionEvent`].
+       pub fn handle_event(&self, event: &BumpTransactionEvent) {
+               match event {
+                       BumpTransactionEvent::ChannelClose {
+                               claim_id, package_target_feerate_sat_per_1000_weight, commitment_tx,
+                               commitment_tx_fee_satoshis, anchor_descriptor, ..
+                       } => {
+                               log_info!(self.logger, "Handling channel close bump (claim_id = {}, commitment_txid = {})",
+                                       log_bytes!(claim_id.0), commitment_tx.txid());
+                               if let Err(_) = self.handle_channel_close(
+                                       *claim_id, *package_target_feerate_sat_per_1000_weight, commitment_tx,
+                                       *commitment_tx_fee_satoshis, anchor_descriptor,
+                               ) {
+                                       log_error!(self.logger, "Failed bumping commitment transaction fee for {}",
+                                               commitment_tx.txid());
+                               }
+                       }
+                       BumpTransactionEvent::HTLCResolution {
+                               claim_id, target_feerate_sat_per_1000_weight, htlc_descriptors, tx_lock_time,
+                       } => {
+                               log_info!(self.logger, "Handling HTLC bump (claim_id = {}, htlcs_to_claim = {})",
+                                       log_bytes!(claim_id.0), log_iter!(htlc_descriptors.iter().map(|d| d.outpoint())));
+                               if let Err(_) = self.handle_htlc_resolution(
+                                       *claim_id, *target_feerate_sat_per_1000_weight, htlc_descriptors, *tx_lock_time,
+                               ) {
+                                       log_error!(self.logger, "Failed bumping HTLC transaction fee for commitment {}",
+                                               htlc_descriptors[0].commitment_txid);
+                               }
+                       }
+               }
+       }
+}
index 76a7f884ad27ceb3a1550e1b7235bf7dc8795f6d..d08e563cbf6195e4566bae0691b783e947033156 100644 (file)
 //! future, as well as generate and broadcast funding transactions handle payment preimages and a
 //! few other things.
 
-#[cfg(anchors)]
 pub mod bump_transaction;
 
-#[cfg(anchors)]
 pub use bump_transaction::BumpTransactionEvent;
 
 use crate::sign::SpendableOutputDescriptor;
@@ -33,8 +31,6 @@ use crate::util::string::UntrustedString;
 use crate::routing::router::{BlindedTail, Path, RouteHop, RouteParameters};
 
 use bitcoin::{PackedLockTime, Transaction, OutPoint};
-#[cfg(anchors)]
-use bitcoin::{Txid, TxIn, TxOut, Witness};
 use bitcoin::blockdata::script::Script;
 use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
@@ -117,7 +113,7 @@ impl_writeable_tlv_based_enum_upgradable!(PathFailure,
 );
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-/// The reason the channel was closed. See individual variants more details.
+/// The reason the channel was closed. See individual variants for more details.
 pub enum ClosureReason {
        /// Closure generated from receiving a peer error message.
        ///
@@ -168,7 +164,10 @@ pub enum ClosureReason {
        ///
        /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor
        /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
-       OutdatedChannelManager
+       OutdatedChannelManager,
+       /// The counterparty requested a cooperative close of a channel that had not been funded yet.
+       /// The channel has been immediately closed.
+       CounterpartyCoopClosedUnfundedChannel,
 }
 
 impl core::fmt::Display for ClosureReason {
@@ -188,6 +187,7 @@ impl core::fmt::Display for ClosureReason {
                        },
                        ClosureReason::DisconnectedPeer => f.write_str("the peer disconnected prior to the channel being funded"),
                        ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
+                       ClosureReason::CounterpartyCoopClosedUnfundedChannel => f.write_str("the peer requested the unfunded channel be closed"),
                }
        }
 }
@@ -201,6 +201,7 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
        (8, ProcessingError) => { (1, err, required) },
        (10, DisconnectedPeer) => {},
        (12, OutdatedChannelManager) => {},
+       (13, CounterpartyCoopClosedUnfundedChannel) => {},
 );
 
 /// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].
@@ -387,8 +388,25 @@ pub enum Event {
                ///
                /// Payments received on LDK versions prior to 0.0.115 will have this field unset.
                onion_fields: Option<RecipientOnionFields>,
-               /// The value, in thousandths of a satoshi, that this payment is for.
+               /// The value, in thousandths of a satoshi, that this payment is claimable for. May be greater
+               /// than the invoice amount.
+               ///
+               /// May be less than the invoice amount if [`ChannelConfig::accept_underpaying_htlcs`] is set
+               /// and the previous hop took an extra fee.
+               ///
+               /// # Note
+               /// If [`ChannelConfig::accept_underpaying_htlcs`] is set and you claim without verifying this
+               /// field, you may lose money!
+               ///
+               /// [`ChannelConfig::accept_underpaying_htlcs`]: crate::util::config::ChannelConfig::accept_underpaying_htlcs
                amount_msat: u64,
+               /// The value, in thousands of a satoshi, that was skimmed off of this payment as an extra fee
+               /// taken by our channel counterparty.
+               ///
+               /// Will always be 0 unless [`ChannelConfig::accept_underpaying_htlcs`] is set.
+               ///
+               /// [`ChannelConfig::accept_underpaying_htlcs`]: crate::util::config::ChannelConfig::accept_underpaying_htlcs
+               counterparty_skimmed_fee_msat: u64,
                /// Information for claiming this received payment, based on whether the purpose of the
                /// payment is to pay an invoice or to send a spontaneous payment.
                purpose: PaymentPurpose,
@@ -430,7 +448,8 @@ pub enum Event {
                /// The payment hash of the claimed payment. Note that LDK will not stop you from
                /// registering duplicate payment hashes for inbound payments.
                payment_hash: PaymentHash,
-               /// The value, in thousandths of a satoshi, that this payment is for.
+               /// The value, in thousandths of a satoshi, that this payment is for. May be greater than the
+               /// invoice amount.
                amount_msat: u64,
                /// The purpose of the claimed payment, i.e. whether the payment was for an invoice or a
                /// spontaneous payment.
@@ -623,6 +642,7 @@ pub enum Event {
                inbound_amount_msat: u64,
                /// How many msats the payer intended to route to the next node. Depending on the reason you are
                /// intercepting this payment, you might take a fee by forwarding less than this amount.
+               /// Forwarding less than this amount may break compatibility with LDK versions prior to 0.0.116.
                ///
                /// Note that LDK will NOT check that expected fees were factored into this value. You MUST
                /// check that whatever fee you want has been included here or subtract it as required. Further,
@@ -815,12 +835,14 @@ pub enum Event {
                /// Destination of the HTLC that failed to be processed.
                failed_next_destination: HTLCDestination,
        },
-       #[cfg(anchors)]
        /// Indicates that a transaction originating from LDK needs to have its fee bumped. This event
        /// requires confirmed external funds to be readily available to spend.
        ///
-       /// LDK does not currently generate this event. It is limited to the scope of channels with
-       /// anchor outputs, which will be introduced in a future release.
+       /// LDK does not currently generate this event unless the
+       /// [`ChannelHandshakeConfig::negotiate_anchors_zero_fee_htlc_tx`] config flag is set to true.
+       /// It is limited to the scope of channels with anchor outputs.
+       ///
+       /// [`ChannelHandshakeConfig::negotiate_anchors_zero_fee_htlc_tx`]: crate::util::config::ChannelHandshakeConfig::negotiate_anchors_zero_fee_htlc_tx
        BumpTransaction(BumpTransactionEvent),
 }
 
@@ -832,8 +854,8 @@ impl Writeable for Event {
                                // We never write out FundingGenerationReady events as, upon disconnection, peers
                                // drop any channels which have not yet exchanged funding_signed.
                        },
-                       &Event::PaymentClaimable { ref payment_hash, ref amount_msat, ref purpose,
-                               ref receiver_node_id, ref via_channel_id, ref via_user_channel_id,
+                       &Event::PaymentClaimable { ref payment_hash, ref amount_msat, counterparty_skimmed_fee_msat,
+                               ref purpose, ref receiver_node_id, ref via_channel_id, ref via_user_channel_id,
                                ref claim_deadline, ref onion_fields
                        } => {
                                1u8.write(writer)?;
@@ -848,6 +870,8 @@ impl Writeable for Event {
                                                payment_preimage = Some(*preimage);
                                        }
                                }
+                               let skimmed_fee_opt = if counterparty_skimmed_fee_msat == 0 { None }
+                                       else { Some(counterparty_skimmed_fee_msat) };
                                write_tlv_fields!(writer, {
                                        (0, payment_hash, required),
                                        (1, receiver_node_id, option),
@@ -855,10 +879,11 @@ impl Writeable for Event {
                                        (3, via_channel_id, option),
                                        (4, amount_msat, required),
                                        (5, via_user_channel_id, option),
-                                       (6, 0u64, required), // user_payment_id required for compatibility with 0.0.103 and earlier
+                                       // Type 6 was `user_payment_id` on 0.0.103 and earlier
                                        (7, claim_deadline, option),
                                        (8, payment_preimage, option),
                                        (9, onion_fields, option),
+                                       (10, skimmed_fee_opt, option),
                                });
                        },
                        &Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
@@ -889,7 +914,7 @@ impl Writeable for Event {
                                        (2, payment_failed_permanently, required),
                                        (3, false, required), // all_paths_failed in LDK versions prior to 0.0.114
                                        (4, path.blinded_tail, option),
-                                       (5, path.hops, vec_type),
+                                       (5, path.hops, required_vec),
                                        (7, short_channel_id, option),
                                        (9, None::<RouteParameters>, option), // retry in LDK versions prior to 0.0.115
                                        (11, payment_id, option),
@@ -957,7 +982,7 @@ impl Writeable for Event {
                                write_tlv_fields!(writer, {
                                        (0, payment_id, required),
                                        (2, payment_hash, option),
-                                       (4, path.hops, vec_type),
+                                       (4, path.hops, required_vec),
                                        (6, path.blinded_tail, option),
                                })
                        },
@@ -988,7 +1013,7 @@ impl Writeable for Event {
                                write_tlv_fields!(writer, {
                                        (0, payment_id, required),
                                        (2, payment_hash, required),
-                                       (4, path.hops, vec_type),
+                                       (4, path.hops, required_vec),
                                        (6, path.blinded_tail, option),
                                })
                        },
@@ -997,7 +1022,7 @@ impl Writeable for Event {
                                write_tlv_fields!(writer, {
                                        (0, payment_id, required),
                                        (2, payment_hash, required),
-                                       (4, path.hops, vec_type),
+                                       (4, path.hops, required_vec),
                                        (6, short_channel_id, option),
                                        (8, path.blinded_tail, option),
                                })
@@ -1009,7 +1034,6 @@ impl Writeable for Event {
                                        (2, failed_next_destination, required),
                                })
                        },
-                       #[cfg(anchors)]
                        &Event::BumpTransaction(ref event)=> {
                                27u8.write(writer)?;
                                match event {
@@ -1058,8 +1082,9 @@ impl MaybeReadable for Event {
                                        let mut payment_preimage = None;
                                        let mut payment_secret = None;
                                        let mut amount_msat = 0;
+                                       let mut counterparty_skimmed_fee_msat_opt = None;
                                        let mut receiver_node_id = None;
-                                       let mut _user_payment_id = None::<u64>; // For compatibility with 0.0.103 and earlier
+                                       let mut _user_payment_id = None::<u64>; // Used in 0.0.103 and earlier, no longer written in 0.0.116+.
                                        let mut via_channel_id = None;
                                        let mut claim_deadline = None;
                                        let mut via_user_channel_id = None;
@@ -1075,6 +1100,7 @@ impl MaybeReadable for Event {
                                                (7, claim_deadline, option),
                                                (8, payment_preimage, option),
                                                (9, onion_fields, option),
+                                               (10, counterparty_skimmed_fee_msat_opt, option),
                                        });
                                        let purpose = match payment_secret {
                                                Some(secret) => PaymentPurpose::InvoicePayment {
@@ -1088,6 +1114,7 @@ impl MaybeReadable for Event {
                                                receiver_node_id,
                                                payment_hash,
                                                amount_msat,
+                                               counterparty_skimmed_fee_msat: counterparty_skimmed_fee_msat_opt.unwrap_or(0),
                                                purpose,
                                                via_channel_id,
                                                via_user_channel_id,
@@ -1140,7 +1167,9 @@ impl MaybeReadable for Event {
                                                (1, network_update, upgradable_option),
                                                (2, payment_failed_permanently, required),
                                                (4, blinded_tail, option),
-                                               (5, path, vec_type),
+                                               // Added as a part of LDK 0.0.101 and always filled in since.
+                                               // Defaults to an empty Vec, though likely should have been `Option`al.
+                                               (5, path, optional_vec),
                                                (7, short_channel_id, option),
                                                (11, payment_id, option),
                                                (13, failure_opt, upgradable_option),
@@ -1257,13 +1286,13 @@ impl MaybeReadable for Event {
                                        _init_and_read_tlv_fields!(reader, {
                                                (0, payment_id, required),
                                                (2, payment_hash, option),
-                                               (4, path, vec_type),
+                                               (4, path, required_vec),
                                                (6, blinded_tail, option),
                                        });
                                        Ok(Some(Event::PaymentPathSuccessful {
                                                payment_id: payment_id.0.unwrap(),
                                                payment_hash,
-                                               path: Path { hops: path.unwrap(), blinded_tail },
+                                               path: Path { hops: path, blinded_tail },
                                        }))
                                };
                                f()
@@ -1316,13 +1345,13 @@ impl MaybeReadable for Event {
                                        _init_and_read_tlv_fields!(reader, {
                                                (0, payment_id, required),
                                                (2, payment_hash, required),
-                                               (4, path, vec_type),
+                                               (4, path, required_vec),
                                                (6, blinded_tail, option),
                                        });
                                        Ok(Some(Event::ProbeSuccessful {
                                                payment_id: payment_id.0.unwrap(),
                                                payment_hash: payment_hash.0.unwrap(),
-                                               path: Path { hops: path.unwrap(), blinded_tail },
+                                               path: Path { hops: path, blinded_tail },
                                        }))
                                };
                                f()
@@ -1332,14 +1361,14 @@ impl MaybeReadable for Event {
                                        _init_and_read_tlv_fields!(reader, {
                                                (0, payment_id, required),
                                                (2, payment_hash, required),
-                                               (4, path, vec_type),
+                                               (4, path, required_vec),
                                                (6, short_channel_id, option),
                                                (8, blinded_tail, option),
                                        });
                                        Ok(Some(Event::ProbeFailed {
                                                payment_id: payment_id.0.unwrap(),
                                                payment_hash: payment_hash.0.unwrap(),
-                                               path: Path { hops: path.unwrap(), blinded_tail },
+                                               path: Path { hops: path, blinded_tail },
                                                short_channel_id,
                                        }))
                                };
index cea15b21ad2fba1b6f1937b030d59551bede682c..cf0a04aab081f458b586e1c9f87c0ab7cc305e55 100644 (file)
@@ -38,7 +38,7 @@
 //!     * `max_level_trace`
 
 #![cfg_attr(not(any(test, fuzzing, feature = "_test_utils")), deny(missing_docs))]
-#![cfg_attr(not(any(test, fuzzing, feature = "_test_utils")), forbid(unsafe_code))]
+#![cfg_attr(not(any(test, feature = "_test_utils")), forbid(unsafe_code))]
 
 // Prefix these with `rustdoc::` when we update our MSRV to be >= 1.52 to remove warnings.
 #![deny(broken_intra_doc_links)]
@@ -67,7 +67,7 @@ extern crate bitcoin;
 extern crate core;
 
 #[cfg(any(test, feature = "_test_utils"))] extern crate hex;
-#[cfg(any(test, fuzzing, feature = "_test_utils"))] extern crate regex;
+#[cfg(any(test, feature = "_test_utils"))] extern crate regex;
 
 #[cfg(not(feature = "std"))] extern crate core2;
 
index b3b87146792af6bed47fcbf236192e7cb8aa7982..85490afaec1292bf792d245c18b13c3b54d78b0a 100644 (file)
@@ -24,7 +24,7 @@ use bitcoin::hash_types::{Txid, PubkeyHash};
 use crate::sign::EntropySource;
 use crate::ln::{PaymentHash, PaymentPreimage};
 use crate::ln::msgs::DecodeError;
-use crate::util::ser::{Readable, Writeable, Writer};
+use crate::util::ser::{Readable, RequiredWrapper, Writeable, Writer};
 use crate::util::transaction_utils;
 
 use bitcoin::secp256k1::{SecretKey, PublicKey, Scalar};
@@ -40,6 +40,7 @@ use crate::util::transaction_utils::sort_outputs;
 use crate::ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE_SATOSHI};
 use core::ops::Deref;
 use crate::chain;
+use crate::ln::features::ChannelTypeFeatures;
 use crate::util::crypto::{sign, sign_with_aux_rand};
 
 /// Maximum number of one-way in-flight HTLC (protocol-level value).
@@ -57,20 +58,29 @@ pub(crate) const MIN_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 136;
 /// This is the maximum post-anchor value.
 pub const MAX_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 143;
 
+/// The upper bound weight of an anchor input.
+pub const ANCHOR_INPUT_WITNESS_WEIGHT: u64 = 116;
+/// The upper bound weight of an HTLC timeout input from a commitment transaction with anchor
+/// outputs.
+pub const HTLC_TIMEOUT_INPUT_ANCHOR_WITNESS_WEIGHT: u64 = 288;
+/// The upper bound weight of an HTLC success input from a commitment transaction with anchor
+/// outputs.
+pub const HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT: u64 = 327;
+
 /// Gets the weight for an HTLC-Success transaction.
 #[inline]
-pub fn htlc_success_tx_weight(opt_anchors: bool) -> u64 {
+pub fn htlc_success_tx_weight(channel_type_features: &ChannelTypeFeatures) -> u64 {
        const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
        const HTLC_SUCCESS_ANCHOR_TX_WEIGHT: u64 = 706;
-       if opt_anchors { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT }
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT }
 }
 
 /// Gets the weight for an HTLC-Timeout transaction.
 #[inline]
-pub fn htlc_timeout_tx_weight(opt_anchors: bool) -> u64 {
+pub fn htlc_timeout_tx_weight(channel_type_features: &ChannelTypeFeatures) -> u64 {
        const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
        const HTLC_TIMEOUT_ANCHOR_TX_WEIGHT: u64 = 666;
-       if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT }
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT }
 }
 
 /// Describes the type of HTLC claim as determined by analyzing the witness.
@@ -574,7 +584,7 @@ impl_writeable_tlv_based!(HTLCOutputInCommitment, {
 });
 
 #[inline]
-pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, opt_anchors: bool, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
+pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
        let payment_hash160 = Ripemd160::hash(&htlc.payment_hash.0[..]).into_inner();
        if htlc.offered {
                let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP)
@@ -602,7 +612,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit
                              .push_opcode(opcodes::all::OP_EQUALVERIFY)
                              .push_opcode(opcodes::all::OP_CHECKSIG)
                              .push_opcode(opcodes::all::OP_ENDIF);
-               if opt_anchors {
+               if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
                        bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1)
                                .push_opcode(opcodes::all::OP_CSV)
                                .push_opcode(opcodes::all::OP_DROP);
@@ -638,7 +648,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit
                              .push_opcode(opcodes::all::OP_DROP)
                              .push_opcode(opcodes::all::OP_CHECKSIG)
                              .push_opcode(opcodes::all::OP_ENDIF);
-               if opt_anchors {
+               if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
                        bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1)
                                .push_opcode(opcodes::all::OP_CSV)
                                .push_opcode(opcodes::all::OP_DROP);
@@ -651,8 +661,8 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit
 /// Gets the witness redeemscript for an HTLC output in a commitment transaction. Note that htlc
 /// does not need to have its previous_output_index filled.
 #[inline]
-pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, opt_anchors: bool, keys: &TxCreationKeys) -> Script {
-       get_htlc_redeemscript_with_explicit_keys(htlc, opt_anchors, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key)
+pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, keys: &TxCreationKeys) -> Script {
+       get_htlc_redeemscript_with_explicit_keys(htlc, channel_type_features, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key)
 }
 
 /// Gets the redeemscript for a funding output from the two funding public keys.
@@ -682,13 +692,13 @@ pub(crate) fn make_funding_redeemscript_from_slices(broadcaster_funding_key: &[u
 ///
 /// Panics if htlc.transaction_output_index.is_none() (as such HTLCs do not appear in the
 /// commitment transaction).
-pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool, use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
+pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
        let mut txins: Vec<TxIn> = Vec::new();
-       txins.push(build_htlc_input(commitment_txid, htlc, opt_anchors));
+       txins.push(build_htlc_input(commitment_txid, htlc, channel_type_features));
 
        let mut txouts: Vec<TxOut> = Vec::new();
        txouts.push(build_htlc_output(
-               feerate_per_kw, contest_delay, htlc, opt_anchors, use_non_zero_fee_anchors,
+               feerate_per_kw, contest_delay, htlc, channel_type_features,
                broadcaster_delayed_payment_key, revocation_key
        ));
 
@@ -700,28 +710,27 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte
        }
 }
 
-pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, opt_anchors: bool) -> TxIn {
+pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures) -> TxIn {
        TxIn {
                previous_output: OutPoint {
                        txid: commitment_txid.clone(),
                        vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"),
                },
                script_sig: Script::new(),
-               sequence: Sequence(if opt_anchors { 1 } else { 0 }),
+               sequence: Sequence(if channel_type_features.supports_anchors_zero_fee_htlc_tx() { 1 } else { 0 }),
                witness: Witness::new(),
        }
 }
 
 pub(crate) fn build_htlc_output(
-       feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool,
-       use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey
+       feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey
 ) -> TxOut {
        let weight = if htlc.offered {
-               htlc_timeout_tx_weight(opt_anchors)
+               htlc_timeout_tx_weight(channel_type_features)
        } else {
-               htlc_success_tx_weight(opt_anchors)
+               htlc_success_tx_weight(channel_type_features)
        };
-       let output_value = if opt_anchors && !use_non_zero_fee_anchors {
+       let output_value = if channel_type_features.supports_anchors_zero_fee_htlc_tx() && !channel_type_features.supports_anchors_nonzero_fee_htlc_tx() {
                htlc.amount_msat / 1000
        } else {
                let total_fee = feerate_per_kw as u64 * weight / 1000;
@@ -737,9 +746,9 @@ pub(crate) fn build_htlc_output(
 /// Returns the witness required to satisfy and spend a HTLC input.
 pub fn build_htlc_input_witness(
        local_sig: &Signature, remote_sig: &Signature, preimage: &Option<PaymentPreimage>,
-       redeem_script: &Script, opt_anchors: bool,
+       redeem_script: &Script, channel_type_features: &ChannelTypeFeatures,
 ) -> Witness {
-       let remote_sighash_type = if opt_anchors {
+       let remote_sighash_type = if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
                EcdsaSighashType::SinglePlusAnyoneCanPay
        } else {
                EcdsaSighashType::All
@@ -760,6 +769,37 @@ pub fn build_htlc_input_witness(
        witness
 }
 
+/// Pre-anchors channel type features did not use to get serialized in the following six structs:
+/// â€” [`ChannelTransactionParameters`]
+/// â€” [`CommitmentTransaction`]
+/// â€” [`CounterpartyOfferedHTLCOutput`]
+/// â€” [`CounterpartyReceivedHTLCOutput`]
+/// â€” [`HolderHTLCOutput`]
+/// â€” [`HolderFundingOutput`]
+///
+/// To ensure a forwards-compatible serialization, we use odd TLV fields. However, if new features
+/// are used that could break security, where old signers should be prevented from handling the
+/// serialized data, an optional even-field TLV will be used as a stand-in to break compatibility.
+///
+/// This method determines whether or not that option needs to be set based on the chanenl type
+/// features, and returns it.
+///
+/// [`CounterpartyOfferedHTLCOutput`]: crate::chain::package::CounterpartyOfferedHTLCOutput
+/// [`CounterpartyReceivedHTLCOutput`]: crate::chain::package::CounterpartyReceivedHTLCOutput
+/// [`HolderHTLCOutput`]: crate::chain::package::HolderHTLCOutput
+/// [`HolderFundingOutput`]: crate::chain::package::HolderFundingOutput
+pub(crate) fn legacy_deserialization_prevention_marker_for_channel_type_features(features: &ChannelTypeFeatures) -> Option<()> {
+       let mut legacy_version_bit_set = ChannelTypeFeatures::only_static_remote_key();
+       legacy_version_bit_set.set_scid_privacy_required();
+       legacy_version_bit_set.set_zero_conf_required();
+
+       if features.is_subset(&legacy_version_bit_set) {
+               None
+       } else {
+               Some(())
+       }
+}
+
 /// Gets the witnessScript for the to_remote output when anchors are enabled.
 #[inline]
 pub fn get_to_countersignatory_with_anchors_redeemscript(payment_point: &PublicKey) -> Script {
@@ -789,7 +829,6 @@ pub fn get_anchor_redeemscript(funding_pubkey: &PublicKey) -> Script {
                .into_script()
 }
 
-#[cfg(anchors)]
 /// Locates the output with an anchor script paying to `funding_pubkey` within `commitment_tx`.
 pub(crate) fn get_anchor_output<'a>(commitment_tx: &'a Transaction, funding_pubkey: &PublicKey) -> Option<(u32, &'a TxOut)> {
        let anchor_script = chan_utils::get_anchor_redeemscript(funding_pubkey).to_v0_p2wsh();
@@ -826,13 +865,9 @@ pub struct ChannelTransactionParameters {
        pub counterparty_parameters: Option<CounterpartyChannelTransactionParameters>,
        /// The late-bound funding outpoint
        pub funding_outpoint: Option<chain::transaction::OutPoint>,
-       /// Are anchors (zero fee HTLC transaction variant) used for this channel. Boolean is
-       /// serialization backwards-compatible.
-       pub opt_anchors: Option<()>,
-       /// Are non-zero-fee anchors are enabled (used in conjuction with opt_anchors)
-       /// It is intended merely for backwards compatibility with signers that need it.
-       /// There is no support for this feature in LDK channel negotiation.
-       pub opt_non_zero_fee_anchors: Option<()>,
+       /// This channel's type, as negotiated during channel open. For old objects where this field
+       /// wasn't serialized, it will default to static_remote_key at deserialization.
+       pub channel_type_features: ChannelTypeFeatures
 }
 
 /// Late-bound per-channel counterparty data used to build transactions.
@@ -880,15 +915,56 @@ impl_writeable_tlv_based!(CounterpartyChannelTransactionParameters, {
        (2, selected_contest_delay, required),
 });
 
-impl_writeable_tlv_based!(ChannelTransactionParameters, {
-       (0, holder_pubkeys, required),
-       (2, holder_selected_contest_delay, required),
-       (4, is_outbound_from_holder, required),
-       (6, counterparty_parameters, option),
-       (8, funding_outpoint, option),
-       (10, opt_anchors, option),
-       (12, opt_non_zero_fee_anchors, option),
-});
+impl Writeable for ChannelTransactionParameters {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               let legacy_deserialization_prevention_marker = legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features);
+               write_tlv_fields!(writer, {
+                       (0, self.holder_pubkeys, required),
+                       (2, self.holder_selected_contest_delay, required),
+                       (4, self.is_outbound_from_holder, required),
+                       (6, self.counterparty_parameters, option),
+                       (8, self.funding_outpoint, option),
+                       (10, legacy_deserialization_prevention_marker, option),
+                       (11, self.channel_type_features, required),
+               });
+               Ok(())
+       }
+}
+
+impl Readable for ChannelTransactionParameters {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               let mut holder_pubkeys = RequiredWrapper(None);
+               let mut holder_selected_contest_delay = RequiredWrapper(None);
+               let mut is_outbound_from_holder = RequiredWrapper(None);
+               let mut counterparty_parameters = None;
+               let mut funding_outpoint = None;
+               let mut _legacy_deserialization_prevention_marker: Option<()> = None;
+               let mut channel_type_features = None;
+
+               read_tlv_fields!(reader, {
+                       (0, holder_pubkeys, required),
+                       (2, holder_selected_contest_delay, required),
+                       (4, is_outbound_from_holder, required),
+                       (6, counterparty_parameters, option),
+                       (8, funding_outpoint, option),
+                       (10, _legacy_deserialization_prevention_marker, option),
+                       (11, channel_type_features, option),
+               });
+
+               let mut additional_features = ChannelTypeFeatures::empty();
+               additional_features.set_anchors_nonzero_fee_htlc_tx_required();
+               chain::package::verify_channel_type_features(&channel_type_features, Some(&additional_features))?;
+
+               Ok(Self {
+                       holder_pubkeys: holder_pubkeys.0.unwrap(),
+                       holder_selected_contest_delay: holder_selected_contest_delay.0.unwrap(),
+                       is_outbound_from_holder: is_outbound_from_holder.0.unwrap(),
+                       counterparty_parameters,
+                       funding_outpoint,
+                       channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key())
+               })
+       }
+}
 
 /// Static channel fields used to build transactions given per-commitment fields, organized by
 /// broadcaster/countersignatory.
@@ -942,8 +1018,8 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
        }
 
        /// Whether to use anchors for this channel
-       pub fn opt_anchors(&self) -> bool {
-               self.inner.opt_anchors.is_some()
+       pub fn channel_type_features(&self) -> &ChannelTypeFeatures {
+               &self.inner.channel_type_features
        }
 }
 
@@ -980,7 +1056,7 @@ impl_writeable_tlv_based!(HolderCommitmentTransaction, {
        (0, inner, required),
        (2, counterparty_sig, required),
        (4, holder_sig_first, required),
-       (6, counterparty_htlc_sigs, vec_type),
+       (6, counterparty_htlc_sigs, required_vec),
 });
 
 impl HolderCommitmentTransaction {
@@ -1010,14 +1086,13 @@ impl HolderCommitmentTransaction {
                        is_outbound_from_holder: false,
                        counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }),
                        funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }),
-                       opt_anchors: None,
-                       opt_non_zero_fee_anchors: None,
+                       channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
                };
                let mut counterparty_htlc_sigs = Vec::new();
                for _ in 0..htlcs.len() {
                        counterparty_htlc_sigs.push(dummy_sig);
                }
-               let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, false, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable());
+               let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable());
                htlcs.sort_by_key(|htlc| htlc.0.transaction_output_index);
                HolderCommitmentTransaction {
                        inner,
@@ -1235,10 +1310,8 @@ pub struct CommitmentTransaction {
        to_countersignatory_value_sat: u64,
        feerate_per_kw: u32,
        htlcs: Vec<HTLCOutputInCommitment>,
-       // A boolean that is serialization backwards-compatible
-       opt_anchors: Option<()>,
-       // Whether non-zero-fee anchors should be used
-       opt_non_zero_fee_anchors: Option<()>,
+       // Note that on upgrades, some features of existing outputs may be missed.
+       channel_type_features: ChannelTypeFeatures,
        // A cache of the parties' pubkeys required to construct the transaction, see doc for trust()
        keys: TxCreationKeys,
        // For access to the pre-built transaction, see doc for trust()
@@ -1253,7 +1326,7 @@ impl PartialEq for CommitmentTransaction {
                        self.to_countersignatory_value_sat == o.to_countersignatory_value_sat &&
                        self.feerate_per_kw == o.feerate_per_kw &&
                        self.htlcs == o.htlcs &&
-                       self.opt_anchors == o.opt_anchors &&
+                       self.channel_type_features == o.channel_type_features &&
                        self.keys == o.keys;
                if eq {
                        debug_assert_eq!(self.built.transaction, o.built.transaction);
@@ -1263,17 +1336,54 @@ impl PartialEq for CommitmentTransaction {
        }
 }
 
-impl_writeable_tlv_based!(CommitmentTransaction, {
-       (0, commitment_number, required),
-       (2, to_broadcaster_value_sat, required),
-       (4, to_countersignatory_value_sat, required),
-       (6, feerate_per_kw, required),
-       (8, keys, required),
-       (10, built, required),
-       (12, htlcs, vec_type),
-       (14, opt_anchors, option),
-       (16, opt_non_zero_fee_anchors, option),
-});
+impl Writeable for CommitmentTransaction {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               let legacy_deserialization_prevention_marker = legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features);
+               write_tlv_fields!(writer, {
+                       (0, self.commitment_number, required),
+                       (2, self.to_broadcaster_value_sat, required),
+                       (4, self.to_countersignatory_value_sat, required),
+                       (6, self.feerate_per_kw, required),
+                       (8, self.keys, required),
+                       (10, self.built, required),
+                       (12, self.htlcs, required_vec),
+                       (14, legacy_deserialization_prevention_marker, option),
+                       (15, self.channel_type_features, required),
+               });
+               Ok(())
+       }
+}
+
+impl Readable for CommitmentTransaction {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               _init_and_read_tlv_fields!(reader, {
+                       (0, commitment_number, required),
+                       (2, to_broadcaster_value_sat, required),
+                       (4, to_countersignatory_value_sat, required),
+                       (6, feerate_per_kw, required),
+                       (8, keys, required),
+                       (10, built, required),
+                       (12, htlcs, required_vec),
+                       (14, _legacy_deserialization_prevention_marker, option),
+                       (15, channel_type_features, option),
+               });
+
+               let mut additional_features = ChannelTypeFeatures::empty();
+               additional_features.set_anchors_nonzero_fee_htlc_tx_required();
+               chain::package::verify_channel_type_features(&channel_type_features, Some(&additional_features))?;
+
+               Ok(Self {
+                       commitment_number: commitment_number.0.unwrap(),
+                       to_broadcaster_value_sat: to_broadcaster_value_sat.0.unwrap(),
+                       to_countersignatory_value_sat: to_countersignatory_value_sat.0.unwrap(),
+                       feerate_per_kw: feerate_per_kw.0.unwrap(),
+                       keys: keys.0.unwrap(),
+                       built: built.0.unwrap(),
+                       htlcs,
+                       channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key())
+               })
+       }
+}
 
 impl CommitmentTransaction {
        /// Construct an object of the class while assigning transaction output indices to HTLCs.
@@ -1286,9 +1396,9 @@ impl CommitmentTransaction {
        /// Only include HTLCs that are above the dust limit for the channel.
        ///
        /// This is not exported to bindings users due to the generic though we likely should expose a version without
-       pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, opt_anchors: bool, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction {
+       pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction {
                // Sort outputs and populate output indices while keeping track of the auxiliary data
-               let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, opt_anchors, &broadcaster_funding_key, &countersignatory_funding_key).unwrap();
+               let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, &broadcaster_funding_key, &countersignatory_funding_key).unwrap();
 
                let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters);
                let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
@@ -1299,13 +1409,12 @@ impl CommitmentTransaction {
                        to_countersignatory_value_sat,
                        feerate_per_kw,
                        htlcs,
-                       opt_anchors: if opt_anchors { Some(()) } else { None },
+                       channel_type_features: channel_parameters.channel_type_features().clone(),
                        keys,
                        built: BuiltCommitmentTransaction {
                                transaction,
                                txid
                        },
-                       opt_non_zero_fee_anchors: None,
                }
        }
 
@@ -1313,7 +1422,7 @@ impl CommitmentTransaction {
        ///
        /// This is not exported to bindings users due to move, and also not likely to be useful for binding users
        pub fn with_non_zero_fee_anchors(mut self) -> Self {
-               self.opt_non_zero_fee_anchors = Some(());
+               self.channel_type_features.set_anchors_nonzero_fee_htlc_tx_required();
                self
        }
 
@@ -1321,7 +1430,7 @@ impl CommitmentTransaction {
                let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters);
 
                let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect();
-               let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, self.opt_anchors.is_some(), broadcaster_funding_key, countersignatory_funding_key)?;
+               let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, broadcaster_funding_key, countersignatory_funding_key)?;
 
                let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
                let txid = transaction.txid();
@@ -1345,14 +1454,14 @@ impl CommitmentTransaction {
        // - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the
        //   caller needs to have sorted together with the HTLCs so it can keep track of the output index
        // - building of a bitcoin transaction during a verify() call, in which case T is just ()
-       fn internal_build_outputs<T>(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, opt_anchors: bool, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec<TxOut>, Vec<HTLCOutputInCommitment>), ()> {
+       fn internal_build_outputs<T>(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec<TxOut>, Vec<HTLCOutputInCommitment>), ()> {
                let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys();
                let contest_delay = channel_parameters.contest_delay();
 
                let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>)> = Vec::new();
 
                if to_countersignatory_value_sat > 0 {
-                       let script = if opt_anchors {
+                       let script = if channel_parameters.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
                            get_to_countersignatory_with_anchors_redeemscript(&countersignatory_pubkeys.payment_point).to_v0_p2wsh()
                        } else {
                            Payload::p2wpkh(&BitcoinPublicKey::new(countersignatory_pubkeys.payment_point)).unwrap().script_pubkey()
@@ -1381,7 +1490,7 @@ impl CommitmentTransaction {
                        ));
                }
 
-               if opt_anchors {
+               if channel_parameters.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
                        if to_broadcaster_value_sat > 0 || !htlcs_with_aux.is_empty() {
                                let anchor_script = get_anchor_redeemscript(broadcaster_funding_key);
                                txouts.push((
@@ -1407,7 +1516,7 @@ impl CommitmentTransaction {
 
                let mut htlcs = Vec::with_capacity(htlcs_with_aux.len());
                for (htlc, _) in htlcs_with_aux {
-                       let script = chan_utils::get_htlc_redeemscript(&htlc, opt_anchors, &keys);
+                       let script = chan_utils::get_htlc_redeemscript(&htlc, &channel_parameters.channel_type_features(), &keys);
                        let txout = TxOut {
                                script_pubkey: script.to_v0_p2wsh(),
                                value: htlc.amount_msat / 1000,
@@ -1562,8 +1671,8 @@ impl<'a> TrustedCommitmentTransaction<'a> {
        }
 
        /// Should anchors be used.
-       pub fn opt_anchors(&self) -> bool {
-               self.opt_anchors.is_some()
+       pub fn channel_type_features(&self) -> &ChannelTypeFeatures {
+               &self.inner.channel_type_features
        }
 
        /// Get a signature for each HTLC which was included in the commitment transaction (ie for
@@ -1584,9 +1693,9 @@ impl<'a> TrustedCommitmentTransaction<'a> {
 
                for this_htlc in inner.htlcs.iter() {
                        assert!(this_htlc.transaction_output_index.is_some());
-                       let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+                       let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, &self.channel_type_features, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
-                       let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
+                       let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &self.channel_type_features, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
 
                        let sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, EcdsaSighashType::All).unwrap()[..]);
                        ret.push(sign_with_aux_rand(secp_ctx, &sighash, &holder_htlc_key, entropy_source));
@@ -1606,12 +1715,12 @@ impl<'a> TrustedCommitmentTransaction<'a> {
                // Further, we should never be provided the preimage for an HTLC-Timeout transaction.
                if  this_htlc.offered && preimage.is_some() { unreachable!(); }
 
-               let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+               let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, &self.channel_type_features, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
-               let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
+               let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &self.channel_type_features, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
 
                htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness(
-                       signature, counterparty_signature, preimage, &htlc_redeemscript, self.opt_anchors(),
+                       signature, counterparty_signature, preimage, &htlc_redeemscript, &self.channel_type_features,
                );
                htlc_tx
        }
@@ -1662,6 +1771,7 @@ mod tests {
        use bitcoin::hashes::hex::ToHex;
        use bitcoin::util::address::Payload;
        use bitcoin::PublicKey as BitcoinPublicKey;
+       use crate::ln::features::ChannelTypeFeatures;
 
        #[test]
        fn test_anchors() {
@@ -1685,8 +1795,7 @@ mod tests {
                        is_outbound_from_holder: false,
                        counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }),
                        funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }),
-                       opt_anchors: None,
-                       opt_non_zero_fee_anchors: None,
+                       channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
                };
 
                let mut htlcs_with_aux: Vec<(_, ())> = Vec::new();
@@ -1694,7 +1803,6 @@ mod tests {
                // Generate broadcaster and counterparty outputs
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        0, 1000, 2000,
-                       false,
                        holder_pubkeys.funding_pubkey,
                        counterparty_pubkeys.funding_pubkey,
                        keys.clone(), 1,
@@ -1704,9 +1812,9 @@ mod tests {
                assert_eq!(tx.built.transaction.output[1].script_pubkey, Payload::p2wpkh(&BitcoinPublicKey::new(counterparty_pubkeys.payment_point)).unwrap().script_pubkey());
 
                // Generate broadcaster and counterparty outputs as well as two anchors
+               channel_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        0, 1000, 2000,
-                       true,
                        holder_pubkeys.funding_pubkey,
                        counterparty_pubkeys.funding_pubkey,
                        keys.clone(), 1,
@@ -1718,7 +1826,6 @@ mod tests {
                // Generate broadcaster output and anchor
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        0, 3000, 0,
-                       true,
                        holder_pubkeys.funding_pubkey,
                        counterparty_pubkeys.funding_pubkey,
                        keys.clone(), 1,
@@ -1729,7 +1836,6 @@ mod tests {
                // Generate counterparty output and anchor
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        0, 0, 3000,
-                       true,
                        holder_pubkeys.funding_pubkey,
                        counterparty_pubkeys.funding_pubkey,
                        keys.clone(), 1,
@@ -1754,9 +1860,9 @@ mod tests {
                };
 
                // Generate broadcaster output and received and offered HTLC outputs,  w/o anchors
+               channel_parameters.channel_type_features = ChannelTypeFeatures::only_static_remote_key();
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        0, 3000, 0,
-                       false,
                        holder_pubkeys.funding_pubkey,
                        counterparty_pubkeys.funding_pubkey,
                        keys.clone(), 1,
@@ -1764,18 +1870,17 @@ mod tests {
                        &channel_parameters.as_holder_broadcastable()
                );
                assert_eq!(tx.built.transaction.output.len(), 3);
-               assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh());
-               assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh());
-               assert_eq!(get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+               assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh());
+               assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh());
+               assert_eq!(get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh().to_hex(),
                                   "0020e43a7c068553003fe68fcae424fb7b28ec5ce48cd8b6744b3945631389bad2fb");
-               assert_eq!(get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+               assert_eq!(get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::only_static_remote_key(), &keys).to_v0_p2wsh().to_hex(),
                                   "0020215d61bba56b19e9eadb6107f5a85d7f99c40f65992443f69229c290165bc00d");
 
                // Generate broadcaster output and received and offered HTLC outputs,  with anchors
-               channel_parameters.opt_anchors = Some(());
+               channel_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        0, 3000, 0,
-                       true,
                        holder_pubkeys.funding_pubkey,
                        counterparty_pubkeys.funding_pubkey,
                        keys.clone(), 1,
@@ -1783,11 +1888,11 @@ mod tests {
                        &channel_parameters.as_holder_broadcastable()
                );
                assert_eq!(tx.built.transaction.output.len(), 5);
-               assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh());
-               assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh());
-               assert_eq!(get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+               assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh());
+               assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh());
+               assert_eq!(get_htlc_redeemscript(&received_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh().to_hex(),
                                   "0020b70d0649c72b38756885c7a30908d912a7898dd5d79457a7280b8e9a20f3f2bc");
-               assert_eq!(get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+               assert_eq!(get_htlc_redeemscript(&offered_htlc, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), &keys).to_v0_p2wsh().to_hex(),
                                   "002087a3faeb1950a469c0e2db4a79b093a41b9526e5a6fc6ef5cb949bde3be379c7");
        }
 
index 707c27908eddabd5efdbabeda8278af225b02950..8d4c40b64d06b303c7aab3b183adbc98dcf8829d 100644 (file)
@@ -2346,6 +2346,7 @@ fn do_channel_holding_cell_serialize(disconnect: bool, reload_a: bool) {
                RecipientOnionFields::secret_only(payment_secret_2), PaymentId(payment_hash_2.0)).unwrap();
        check_added_monitors!(nodes[0], 0);
 
+       let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode();
        chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
        chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
        nodes[0].node.claim_funds(payment_preimage_0);
@@ -2365,8 +2366,9 @@ fn do_channel_holding_cell_serialize(disconnect: bool, reload_a: bool) {
                // disconnect the peers. Note that the fuzzer originally found this issue because
                // deserializing a ChannelManager in this state causes an assertion failure.
                if reload_a {
-                       let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode();
                        reload_node!(nodes[0], &nodes[0].node.encode(), &[&chan_0_monitor_serialized], persister, new_chain_monitor, nodes_0_deserialized);
+                       persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+                       persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
                } else {
                        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
                }
@@ -2406,9 +2408,14 @@ fn do_channel_holding_cell_serialize(disconnect: bool, reload_a: bool) {
                        assert_eq!(pending_cs.commitment_signed, cs);
                } else { panic!(); }
 
-               // There should be no monitor updates as we are still pending awaiting a failed one.
-               check_added_monitors!(nodes[0], 0);
-               check_added_monitors!(nodes[1], 0);
+               if reload_a {
+                       // The two pending monitor updates were replayed (but are still pending).
+                       check_added_monitors(&nodes[0], 2);
+               } else {
+                       // There should be no monitor updates as we are still pending awaiting a failed one.
+                       check_added_monitors(&nodes[0], 0);
+               }
+               check_added_monitors(&nodes[1], 0);
        }
 
        // If we finish updating the monitor, we should free the holding cell right away (this did
index 6df539b537cff8035f50a4625317c785f8cb31f3..e559ac3355007808a18abe58acb562cf8e2c112f 100644 (file)
@@ -27,7 +27,7 @@ use crate::ln::features::{ChannelTypeFeatures, InitFeatures};
 use crate::ln::msgs;
 use crate::ln::msgs::DecodeError;
 use crate::ln::script::{self, ShutdownScript};
-use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
+use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT, ChannelShutdownState};
 use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
 use crate::ln::chan_utils;
 use crate::ln::onion_utils::HTLCFailReason;
@@ -41,7 +41,7 @@ use crate::routing::gossip::NodeId;
 use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
 use crate::util::logger::Logger;
 use crate::util::errors::APIError;
-use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits};
+use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure};
 use crate::util::scid_utils::scid_from_parts;
 
 use crate::io;
@@ -224,6 +224,7 @@ struct OutboundHTLCOutput {
        payment_hash: PaymentHash,
        state: OutboundHTLCState,
        source: HTLCSource,
+       skimmed_fee_msat: Option<u64>,
 }
 
 /// See AwaitingRemoteRevoke ChannelState for more info
@@ -235,6 +236,8 @@ enum HTLCUpdateAwaitingACK {
                payment_hash: PaymentHash,
                source: HTLCSource,
                onion_routing_packet: msgs::OnionPacket,
+               // The extra fee we're skimming off the top of this HTLC.
+               skimmed_fee_msat: Option<u64>,
        },
        ClaimHTLC {
                payment_preimage: PaymentPreimage,
@@ -306,10 +309,10 @@ pub const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
 
 pub const DEFAULT_MAX_HTLCS: u16 = 50;
 
-pub(crate) fn commitment_tx_base_weight(opt_anchors: bool) -> u64 {
+pub(crate) fn commitment_tx_base_weight(channel_type_features: &ChannelTypeFeatures) -> u64 {
        const COMMITMENT_TX_BASE_WEIGHT: u64 = 724;
        const COMMITMENT_TX_BASE_ANCHOR_WEIGHT: u64 = 1124;
-       if opt_anchors { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT }
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT }
 }
 
 #[cfg(not(test))]
@@ -485,13 +488,13 @@ enum UpdateFulfillFetch {
 }
 
 /// The return type of get_update_fulfill_htlc_and_commit.
-pub enum UpdateFulfillCommitFetch<'a> {
+pub enum UpdateFulfillCommitFetch {
        /// Indicates the HTLC fulfill is new, and either generated an update_fulfill message, placed
        /// it in the holding cell, or re-generated the update_fulfill message after the same claim was
        /// previously placed in the holding cell (and has since been removed).
        NewClaim {
                /// The ChannelMonitorUpdate which places the new payment preimage in the channel monitor
-               monitor_update: &'a ChannelMonitorUpdate,
+               monitor_update: ChannelMonitorUpdate,
                /// The value of the HTLC which was claimed, in msat.
                htlc_value_msat: u64,
        },
@@ -524,6 +527,10 @@ pub(super) struct ReestablishResponses {
 }
 
 /// The return type of `force_shutdown`
+///
+/// Contains a (counterparty_node_id, funding_txo, [`ChannelMonitorUpdate`]) tuple
+/// followed by a list of HTLCs to fail back in the form of the (source, payment hash, and this
+/// channel's counterparty_node_id and channel_id).
 pub(crate) type ShutdownResult = (
        Option<(PublicKey, OutPoint, ChannelMonitorUpdate)>,
        Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>
@@ -583,21 +590,41 @@ pub(crate) const EXPIRE_PREV_CONFIG_TICKS: usize = 5;
 /// See [`ChannelContext::sent_message_awaiting_response`] for more information.
 pub(crate) const DISCONNECT_PEER_AWAITING_RESPONSE_TICKS: usize = 2;
 
+/// The number of ticks that may elapse while we're waiting for an unfunded outbound/inbound channel
+/// to be promoted to a [`Channel`] since the unfunded channel was created. An unfunded channel
+/// exceeding this age limit will be force-closed and purged from memory.
+pub(crate) const UNFUNDED_CHANNEL_AGE_LIMIT_TICKS: usize = 60;
+
 struct PendingChannelMonitorUpdate {
        update: ChannelMonitorUpdate,
-       /// In some cases we need to delay letting the [`ChannelMonitorUpdate`] go until after an
-       /// `Event` is processed by the user. This bool indicates the [`ChannelMonitorUpdate`] is
-       /// blocked on some external event and the [`ChannelManager`] will update us when we're ready.
-       ///
-       /// [`ChannelManager`]: super::channelmanager::ChannelManager
-       blocked: bool,
 }
 
 impl_writeable_tlv_based!(PendingChannelMonitorUpdate, {
        (0, update, required),
-       (2, blocked, required),
 });
 
+/// Contains all state common to unfunded inbound/outbound channels.
+pub(super) struct UnfundedChannelContext {
+       /// A counter tracking how many ticks have elapsed since this unfunded channel was
+       /// created. If this unfunded channel reaches peer has yet to respond after reaching
+       /// `UNFUNDED_CHANNEL_AGE_LIMIT_TICKS`, it will be force-closed and purged from memory.
+       ///
+       /// This is so that we don't keep channels around that haven't progressed to a funded state
+       /// in a timely manner.
+       unfunded_channel_age_ticks: usize,
+}
+
+impl UnfundedChannelContext {
+       /// Determines whether we should force-close and purge this unfunded channel from memory due to it
+       /// having reached the unfunded channel age limit.
+       ///
+       /// This should be called on every [`super::channelmanager::ChannelManager::timer_tick_occurred`].
+       pub fn should_expire_unfunded_channel(&mut self) -> bool {
+               self.unfunded_channel_age_ticks += 1;
+               self.unfunded_channel_age_ticks >= UNFUNDED_CHANNEL_AGE_LIMIT_TICKS
+       }
+}
+
 /// Contains everything about the channel including state, and various flags.
 pub(super) struct ChannelContext<Signer: ChannelSigner> {
        config: LegacyChannelConfig,
@@ -866,18 +893,12 @@ pub(super) struct ChannelContext<Signer: ChannelSigner> {
        /// [`SignerProvider::derive_channel_signer`].
        channel_keys_id: [u8; 32],
 
-       /// When we generate [`ChannelMonitorUpdate`]s to persist, they may not be persisted immediately.
-       /// If we then persist the [`channelmanager::ChannelManager`] and crash before the persistence
-       /// completes we still need to be able to complete the persistence. Thus, we have to keep a
-       /// copy of the [`ChannelMonitorUpdate`] here until it is complete.
-       pending_monitor_updates: Vec<PendingChannelMonitorUpdate>,
+       /// If we can't release a [`ChannelMonitorUpdate`] until some external action completes, we
+       /// store it here and only release it to the `ChannelManager` once it asks for it.
+       blocked_monitor_updates: Vec<PendingChannelMonitorUpdate>,
 }
 
 impl<Signer: ChannelSigner> ChannelContext<Signer> {
-       pub(crate) fn opt_anchors(&self) -> bool {
-               self.channel_transaction_parameters.opt_anchors.is_some()
-       }
-
        /// Allowed in any state (including after shutdown)
        pub fn get_update_time_counter(&self) -> u32 {
                self.update_time_counter
@@ -913,6 +934,34 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                (self.channel_state & mask) == (ChannelState::ChannelReady as u32) && !self.monitor_pending_channel_ready
        }
 
+       /// shutdown state returns the state of the channel in its various stages of shutdown
+       pub fn shutdown_state(&self) -> ChannelShutdownState {
+               if self.channel_state & (ChannelState::ShutdownComplete as u32) != 0 {
+                       return ChannelShutdownState::ShutdownComplete;
+               }
+               if self.channel_state & (ChannelState::LocalShutdownSent as u32) != 0 &&  self.channel_state & (ChannelState::RemoteShutdownSent as u32) == 0 {
+                       return ChannelShutdownState::ShutdownInitiated;
+               }
+               if (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0) && !self.closing_negotiation_ready() {
+                       return ChannelShutdownState::ResolvingHTLCs;
+               }
+               if (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0) && self.closing_negotiation_ready() {
+                       return ChannelShutdownState::NegotiatingClosingFee;
+               }
+               return ChannelShutdownState::NotShuttingDown;
+       }
+
+       fn closing_negotiation_ready(&self) -> bool {
+               self.pending_inbound_htlcs.is_empty() &&
+               self.pending_outbound_htlcs.is_empty() &&
+               self.pending_update_fee.is_none() &&
+               self.channel_state &
+               (BOTH_SIDES_SHUTDOWN_MASK |
+                       ChannelState::AwaitingRemoteRevoke as u32 |
+                       ChannelState::PeerDisconnected as u32 |
+                       ChannelState::MonitorUpdateInProgress as u32) == BOTH_SIDES_SHUTDOWN_MASK
+       }
+
        /// Returns true if this channel is currently available for use. This is a superset of
        /// is_usable() and considers things like the channel being temporarily disabled.
        /// Allowed in any state (including after shutdown)
@@ -973,7 +1022,7 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
        }
 
        /// Returns the funding_txo we either got from our peer, or were given by
-       /// get_outbound_funding_created.
+       /// get_funding_created.
        pub fn get_funding_txo(&self) -> Option<OutPoint> {
                self.channel_transaction_parameters.funding_outpoint
        }
@@ -1069,8 +1118,18 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                cmp::max(self.config.options.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
        }
 
-       pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
-               self.config.options.max_dust_htlc_exposure_msat
+       pub fn get_max_dust_htlc_exposure_msat<F: Deref>(&self,
+               fee_estimator: &LowerBoundedFeeEstimator<F>) -> u64
+       where F::Target: FeeEstimator
+       {
+               match self.config.options.max_dust_htlc_exposure {
+                       MaxDustHTLCExposure::FeeRateMultiplier(multiplier) => {
+                               let feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(
+                                       ConfirmationTarget::HighPriority);
+                               feerate_per_kw as u64 * multiplier
+                       },
+                       MaxDustHTLCExposure::FixedLimitMsat(limit) => limit,
+               }
        }
 
        /// Returns the previous [`ChannelConfig`] applied to this channel, if any.
@@ -1204,10 +1263,10 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                        ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => {
                                if $outbound == local { // "offered HTLC output"
                                        let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
-                                       let htlc_tx_fee = if self.opt_anchors() {
+                                       let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                                                0
                                        } else {
-                                               feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000
+                                               feerate_per_kw as u64 * htlc_timeout_tx_weight(self.get_channel_type()) / 1000
                                        };
                                        if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
                                                log_trace!(logger, "   ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
@@ -1218,10 +1277,10 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                                        }
                                } else {
                                        let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
-                                       let htlc_tx_fee = if self.opt_anchors() {
+                                       let htlc_tx_fee = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                                                0
                                        } else {
-                                               feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000
+                                               feerate_per_kw as u64 * htlc_success_tx_weight(self.get_channel_type()) / 1000
                                        };
                                        if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
                                                log_trace!(logger, "   ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
@@ -1326,8 +1385,8 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                        broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64);
                }
 
-               let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), self.channel_transaction_parameters.opt_anchors.is_some());
-               let anchors_val = if self.channel_transaction_parameters.opt_anchors.is_some() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64;
+               let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &self.channel_transaction_parameters.channel_type_features);
+               let anchors_val = if self.channel_transaction_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64;
                let (value_to_self, value_to_remote) = if self.is_outbound() {
                        (value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000)
                } else {
@@ -1362,7 +1421,6 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
                                                                             value_to_a as u64,
                                                                             value_to_b as u64,
-                                                                            self.channel_transaction_parameters.opt_anchors.is_some(),
                                                                             funding_pubkey_a,
                                                                             funding_pubkey_b,
                                                                             keys.clone(),
@@ -1409,7 +1467,7 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
        #[inline]
        /// Creates a set of keys for build_commitment_transaction to generate a transaction which we
        /// will sign and send to our counterparty.
-       /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
+       /// If an Err is returned, it is a ChannelError::Close (for get_funding_created)
        fn build_remote_transaction_keys(&self) -> TxCreationKeys {
                //TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we
                //may see payments to it!
@@ -1470,12 +1528,12 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                        on_holder_tx_holding_cell_htlcs_count: 0,
                };
 
-               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if context.opt_anchors() {
+               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                        (0, 0)
                } else {
                        let dust_buffer_feerate = context.get_dust_buffer_feerate(outbound_feerate_update) as u64;
-                       (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000,
-                               dust_buffer_feerate * htlc_success_tx_weight(false) / 1000)
+                       (dust_buffer_feerate * htlc_timeout_tx_weight(context.get_channel_type()) / 1000,
+                               dust_buffer_feerate * htlc_success_tx_weight(context.get_channel_type()) / 1000)
                };
                let counterparty_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.counterparty_dust_limit_satoshis;
                let holder_dust_limit_success_sat = htlc_success_dust_limit + context.holder_dust_limit_satoshis;
@@ -1503,12 +1561,12 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                        on_holder_tx_holding_cell_htlcs_count: 0,
                };
 
-               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if context.opt_anchors() {
+               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                        (0, 0)
                } else {
                        let dust_buffer_feerate = context.get_dust_buffer_feerate(outbound_feerate_update) as u64;
-                       (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000,
-                               dust_buffer_feerate * htlc_success_tx_weight(false) / 1000)
+                       (dust_buffer_feerate * htlc_timeout_tx_weight(context.get_channel_type()) / 1000,
+                               dust_buffer_feerate * htlc_success_tx_weight(context.get_channel_type()) / 1000)
                };
                let counterparty_dust_limit_success_sat = htlc_success_dust_limit + context.counterparty_dust_limit_satoshis;
                let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.holder_dust_limit_satoshis;
@@ -1544,7 +1602,10 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
        /// Doesn't bother handling the
        /// if-we-removed-it-already-but-haven't-fully-resolved-they-can-still-send-an-inbound-HTLC
        /// corner case properly.
-       pub fn get_available_balances(&self) -> AvailableBalances {
+       pub fn get_available_balances<F: Deref>(&self, fee_estimator: &LowerBoundedFeeEstimator<F>)
+       -> AvailableBalances
+       where F::Target: FeeEstimator
+       {
                let context = &self;
                // Note that we have to handle overflow due to the above case.
                let inbound_stats = context.get_inbound_pending_htlc_stats(None);
@@ -1574,8 +1635,8 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                        // dependency.
                        // This complicates the computation around dust-values, up to the one-htlc-value.
                        let mut real_dust_limit_timeout_sat = context.holder_dust_limit_satoshis;
-                       if !context.opt_anchors() {
-                               real_dust_limit_timeout_sat += context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000;
+                       if !context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                               real_dust_limit_timeout_sat += context.feerate_per_kw as u64 * htlc_timeout_tx_weight(context.get_channel_type()) / 1000;
                        }
 
                        let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
@@ -1600,8 +1661,8 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                        // If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
                        // sending a new HTLC won't reduce their balance below our reserve threshold.
                        let mut real_dust_limit_success_sat = context.counterparty_dust_limit_satoshis;
-                       if !context.opt_anchors() {
-                               real_dust_limit_success_sat += context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000;
+                       if !context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                               real_dust_limit_success_sat += context.feerate_per_kw as u64 * htlc_success_tx_weight(context.get_channel_type()) / 1000;
                        }
 
                        let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
@@ -1626,26 +1687,27 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                // send above the dust limit (as the router can always overpay to meet the dust limit).
                let mut remaining_msat_below_dust_exposure_limit = None;
                let mut dust_exposure_dust_limit_msat = 0;
+               let max_dust_htlc_exposure_msat = context.get_max_dust_htlc_exposure_msat(fee_estimator);
 
-               let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() {
+               let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                        (context.counterparty_dust_limit_satoshis, context.holder_dust_limit_satoshis)
                } else {
                        let dust_buffer_feerate = context.get_dust_buffer_feerate(None) as u64;
-                       (context.counterparty_dust_limit_satoshis + dust_buffer_feerate * htlc_success_tx_weight(false) / 1000,
-                        context.holder_dust_limit_satoshis       + dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000)
+                       (context.counterparty_dust_limit_satoshis + dust_buffer_feerate * htlc_success_tx_weight(context.get_channel_type()) / 1000,
+                        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 > context.get_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 as i64 {
                        remaining_msat_below_dust_exposure_limit =
-                               Some(context.get_max_dust_htlc_exposure_msat().saturating_sub(on_counterparty_dust_htlc_exposure_msat));
+                               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 > context.get_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 as i64 {
                        remaining_msat_below_dust_exposure_limit = Some(cmp::min(
                                remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()),
-                               context.get_max_dust_htlc_exposure_msat().saturating_sub(on_holder_dust_htlc_exposure_msat)));
+                               max_dust_htlc_exposure_msat.saturating_sub(on_holder_dust_htlc_exposure_msat)));
                        dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_timeout_dust_limit * 1000);
                }
 
@@ -1696,11 +1758,11 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                let context = &self;
                assert!(context.is_outbound());
 
-               let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() {
+               let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                        (0, 0)
                } else {
-                       (context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000,
-                               context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000)
+                       (context.feerate_per_kw as u64 * htlc_success_tx_weight(context.get_channel_type()) / 1000,
+                               context.feerate_per_kw as u64 * htlc_timeout_tx_weight(context.get_channel_type()) / 1000)
                };
                let real_dust_limit_success_sat = htlc_success_dust_limit + context.holder_dust_limit_satoshis;
                let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.holder_dust_limit_satoshis;
@@ -1759,12 +1821,12 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                }
 
                let num_htlcs = included_htlcs + addl_htlcs;
-               let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, context.opt_anchors());
+               let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, &context.channel_type);
                #[cfg(any(test, fuzzing))]
                {
                        let mut fee = res;
                        if fee_spike_buffer_htlc.is_some() {
-                               fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, context.opt_anchors());
+                               fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, &context.channel_type);
                        }
                        let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len()
                                + context.holding_cell_htlc_updates.len();
@@ -1800,11 +1862,11 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                let context = &self;
                assert!(!context.is_outbound());
 
-               let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() {
+               let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                        (0, 0)
                } else {
-                       (context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000,
-                               context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000)
+                       (context.feerate_per_kw as u64 * htlc_success_tx_weight(context.get_channel_type()) / 1000,
+                               context.feerate_per_kw as u64 * htlc_timeout_tx_weight(context.get_channel_type()) / 1000)
                };
                let real_dust_limit_success_sat = htlc_success_dust_limit + context.counterparty_dust_limit_satoshis;
                let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.counterparty_dust_limit_satoshis;
@@ -1850,12 +1912,12 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
                }
 
                let num_htlcs = included_htlcs + addl_htlcs;
-               let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, context.opt_anchors());
+               let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, &context.channel_type);
                #[cfg(any(test, fuzzing))]
                {
                        let mut fee = res;
                        if fee_spike_buffer_htlc.is_some() {
-                               fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, context.opt_anchors());
+                               fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, &context.channel_type);
                        }
                        let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len();
                        let commitment_tx_info = CommitmentTxInfoCached {
@@ -1977,21 +2039,21 @@ pub(crate) fn get_legacy_default_holder_selected_channel_reserve_satoshis(channe
 // Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs.
 // Note that num_htlcs should not include dust HTLCs.
 #[inline]
-fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 {
-       feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
+fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, channel_type_features: &ChannelTypeFeatures) -> u64 {
+       feerate_per_kw as u64 * (commitment_tx_base_weight(channel_type_features) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
 }
 
 // Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs.
 // Note that num_htlcs should not include dust HTLCs.
-fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 {
+fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, channel_type_features: &ChannelTypeFeatures) -> u64 {
        // Note that we need to divide before multiplying to round properly,
        // since the lowest denomination of bitcoin on-chain is the satoshi.
-       (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000
+       (commitment_tx_base_weight(channel_type_features) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000
 }
 
 // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
 // has been completed, and then turn into a Channel to get compiler-time enforcement of things like
-// calling channel_id() before we're set up or things like get_outbound_funding_signed on an
+// calling channel_id() before we're set up or things like get_funding_signed on an
 // inbound channel.
 //
 // Holder designates channel data owned for the benefit of the user client.
@@ -2010,20 +2072,35 @@ struct CommitmentTxInfoCached {
 }
 
 impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
-       fn check_remote_fee<F: Deref, L: Deref>(fee_estimator: &LowerBoundedFeeEstimator<F>,
-               feerate_per_kw: u32, cur_feerate_per_kw: Option<u32>, logger: &L)
-               -> Result<(), ChannelError> where F::Target: FeeEstimator, L::Target: Logger,
+       fn check_remote_fee<F: Deref, L: Deref>(
+               channel_type: &ChannelTypeFeatures, fee_estimator: &LowerBoundedFeeEstimator<F>,
+               feerate_per_kw: u32, cur_feerate_per_kw: Option<u32>, logger: &L
+       ) -> Result<(), ChannelError> where F::Target: FeeEstimator, L::Target: Logger,
        {
                // We only bound the fee updates on the upper side to prevent completely absurd feerates,
                // always accepting up to 25 sat/vByte or 10x our fee estimator's "High Priority" fee.
                // We generally don't care too much if they set the feerate to something very high, but it
-               // could result in the channel being useless due to everything being dust.
-               let upper_limit = cmp::max(250 * 25,
-                       fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 * 10);
-               if feerate_per_kw as u64 > upper_limit {
-                       return Err(ChannelError::Close(format!("Peer's feerate much too high. Actual: {}. Our expected upper limit: {}", feerate_per_kw, upper_limit)));
-               }
-               let lower_limit = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background);
+               // could result in the channel being useless due to everything being dust. This doesn't
+               // apply to channels supporting anchor outputs since HTLC transactions are pre-signed with a
+               // zero fee, so their fee is no longer considered to determine dust limits.
+               if !channel_type.supports_anchors_zero_fee_htlc_tx() {
+                       let upper_limit = cmp::max(250 * 25,
+                               fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 * 10);
+                       if feerate_per_kw as u64 > upper_limit {
+                               return Err(ChannelError::Close(format!("Peer's feerate much too high. Actual: {}. Our expected upper limit: {}", feerate_per_kw, upper_limit)));
+                       }
+               }
+
+               // We can afford to use a lower bound with anchors than previously since we can now bump
+               // fees when broadcasting our commitment. However, we must still make sure we meet the
+               // minimum mempool feerate, until package relay is deployed, such that we can ensure the
+               // commitment transaction propagates throughout node mempools on its own.
+               let lower_limit_conf_target = if channel_type.supports_anchors_zero_fee_htlc_tx() {
+                       ConfirmationTarget::MempoolMinimum
+               } else {
+                       ConfirmationTarget::Background
+               };
+               let lower_limit = fee_estimator.bounded_sat_per_1000_weight(lower_limit_conf_target);
                // Some fee estimators round up to the next full sat/vbyte (ie 250 sats per kw), causing
                // occasional issues with feerate disagreements between an initiator that wants a feerate
                // of 1.1 sat/vbyte and a receiver that wants 1.1 rounded up to 2. Thus, we always add 250
@@ -2261,7 +2338,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        }
 
        pub fn get_update_fulfill_htlc_and_commit<L: Deref>(&mut self, htlc_id: u64, payment_preimage: PaymentPreimage, logger: &L) -> UpdateFulfillCommitFetch where L::Target: Logger {
-               let release_cs_monitor = self.context.pending_monitor_updates.iter().all(|upd| !upd.blocked);
+               let release_cs_monitor = self.context.blocked_monitor_updates.is_empty();
                match self.get_update_fulfill_htlc(htlc_id, payment_preimage, logger) {
                        UpdateFulfillFetch::NewClaim { mut monitor_update, htlc_value_msat, msg } => {
                                // Even if we aren't supposed to let new monitor updates with commitment state
@@ -2269,43 +2346,30 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                // matter what. Sadly, to push a new monitor update which flies before others
                                // already queued, we have to insert it into the pending queue and update the
                                // update_ids of all the following monitors.
-                               let unblocked_update_pos = if release_cs_monitor && msg.is_some() {
+                               if release_cs_monitor && msg.is_some() {
                                        let mut additional_update = self.build_commitment_no_status_check(logger);
                                        // build_commitment_no_status_check may bump latest_monitor_id but we want them
                                        // to be strictly increasing by one, so decrement it here.
                                        self.context.latest_monitor_update_id = monitor_update.update_id;
                                        monitor_update.updates.append(&mut additional_update.updates);
-                                       self.context.pending_monitor_updates.push(PendingChannelMonitorUpdate {
-                                               update: monitor_update, blocked: false,
-                                       });
-                                       self.context.pending_monitor_updates.len() - 1
                                } else {
-                                       let insert_pos = self.context.pending_monitor_updates.iter().position(|upd| upd.blocked)
-                                               .unwrap_or(self.context.pending_monitor_updates.len());
-                                       let new_mon_id = self.context.pending_monitor_updates.get(insert_pos)
+                                       let new_mon_id = self.context.blocked_monitor_updates.get(0)
                                                .map(|upd| upd.update.update_id).unwrap_or(monitor_update.update_id);
                                        monitor_update.update_id = new_mon_id;
-                                       self.context.pending_monitor_updates.insert(insert_pos, PendingChannelMonitorUpdate {
-                                               update: monitor_update, blocked: false,
-                                       });
-                                       for held_update in self.context.pending_monitor_updates.iter_mut().skip(insert_pos + 1) {
+                                       for held_update in self.context.blocked_monitor_updates.iter_mut() {
                                                held_update.update.update_id += 1;
                                        }
                                        if msg.is_some() {
                                                debug_assert!(false, "If there is a pending blocked monitor we should have MonitorUpdateInProgress set");
                                                let update = self.build_commitment_no_status_check(logger);
-                                               self.context.pending_monitor_updates.push(PendingChannelMonitorUpdate {
-                                                       update, blocked: true,
+                                               self.context.blocked_monitor_updates.push(PendingChannelMonitorUpdate {
+                                                       update,
                                                });
                                        }
-                                       insert_pos
-                               };
-                               self.monitor_updating_paused(false, msg.is_some(), false, Vec::new(), Vec::new(), Vec::new());
-                               UpdateFulfillCommitFetch::NewClaim {
-                                       monitor_update: &self.context.pending_monitor_updates.get(unblocked_update_pos)
-                                               .expect("We just pushed the monitor update").update,
-                                       htlc_value_msat,
                                }
+
+                               self.monitor_updating_paused(false, msg.is_some(), false, Vec::new(), Vec::new(), Vec::new());
+                               UpdateFulfillCommitFetch::NewClaim { monitor_update, htlc_value_msat, }
                        },
                        UpdateFulfillFetch::DuplicateClaim {} => UpdateFulfillCommitFetch::DuplicateClaim {},
                }
@@ -2576,8 +2640,13 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                Ok(self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, best_block.height(), logger))
        }
 
-       pub fn update_add_htlc<F, L: Deref>(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F, logger: &L) -> Result<(), ChannelError>
-       where F: for<'a> Fn(&'a Self, PendingHTLCStatus, u16) -> PendingHTLCStatus, L::Target: Logger {
+       pub fn update_add_htlc<F, FE: Deref, L: Deref>(
+               &mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus,
+               create_pending_htlc_status: F, fee_estimator: &LowerBoundedFeeEstimator<FE>, logger: &L
+       ) -> Result<(), ChannelError>
+       where F: for<'a> Fn(&'a Self, PendingHTLCStatus, u16) -> PendingHTLCStatus,
+               FE::Target: FeeEstimator, L::Target: Logger,
+       {
                // We can't accept HTLCs sent after we've sent a shutdown.
                let local_sent_shutdown = (self.context.channel_state & (ChannelState::ChannelReady as u32 | ChannelState::LocalShutdownSent as u32)) != (ChannelState::ChannelReady as u32);
                if local_sent_shutdown {
@@ -2630,19 +2699,20 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        }
                }
 
-               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.context.opt_anchors() {
+               let max_dust_htlc_exposure_msat = self.context.get_max_dust_htlc_exposure_msat(fee_estimator);
+               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
                        (0, 0)
                } else {
                        let dust_buffer_feerate = self.context.get_dust_buffer_feerate(None) as u64;
-                       (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000,
-                               dust_buffer_feerate * htlc_success_tx_weight(false) / 1000)
+                       (dust_buffer_feerate * htlc_timeout_tx_weight(self.context.get_channel_type()) / 1000,
+                               dust_buffer_feerate * htlc_success_tx_weight(self.context.get_channel_type()) / 1000)
                };
                let exposure_dust_limit_timeout_sats = htlc_timeout_dust_limit + self.context.counterparty_dust_limit_satoshis;
                if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
                        let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat;
-                       if on_counterparty_tx_dust_htlc_exposure_msat > self.context.get_max_dust_htlc_exposure_msat() {
+                       if on_counterparty_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
                                log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx",
-                                       on_counterparty_tx_dust_htlc_exposure_msat, self.context.get_max_dust_htlc_exposure_msat());
+                                       on_counterparty_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
                                pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
                        }
                }
@@ -2650,9 +2720,9 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.context.holder_dust_limit_satoshis;
                if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
                        let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat;
-                       if on_holder_tx_dust_htlc_exposure_msat > self.context.get_max_dust_htlc_exposure_msat() {
+                       if on_holder_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
                                log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx",
-                                       on_holder_tx_dust_htlc_exposure_msat, self.context.get_max_dust_htlc_exposure_msat());
+                                       on_holder_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
                                pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
                        }
                }
@@ -2795,7 +2865,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                Ok(())
        }
 
-       pub fn commitment_signed<L: Deref>(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<Option<&ChannelMonitorUpdate>, ChannelError>
+       pub fn commitment_signed<L: Deref>(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
                where L::Target: Logger
        {
                if (self.context.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) {
@@ -2883,11 +2953,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                for (idx, (htlc, mut source_opt)) in htlcs_cloned.drain(..).enumerate() {
                        if let Some(_) = htlc.transaction_output_index {
                                let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw,
-                                       self.context.get_counterparty_selected_contest_delay().unwrap(), &htlc, self.context.opt_anchors(),
-                                       false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+                                       self.context.get_counterparty_selected_contest_delay().unwrap(), &htlc, &self.context.channel_type,
+                                       &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
-                               let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.context.opt_anchors(), &keys);
-                               let htlc_sighashtype = if self.context.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
+                               let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &keys);
+                               let htlc_sighashtype = if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
                                let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]);
                                log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.",
                                        log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.serialize()),
@@ -3019,16 +3089,24 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// Public version of the below, checking relevant preconditions first.
        /// If we're not in a state where freeing the holding cell makes sense, this is a no-op and
        /// returns `(None, Vec::new())`.
-       pub fn maybe_free_holding_cell_htlcs<L: Deref>(&mut self, logger: &L) -> (Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>) where L::Target: Logger {
+       pub fn maybe_free_holding_cell_htlcs<F: Deref, L: Deref>(
+               &mut self, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
+       ) -> (Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>)
+       where F::Target: FeeEstimator, L::Target: Logger
+       {
                if self.context.channel_state >= ChannelState::ChannelReady as u32 &&
                   (self.context.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32)) == 0 {
-                       self.free_holding_cell_htlcs(logger)
+                       self.free_holding_cell_htlcs(fee_estimator, logger)
                } else { (None, Vec::new()) }
        }
 
        /// Frees any pending commitment updates in the holding cell, generating the relevant messages
        /// for our counterparty.
-       fn free_holding_cell_htlcs<L: Deref>(&mut self, logger: &L) -> (Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>) where L::Target: Logger {
+       fn free_holding_cell_htlcs<F: Deref, L: Deref>(
+               &mut self, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
+       ) -> (Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>)
+       where F::Target: FeeEstimator, L::Target: Logger
+       {
                assert_eq!(self.context.channel_state & ChannelState::MonitorUpdateInProgress as u32, 0);
                if self.context.holding_cell_htlc_updates.len() != 0 || self.context.holding_cell_update_fee.is_some() {
                        log_trace!(logger, "Freeing holding cell with {} HTLC updates{} in channel {}", self.context.holding_cell_htlc_updates.len(),
@@ -3052,8 +3130,13 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                // handling this case better and maybe fulfilling some of the HTLCs while attempting
                                // to rebalance channels.
                                match &htlc_update {
-                                       &HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet, ..} => {
-                                               match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone(), false, logger) {
+                                       &HTLCUpdateAwaitingACK::AddHTLC {
+                                               amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet,
+                                               skimmed_fee_msat, ..
+                                       } => {
+                                               match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(),
+                                                       onion_routing_packet.clone(), false, skimmed_fee_msat, fee_estimator, logger)
+                                               {
                                                        Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()),
                                                        Err(e) => {
                                                                match e {
@@ -3112,7 +3195,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                return (None, htlcs_to_fail);
                        }
                        let update_fee = if let Some(feerate) = self.context.holding_cell_update_fee.take() {
-                               self.send_update_fee(feerate, false, logger)
+                               self.send_update_fee(feerate, false, fee_estimator, logger)
                        } else {
                                None
                        };
@@ -3139,8 +3222,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail,
        /// generating an appropriate error *after* the channel state has been updated based on the
        /// revoke_and_ack message.
-       pub fn revoke_and_ack<L: Deref>(&mut self, msg: &msgs::RevokeAndACK, logger: &L) -> Result<(Vec<(HTLCSource, PaymentHash)>, Option<&ChannelMonitorUpdate>), ChannelError>
-               where L::Target: Logger,
+       pub fn revoke_and_ack<F: Deref, L: Deref>(&mut self, msg: &msgs::RevokeAndACK,
+               fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
+       ) -> Result<(Vec<(HTLCSource, PaymentHash)>, Option<ChannelMonitorUpdate>), ChannelError>
+       where F::Target: FeeEstimator, L::Target: Logger,
        {
                if (self.context.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) {
                        return Err(ChannelError::Close("Got revoke/ACK message when channel was not in an operational state".to_owned()));
@@ -3340,9 +3425,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        return Ok((Vec::new(), self.push_ret_blockable_mon_update(monitor_update)));
                }
 
-               match self.free_holding_cell_htlcs(logger) {
-                       (Some(_), htlcs_to_fail) => {
-                               let mut additional_update = self.context.pending_monitor_updates.pop().unwrap().update;
+               match self.free_holding_cell_htlcs(fee_estimator, logger) {
+                       (Some(mut additional_update), htlcs_to_fail) => {
                                // free_holding_cell_htlcs may bump latest_monitor_id multiple times but we want them to be
                                // strictly increasing by one, so decrement it here.
                                self.context.latest_monitor_update_id = monitor_update.update_id;
@@ -3376,8 +3460,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// Queues up an outbound update fee by placing it in the holding cell. You should call
        /// [`Self::maybe_free_holding_cell_htlcs`] in order to actually generate and send the
        /// commitment update.
-       pub fn queue_update_fee<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) where L::Target: Logger {
-               let msg_opt = self.send_update_fee(feerate_per_kw, true, logger);
+       pub fn queue_update_fee<F: Deref, L: Deref>(&mut self, feerate_per_kw: u32,
+               fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L)
+       where F::Target: FeeEstimator, L::Target: Logger
+       {
+               let msg_opt = self.send_update_fee(feerate_per_kw, true, fee_estimator, logger);
                assert!(msg_opt.is_none(), "We forced holding cell?");
        }
 
@@ -3388,7 +3475,12 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        ///
        /// You MUST call [`Self::send_commitment_no_state_update`] prior to any other calls on this
        /// [`Channel`] if `force_holding_cell` is false.
-       fn send_update_fee<L: Deref>(&mut self, feerate_per_kw: u32, mut force_holding_cell: bool, logger: &L) -> Option<msgs::UpdateFee> where L::Target: Logger {
+       fn send_update_fee<F: Deref, L: Deref>(
+               &mut self, feerate_per_kw: u32, mut force_holding_cell: bool,
+               fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
+       ) -> Option<msgs::UpdateFee>
+       where F::Target: FeeEstimator, L::Target: Logger
+       {
                if !self.context.is_outbound() {
                        panic!("Cannot send fee from inbound channel");
                }
@@ -3404,7 +3496,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                let outbound_stats = self.context.get_outbound_pending_htlc_stats(Some(feerate_per_kw));
                let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
                let commitment_stats = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, true, logger);
-               let buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.opt_anchors()) * 1000;
+               let buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.get_channel_type()) * 1000;
                let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat;
                if holder_balance_msat < buffer_fee_msat  + self.context.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
                        //TODO: auto-close after a number of failures?
@@ -3415,11 +3507,12 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                // Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`.
                let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
                let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
-               if holder_tx_dust_exposure > self.context.get_max_dust_htlc_exposure_msat() {
+               let max_dust_htlc_exposure_msat = self.context.get_max_dust_htlc_exposure_msat(fee_estimator);
+               if holder_tx_dust_exposure > max_dust_htlc_exposure_msat {
                        log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
                        return None;
                }
-               if counterparty_tx_dust_exposure > self.context.get_max_dust_htlc_exposure_msat() {
+               if counterparty_tx_dust_exposure > max_dust_htlc_exposure_msat {
                        log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
                        return None;
                }
@@ -3558,12 +3651,6 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        {
                assert_eq!(self.context.channel_state & ChannelState::MonitorUpdateInProgress as u32, ChannelState::MonitorUpdateInProgress as u32);
                self.context.channel_state &= !(ChannelState::MonitorUpdateInProgress as u32);
-               let mut found_blocked = false;
-               self.context.pending_monitor_updates.retain(|upd| {
-                       if found_blocked { debug_assert!(upd.blocked, "No mons may be unblocked after a blocked one"); }
-                       if upd.blocked { found_blocked = true; }
-                       upd.blocked
-               });
 
                // If we're past (or at) the FundingSent stage on an outbound channel, try to
                // (re-)broadcast the funding transaction as we may have declined to broadcast it when we
@@ -3643,7 +3730,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                if self.context.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
                        return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
                }
-               Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
+               Channel::<Signer>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
                let feerate_over_dust_buffer = msg.feerate_per_kw > self.context.get_dust_buffer_feerate(None);
 
                self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
@@ -3656,11 +3743,12 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        let outbound_stats = self.context.get_outbound_pending_htlc_stats(None);
                        let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
                        let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
-                       if holder_tx_dust_exposure > self.context.get_max_dust_htlc_exposure_msat() {
+                       let max_dust_htlc_exposure_msat = self.context.get_max_dust_htlc_exposure_msat(fee_estimator);
+                       if holder_tx_dust_exposure > max_dust_htlc_exposure_msat {
                                return Err(ChannelError::Close(format!("Peer sent update_fee with a feerate ({}) which may over-expose us to dust-in-flight on our own transactions (totaling {} msat)",
                                        msg.feerate_per_kw, holder_tx_dust_exposure)));
                        }
-                       if counterparty_tx_dust_exposure > self.context.get_max_dust_htlc_exposure_msat() {
+                       if counterparty_tx_dust_exposure > max_dust_htlc_exposure_msat {
                                return Err(ChannelError::Close(format!("Peer sent update_fee with a feerate ({}) which may over-expose us to dust-in-flight on our counterparty's transactions (totaling {} msat)",
                                        msg.feerate_per_kw, counterparty_tx_dust_exposure)));
                        }
@@ -3695,6 +3783,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                        payment_hash: htlc.payment_hash,
                                        cltv_expiry: htlc.cltv_expiry,
                                        onion_routing_packet: (**onion_packet).clone(),
+                                       skimmed_fee_msat: htlc.skimmed_fee_msat,
                                });
                        }
                }
@@ -3981,12 +4070,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// this point if we're the funder we should send the initial closing_signed, and in any case
        /// shutdown should complete within a reasonable timeframe.
        fn closing_negotiation_ready(&self) -> bool {
-               self.context.pending_inbound_htlcs.is_empty() && self.context.pending_outbound_htlcs.is_empty() &&
-                       self.context.channel_state &
-                               (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::AwaitingRemoteRevoke as u32 |
-                                ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32)
-                               == BOTH_SIDES_SHUTDOWN_MASK &&
-                       self.context.pending_update_fee.is_none()
+               self.context.closing_negotiation_ready()
        }
 
        /// Checks if the closing_signed negotiation is making appropriate progress, possibly returning
@@ -4066,7 +4150,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 
        pub fn shutdown<SP: Deref>(
                &mut self, signer_provider: &SP, their_features: &InitFeatures, msg: &msgs::Shutdown
-       ) -> Result<(Option<msgs::Shutdown>, Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
+       ) -> Result<(Option<msgs::Shutdown>, Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
        where SP::Target: SignerProvider
        {
                if self.context.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
@@ -4132,9 +4216,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                }],
                        };
                        self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new());
-                       if self.push_blockable_mon_update(monitor_update) {
-                               self.context.pending_monitor_updates.last().map(|upd| &upd.update)
-                       } else { None }
+                       self.push_ret_blockable_mon_update(monitor_update)
                } else { None };
                let shutdown = if send_shutdown {
                        Some(msgs::Shutdown {
@@ -4424,64 +4506,37 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                (self.context.channel_state & ChannelState::MonitorUpdateInProgress as u32) != 0
        }
 
-       pub fn get_latest_complete_monitor_update_id(&self) -> u64 {
-               if self.context.pending_monitor_updates.is_empty() { return self.context.get_latest_monitor_update_id(); }
-               self.context.pending_monitor_updates[0].update.update_id - 1
+       /// Gets the latest [`ChannelMonitorUpdate`] ID which has been released and is in-flight.
+       pub fn get_latest_unblocked_monitor_update_id(&self) -> u64 {
+               if self.context.blocked_monitor_updates.is_empty() { return self.context.get_latest_monitor_update_id(); }
+               self.context.blocked_monitor_updates[0].update.update_id - 1
        }
 
        /// Returns the next blocked monitor update, if one exists, and a bool which indicates a
        /// further blocked monitor update exists after the next.
-       pub fn unblock_next_blocked_monitor_update(&mut self) -> Option<(&ChannelMonitorUpdate, bool)> {
-               for i in 0..self.context.pending_monitor_updates.len() {
-                       if self.context.pending_monitor_updates[i].blocked {
-                               self.context.pending_monitor_updates[i].blocked = false;
-                               return Some((&self.context.pending_monitor_updates[i].update,
-                                       self.context.pending_monitor_updates.len() > i + 1));
-                       }
-               }
-               None
-       }
-
-       /// Pushes a new monitor update into our monitor update queue, returning whether it should be
-       /// immediately given to the user for persisting or if it should be held as blocked.
-       fn push_blockable_mon_update(&mut self, update: ChannelMonitorUpdate) -> bool {
-               let release_monitor = self.context.pending_monitor_updates.iter().all(|upd| !upd.blocked);
-               self.context.pending_monitor_updates.push(PendingChannelMonitorUpdate {
-                       update, blocked: !release_monitor
-               });
-               release_monitor
+       pub fn unblock_next_blocked_monitor_update(&mut self) -> Option<(ChannelMonitorUpdate, bool)> {
+               if self.context.blocked_monitor_updates.is_empty() { return None; }
+               Some((self.context.blocked_monitor_updates.remove(0).update,
+                       !self.context.blocked_monitor_updates.is_empty()))
        }
 
-       /// Pushes a new monitor update into our monitor update queue, returning a reference to it if
-       /// it should be immediately given to the user for persisting or `None` if it should be held as
-       /// blocked.
+       /// Pushes a new monitor update into our monitor update queue, returning it if it should be
+       /// immediately given to the user for persisting or `None` if it should be held as blocked.
        fn push_ret_blockable_mon_update(&mut self, update: ChannelMonitorUpdate)
-       -> Option<&ChannelMonitorUpdate> {
-               let release_monitor = self.push_blockable_mon_update(update);
-               if release_monitor { self.context.pending_monitor_updates.last().map(|upd| &upd.update) } else { None }
-       }
-
-       pub fn no_monitor_updates_pending(&self) -> bool {
-               self.context.pending_monitor_updates.is_empty()
-       }
-
-       pub fn complete_all_mon_updates_through(&mut self, update_id: u64) {
-               self.context.pending_monitor_updates.retain(|upd| {
-                       if upd.update.update_id <= update_id {
-                               assert!(!upd.blocked, "Completed update must have flown");
-                               false
-                       } else { true }
-               });
-       }
-
-       pub fn complete_one_mon_update(&mut self, update_id: u64) {
-               self.context.pending_monitor_updates.retain(|upd| upd.update.update_id != update_id);
+       -> Option<ChannelMonitorUpdate> {
+               let release_monitor = self.context.blocked_monitor_updates.is_empty();
+               if !release_monitor {
+                       self.context.blocked_monitor_updates.push(PendingChannelMonitorUpdate {
+                               update,
+                       });
+                       None
+               } else {
+                       Some(update)
+               }
        }
 
-       /// Returns an iterator over all unblocked monitor updates which have not yet completed.
-       pub fn uncompleted_unblocked_mon_updates(&self) -> impl Iterator<Item=&ChannelMonitorUpdate> {
-               self.context.pending_monitor_updates.iter()
-                       .filter_map(|upd| if upd.blocked { None } else { Some(&upd.update) })
+       pub fn blocked_monitor_updates_pending(&self) -> usize {
+               self.context.blocked_monitor_updates.len()
        }
 
        /// Returns true if the channel is awaiting the persistence of the initial ChannelMonitor.
@@ -5049,11 +5104,16 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// commitment update.
        ///
        /// `Err`s will only be [`ChannelError::Ignore`].
-       pub fn queue_add_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
-               onion_routing_packet: msgs::OnionPacket, logger: &L)
-       -> Result<(), ChannelError> where L::Target: Logger {
+       pub fn queue_add_htlc<F: Deref, L: Deref>(
+               &mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
+               onion_routing_packet: msgs::OnionPacket, skimmed_fee_msat: Option<u64>,
+               fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
+       ) -> Result<(), ChannelError>
+       where F::Target: FeeEstimator, L::Target: Logger
+       {
                self
-                       .send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, true, logger)
+                       .send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, true,
+                               skimmed_fee_msat, fee_estimator, logger)
                        .map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
                        .map_err(|err| {
                                if let ChannelError::Ignore(_) = err { /* fine */ }
@@ -5078,9 +5138,13 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// on this [`Channel`] if `force_holding_cell` is false.
        ///
        /// `Err`s will only be [`ChannelError::Ignore`].
-       fn send_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
-               onion_routing_packet: msgs::OnionPacket, mut force_holding_cell: bool, logger: &L)
-       -> Result<Option<msgs::UpdateAddHTLC>, ChannelError> where L::Target: Logger {
+       fn send_htlc<F: Deref, L: Deref>(
+               &mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
+               onion_routing_packet: msgs::OnionPacket, mut force_holding_cell: bool,
+               skimmed_fee_msat: Option<u64>, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
+       ) -> Result<Option<msgs::UpdateAddHTLC>, ChannelError>
+       where F::Target: FeeEstimator, L::Target: Logger
+       {
                if (self.context.channel_state & (ChannelState::ChannelReady as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelReady as u32) {
                        return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned()));
                }
@@ -5093,7 +5157,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        return Err(ChannelError::Ignore("Cannot send 0-msat HTLC".to_owned()));
                }
 
-               let available_balances = self.context.get_available_balances();
+               let available_balances = self.context.get_available_balances(fee_estimator);
                if amount_msat < available_balances.next_outbound_htlc_minimum_msat {
                        return Err(ChannelError::Ignore(format!("Cannot send less than our next-HTLC minimum - {} msat",
                                available_balances.next_outbound_htlc_minimum_msat)));
@@ -5132,6 +5196,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                cltv_expiry,
                                source,
                                onion_routing_packet,
+                               skimmed_fee_msat,
                        });
                        return Ok(None);
                }
@@ -5143,6 +5208,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        cltv_expiry,
                        state: OutboundHTLCState::LocalAnnounced(Box::new(onion_routing_packet.clone())),
                        source,
+                       skimmed_fee_msat,
                });
 
                let res = msgs::UpdateAddHTLC {
@@ -5152,6 +5218,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        payment_hash,
                        cltv_expiry,
                        onion_routing_packet,
+                       skimmed_fee_msat,
                };
                self.context.next_holder_htlc_id += 1;
 
@@ -5229,7 +5296,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                                && info.next_holder_htlc_id == self.context.next_holder_htlc_id
                                                && info.next_counterparty_htlc_id == self.context.next_counterparty_htlc_id
                                                && info.feerate == self.context.feerate_per_kw {
-                                                       let actual_fee = commit_tx_fee_msat(self.context.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.context.opt_anchors());
+                                                       let actual_fee = commit_tx_fee_msat(self.context.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.context.get_channel_type());
                                                        assert_eq!(actual_fee, info.fee);
                                                }
                                }
@@ -5269,8 +5336,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 
                        for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) {
                                log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}",
-                                       encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.context.get_holder_selected_contest_delay(), htlc, self.context.opt_anchors(), false, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
-                                       encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, self.context.opt_anchors(), &counterparty_keys)),
+                                       encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.context.get_holder_selected_contest_delay(), htlc, &self.context.channel_type, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
+                                       encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &counterparty_keys)),
                                        log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()),
                                        log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.context.channel_id()));
                        }
@@ -5290,8 +5357,15 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        ///
        /// Shorthand for calling [`Self::send_htlc`] followed by a commitment update, see docs on
        /// [`Self::send_htlc`] and [`Self::build_commitment_no_state_update`] for more info.
-       pub fn send_htlc_and_commit<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<&ChannelMonitorUpdate>, ChannelError> where L::Target: Logger {
-               let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger);
+       pub fn send_htlc_and_commit<F: Deref, L: Deref>(
+               &mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32,
+               source: HTLCSource, onion_routing_packet: msgs::OnionPacket, skimmed_fee_msat: Option<u64>,
+               fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
+       ) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
+       where F::Target: FeeEstimator, L::Target: Logger
+       {
+               let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source,
+                       onion_routing_packet, false, skimmed_fee_msat, fee_estimator, logger);
                if let Err(e) = &send_res { if let ChannelError::Ignore(_) = e {} else { debug_assert!(false, "Sending cannot trigger channel failure"); } }
                match send_res? {
                        Some(_) => {
@@ -5323,7 +5397,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// [`ChannelMonitorUpdate`] will be returned).
        pub fn get_shutdown<SP: Deref>(&mut self, signer_provider: &SP, their_features: &InitFeatures,
                target_feerate_sats_per_kw: Option<u32>, override_shutdown_script: Option<ShutdownScript>)
-       -> Result<(msgs::Shutdown, Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), APIError>
+       -> Result<(msgs::Shutdown, Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), APIError>
        where SP::Target: SignerProvider {
                for htlc in self.context.pending_outbound_htlcs.iter() {
                        if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
@@ -5394,9 +5468,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                                }],
                        };
                        self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new());
-                       if self.push_blockable_mon_update(monitor_update) {
-                               self.context.pending_monitor_updates.last().map(|upd| &upd.update)
-                       } else { None }
+                       self.push_ret_blockable_mon_update(monitor_update)
                } else { None };
                let shutdown = msgs::Shutdown {
                        channel_id: self.context.channel_id,
@@ -5439,6 +5511,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 /// A not-yet-funded outbound (from holder) channel using V1 channel establishment.
 pub(super) struct OutboundV1Channel<Signer: ChannelSigner> {
        pub context: ChannelContext<Signer>,
+       pub unfunded_context: UnfundedChannelContext,
 }
 
 impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
@@ -5479,10 +5552,15 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                let channel_type = Self::get_initial_channel_type(&config, their_features);
                debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config)));
 
-               let feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
+               let commitment_conf_target = if channel_type.supports_anchors_zero_fee_htlc_tx() {
+                       ConfirmationTarget::MempoolMinimum
+               } else {
+                       ConfirmationTarget::Normal
+               };
+               let commitment_feerate = fee_estimator.bounded_sat_per_1000_weight(commitment_conf_target);
 
                let value_to_self_msat = channel_value_satoshis * 1000 - push_msat;
-               let commitment_tx_fee = commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, channel_type.requires_anchors_zero_fee_htlc_tx());
+               let commitment_tx_fee = commit_tx_fee_msat(commitment_feerate, MIN_AFFORDABLE_HTLC_COUNT, &channel_type);
                if value_to_self_msat < commitment_tx_fee {
                        return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) });
                }
@@ -5576,7 +5654,7 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                                short_channel_id: None,
                                channel_creation_height: current_chain_height,
 
-                               feerate_per_kw: feerate,
+                               feerate_per_kw: commitment_feerate,
                                counterparty_dust_limit_satoshis: 0,
                                holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
                                counterparty_max_htlc_value_in_flight_msat: 0,
@@ -5597,8 +5675,7 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                                        is_outbound_from_holder: true,
                                        counterparty_parameters: None,
                                        funding_outpoint: None,
-                                       opt_anchors: if channel_type.requires_anchors_zero_fee_htlc_tx() { Some(()) } else { None },
-                                       opt_non_zero_fee_anchors: None
+                                       channel_type_features: channel_type.clone()
                                },
                                funding_transaction: None,
 
@@ -5635,13 +5712,14 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                                channel_type,
                                channel_keys_id,
 
-                               pending_monitor_updates: Vec::new(),
-                       }
+                               blocked_monitor_updates: Vec::new(),
+                       },
+                       unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
                })
        }
 
-       /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
-       fn get_outbound_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ChannelError> where L::Target: Logger {
+       /// If an Err is returned, it is a ChannelError::Close (for get_funding_created)
+       fn get_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ChannelError> where L::Target: Logger {
                let counterparty_keys = self.context.build_remote_transaction_keys();
                let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
                Ok(self.context.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
@@ -5655,7 +5733,7 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
        /// Note that channel_id changes during this call!
        /// Do NOT broadcast the funding transaction until after a successful funding_signed call!
        /// If an Err is returned, it is a ChannelError::Close.
-       pub fn get_outbound_funding_created<L: Deref>(mut self, funding_transaction: Transaction, funding_txo: OutPoint, logger: &L)
+       pub fn get_funding_created<L: Deref>(mut self, funding_transaction: Transaction, funding_txo: OutPoint, logger: &L)
        -> Result<(Channel<Signer>, msgs::FundingCreated), (Self, ChannelError)> where L::Target: Logger {
                if !self.context.is_outbound() {
                        panic!("Tried to create outbound funding_created message on an inbound channel!");
@@ -5672,7 +5750,7 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
                self.context.holder_signer.provide_channel_parameters(&self.context.channel_transaction_parameters);
 
-               let signature = match self.get_outbound_funding_created_signature(logger) {
+               let signature = match self.get_funding_created_signature(logger) {
                        Ok(res) => res,
                        Err(e) => {
                                log_error!(logger, "Got bad signatures: {:?}!", e);
@@ -5720,12 +5798,9 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                // Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
                // set it now. If they don't understand it, we'll fall back to our default of
                // `only_static_remotekey`.
-               #[cfg(anchors)]
-               { // Attributes are not allowed on if expressions on our current MSRV of 1.41.
-                       if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
-                               their_features.supports_anchors_zero_fee_htlc_tx() {
-                               ret.set_anchors_zero_fee_htlc_tx_required();
-                       }
+               if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
+                       their_features.supports_anchors_zero_fee_htlc_tx() {
+                       ret.set_anchors_zero_fee_htlc_tx_required();
                }
 
                ret
@@ -5734,7 +5809,12 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
        /// If we receive an error message, it may only be a rejection of the channel type we tried,
        /// not of our ability to open any channel at all. Thus, on error, we should first call this
        /// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
-       pub(crate) fn maybe_handle_error_without_close(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
+       pub(crate) fn maybe_handle_error_without_close<F: Deref>(
+               &mut self, chain_hash: BlockHash, fee_estimator: &LowerBoundedFeeEstimator<F>
+       ) -> Result<msgs::OpenChannel, ()>
+       where
+               F::Target: FeeEstimator
+       {
                if !self.context.is_outbound() || self.context.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }
                if self.context.channel_type == ChannelTypeFeatures::only_static_remote_key() {
                        // We've exhausted our options
@@ -5751,13 +5831,14 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                // whatever reason.
                if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() {
                        self.context.channel_type.clear_anchors_zero_fee_htlc_tx();
-                       assert!(self.context.channel_transaction_parameters.opt_non_zero_fee_anchors.is_none());
-                       self.context.channel_transaction_parameters.opt_anchors = None;
+                       self.context.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
+                       assert!(!self.context.channel_transaction_parameters.channel_type_features.supports_anchors_nonzero_fee_htlc_tx());
                } else if self.context.channel_type.supports_scid_privacy() {
                        self.context.channel_type.clear_scid_privacy();
                } else {
                        self.context.channel_type = ChannelTypeFeatures::only_static_remote_key();
                }
+               self.context.channel_transaction_parameters.channel_type_features = self.context.channel_type.clone();
                Ok(self.get_open_channel(chain_hash))
        }
 
@@ -5876,7 +5957,8 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
                        if channel_type != ChannelTypeFeatures::only_static_remote_key() {
                                return Err(ChannelError::Close("Only static_remote_key is supported for non-negotiated channel types".to_owned()));
                        }
-                       self.context.channel_type = channel_type;
+                       self.context.channel_type = channel_type.clone();
+                       self.context.channel_transaction_parameters.channel_type_features = channel_type;
                }
 
                let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
@@ -5937,6 +6019,7 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
 /// A not-yet-funded inbound (from counterparty) channel using V1 channel establishment.
 pub(super) struct InboundV1Channel<Signer: ChannelSigner> {
        pub context: ChannelContext<Signer>,
+       pub unfunded_context: UnfundedChannelContext,
 }
 
 impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
@@ -5983,7 +6066,6 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
                        }
                        channel_type
                };
-               let opt_anchors = channel_type.supports_anchors_zero_fee_htlc_tx();
 
                let channel_keys_id = signer_provider.generate_channel_keys_id(true, msg.funding_satoshis, user_id);
                let holder_signer = signer_provider.derive_channel_signer(msg.funding_satoshis, channel_keys_id);
@@ -6020,7 +6102,7 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
                if msg.htlc_minimum_msat >= full_channel_value_msat {
                        return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
                }
-               Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw, None, logger)?;
+               Channel::<Signer>::check_remote_fee(&channel_type, fee_estimator, msg.feerate_per_kw, None, logger)?;
 
                let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
                if msg.to_self_delay > max_counterparty_selected_contest_delay {
@@ -6084,7 +6166,7 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
                // check if the funder's amount for the initial commitment tx is sufficient
                // for full fee payment plus a few HTLCs to ensure the channel will be useful.
                let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat;
-               let commitment_tx_fee = commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, opt_anchors) / 1000;
+               let commitment_tx_fee = commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) / 1000;
                if funders_amount_msat / 1000 < commitment_tx_fee {
                        return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", funders_amount_msat / 1000, commitment_tx_fee)));
                }
@@ -6227,8 +6309,7 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
                                                pubkeys: counterparty_pubkeys,
                                        }),
                                        funding_outpoint: None,
-                                       opt_anchors: if opt_anchors { Some(()) } else { None },
-                                       opt_non_zero_fee_anchors: None
+                                       channel_type_features: channel_type.clone()
                                },
                                funding_transaction: None,
 
@@ -6265,8 +6346,9 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
                                channel_type,
                                channel_keys_id,
 
-                               pending_monitor_updates: Vec::new(),
-                       }
+                               blocked_monitor_updates: Vec::new(),
+                       },
+                       unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
                };
 
                Ok(chan)
@@ -6616,9 +6698,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for Channel<Signer> {
                }
 
                let mut preimages: Vec<&Option<PaymentPreimage>> = vec![];
+               let mut pending_outbound_skimmed_fees: Vec<Option<u64>> = Vec::new();
 
                (self.context.pending_outbound_htlcs.len() as u64).write(writer)?;
-               for htlc in self.context.pending_outbound_htlcs.iter() {
+               for (idx, htlc) in self.context.pending_outbound_htlcs.iter().enumerate() {
                        htlc.htlc_id.write(writer)?;
                        htlc.amount_msat.write(writer)?;
                        htlc.cltv_expiry.write(writer)?;
@@ -6654,18 +6737,37 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for Channel<Signer> {
                                        reason.write(writer)?;
                                }
                        }
+                       if let Some(skimmed_fee) = htlc.skimmed_fee_msat {
+                               if pending_outbound_skimmed_fees.is_empty() {
+                                       for _ in 0..idx { pending_outbound_skimmed_fees.push(None); }
+                               }
+                               pending_outbound_skimmed_fees.push(Some(skimmed_fee));
+                       } else if !pending_outbound_skimmed_fees.is_empty() {
+                               pending_outbound_skimmed_fees.push(None);
+                       }
                }
 
+               let mut holding_cell_skimmed_fees: Vec<Option<u64>> = Vec::new();
                (self.context.holding_cell_htlc_updates.len() as u64).write(writer)?;
-               for update in self.context.holding_cell_htlc_updates.iter() {
+               for (idx, update) in self.context.holding_cell_htlc_updates.iter().enumerate() {
                        match update {
-                               &HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, ref cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet } => {
+                               &HTLCUpdateAwaitingACK::AddHTLC {
+                                       ref amount_msat, ref cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet,
+                                       skimmed_fee_msat,
+                               } => {
                                        0u8.write(writer)?;
                                        amount_msat.write(writer)?;
                                        cltv_expiry.write(writer)?;
                                        payment_hash.write(writer)?;
                                        source.write(writer)?;
                                        onion_routing_packet.write(writer)?;
+
+                                       if let Some(skimmed_fee) = skimmed_fee_msat {
+                                               if holding_cell_skimmed_fees.is_empty() {
+                                                       for _ in 0..idx { holding_cell_skimmed_fees.push(None); }
+                                               }
+                                               holding_cell_skimmed_fees.push(Some(skimmed_fee));
+                                       } else if !holding_cell_skimmed_fees.is_empty() { holding_cell_skimmed_fees.push(None); }
                                },
                                &HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, ref htlc_id } => {
                                        1u8.write(writer)?;
@@ -6818,10 +6920,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for Channel<Signer> {
                        (5, self.context.config, required),
                        (6, serialized_holder_htlc_max_in_flight, option),
                        (7, self.context.shutdown_scriptpubkey, option),
+                       (8, self.context.blocked_monitor_updates, optional_vec),
                        (9, self.context.target_closing_feerate_sats_per_kw, option),
-                       (11, self.context.monitor_pending_finalized_fulfills, vec_type),
+                       (11, self.context.monitor_pending_finalized_fulfills, required_vec),
                        (13, self.context.channel_creation_height, required),
-                       (15, preimages, vec_type),
+                       (15, preimages, required_vec),
                        (17, self.context.announcement_sigs_state, required),
                        (19, self.context.latest_inbound_scid_alias, option),
                        (21, self.context.outbound_scid_alias, required),
@@ -6831,7 +6934,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for Channel<Signer> {
                        (28, holder_max_accepted_htlcs, option),
                        (29, self.context.temporary_channel_id, option),
                        (31, channel_pending_event_emitted, option),
-                       (33, self.context.pending_monitor_updates, vec_type),
+                       (35, pending_outbound_skimmed_fees, optional_vec),
+                       (37, holding_cell_skimmed_fees, optional_vec),
                });
 
                Ok(())
@@ -6942,6 +7046,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                                        },
                                        _ => return Err(DecodeError::InvalidValue),
                                },
+                               skimmed_fee_msat: None,
                        });
                }
 
@@ -6955,6 +7060,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                                        payment_hash: Readable::read(reader)?,
                                        source: Readable::read(reader)?,
                                        onion_routing_packet: Readable::read(reader)?,
+                                       skimmed_fee_msat: None,
                                },
                                1 => HTLCUpdateAwaitingACK::ClaimHTLC {
                                        payment_preimage: Readable::read(reader)?,
@@ -7051,7 +7157,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        _ => return Err(DecodeError::InvalidValue),
                };
 
-               let channel_parameters: ChannelTransactionParameters = Readable::read(reader)?;
+               let mut channel_parameters: ChannelTransactionParameters = Readable::read(reader)?;
                let funding_transaction = Readable::read(reader)?;
 
                let counterparty_cur_commitment_point = Readable::read(reader)?;
@@ -7108,7 +7214,10 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                let mut temporary_channel_id: Option<[u8; 32]> = None;
                let mut holder_max_accepted_htlcs: Option<u16> = None;
 
-               let mut pending_monitor_updates = Some(Vec::new());
+               let mut blocked_monitor_updates = Some(Vec::new());
+
+               let mut pending_outbound_skimmed_fees_opt: Option<Vec<Option<u64>>> = None;
+               let mut holding_cell_skimmed_fees_opt: Option<Vec<Option<u64>>> = None;
 
                read_tlv_fields!(reader, {
                        (0, announcement_sigs, option),
@@ -7119,10 +7228,11 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        (5, config, option), // Note that if none is provided we will *not* overwrite the existing one.
                        (6, holder_max_htlc_value_in_flight_msat, option),
                        (7, shutdown_scriptpubkey, option),
+                       (8, blocked_monitor_updates, optional_vec),
                        (9, target_closing_feerate_sats_per_kw, option),
-                       (11, monitor_pending_finalized_fulfills, vec_type),
+                       (11, monitor_pending_finalized_fulfills, optional_vec),
                        (13, channel_creation_height, option),
-                       (15, preimages_opt, vec_type),
+                       (15, preimages_opt, optional_vec),
                        (17, announcement_sigs_state, option),
                        (19, latest_inbound_scid_alias, option),
                        (21, outbound_scid_alias, option),
@@ -7132,7 +7242,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        (28, holder_max_accepted_htlcs, option),
                        (29, temporary_channel_id, option),
                        (31, channel_pending_event_emitted, option),
-                       (33, pending_monitor_updates, vec_type),
+                       (35, pending_outbound_skimmed_fees_opt, optional_vec),
+                       (37, holding_cell_skimmed_fees_opt, optional_vec),
                });
 
                let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id {
@@ -7177,6 +7288,10 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        return Err(DecodeError::UnknownRequiredFeature);
                }
 
+               // ChannelTransactionParameters may have had an empty features set upon deserialization.
+               // To account for that, we're proactively setting/overriding the field here.
+               channel_parameters.channel_type_features = chan_features.clone();
+
                let mut secp_ctx = Secp256k1::new();
                secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
 
@@ -7187,6 +7302,25 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
 
                let holder_max_accepted_htlcs = holder_max_accepted_htlcs.unwrap_or(DEFAULT_MAX_HTLCS);
 
+               if let Some(skimmed_fees) = pending_outbound_skimmed_fees_opt {
+                       let mut iter = skimmed_fees.into_iter();
+                       for htlc in pending_outbound_htlcs.iter_mut() {
+                               htlc.skimmed_fee_msat = iter.next().ok_or(DecodeError::InvalidValue)?;
+                       }
+                       // We expect all skimmed fees to be consumed above
+                       if iter.next().is_some() { return Err(DecodeError::InvalidValue) }
+               }
+               if let Some(skimmed_fees) = holding_cell_skimmed_fees_opt {
+                       let mut iter = skimmed_fees.into_iter();
+                       for htlc in holding_cell_htlc_updates.iter_mut() {
+                               if let HTLCUpdateAwaitingACK::AddHTLC { ref mut skimmed_fee_msat, .. } = htlc {
+                                       *skimmed_fee_msat = iter.next().ok_or(DecodeError::InvalidValue)?;
+                               }
+                       }
+                       // We expect all skimmed fees to be consumed above
+                       if iter.next().is_some() { return Err(DecodeError::InvalidValue) }
+               }
+
                Ok(Channel {
                        context: ChannelContext {
                                user_id,
@@ -7304,7 +7438,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                                channel_type: channel_type.unwrap(),
                                channel_keys_id,
 
-                               pending_monitor_updates: pending_monitor_updates.unwrap(),
+                               blocked_monitor_updates: blocked_monitor_updates.unwrap(),
                        }
                })
        }
@@ -7321,7 +7455,6 @@ mod tests {
        use hex;
        use crate::ln::PaymentHash;
        use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
-       #[cfg(anchors)]
        use crate::ln::channel::InitFeatures;
        use crate::ln::channel::{Channel, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat};
        use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
@@ -7372,7 +7505,8 @@ mod tests {
                // arithmetic, causing a panic with debug assertions enabled.
                let fee_est = TestFeeEstimator { fee_est: 42 };
                let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_est);
-               assert!(Channel::<InMemorySigner>::check_remote_fee(&bounded_fee_estimator,
+               assert!(Channel::<InMemorySigner>::check_remote_fee(
+                       &ChannelTypeFeatures::only_static_remote_key(), &bounded_fee_estimator,
                        u32::max_value(), None, &&test_utils::TestLogger::new()).is_err());
        }
 
@@ -7411,7 +7545,7 @@ mod tests {
                }
        }
 
-       #[cfg(not(feature = "grind_signatures"))]
+       #[cfg(all(feature = "_test_vectors", not(feature = "grind_signatures")))]
        fn public_from_secret_hex(secp_ctx: &Secp256k1<bitcoin::secp256k1::All>, hex: &str) -> PublicKey {
                PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(hex).unwrap()[..]).unwrap())
        }
@@ -7502,7 +7636,7 @@ mod tests {
                        value: 10000000, script_pubkey: output_script.clone(),
                }]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
-               let (mut node_a_chan, funding_created_msg) = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap();
+               let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap();
                let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
 
                // Node B --> Node A: funding signed
@@ -7529,20 +7663,21 @@ mod tests {
                                session_priv: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
                                first_hop_htlc_msat: 548,
                                payment_id: PaymentId([42; 32]),
-                       }
+                       },
+                       skimmed_fee_msat: None,
                });
 
                // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
                // the dust limit check.
                let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
                let local_commit_tx_fee = node_a_chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
-               let local_commit_fee_0_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 0, node_a_chan.context.opt_anchors());
+               let local_commit_fee_0_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 0, node_a_chan.context.get_channel_type());
                assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs);
 
                // Finally, make sure that when Node A calculates the remote's commitment transaction fees, all
                // of the HTLCs are seen to be above the dust limit.
                node_a_chan.context.channel_transaction_parameters.is_outbound_from_holder = false;
-               let remote_commit_fee_3_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.context.opt_anchors());
+               let remote_commit_fee_3_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.context.get_channel_type());
                let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
                let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(htlc_candidate, None);
                assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs);
@@ -7564,18 +7699,18 @@ mod tests {
                let config = UserConfig::default();
                let mut chan = OutboundV1Channel::<EnforcingSigner>::new(&fee_est, &&keys_provider, &&keys_provider, node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap();
 
-               let commitment_tx_fee_0_htlcs = commit_tx_fee_msat(chan.context.feerate_per_kw, 0, chan.context.opt_anchors());
-               let commitment_tx_fee_1_htlc = commit_tx_fee_msat(chan.context.feerate_per_kw, 1, chan.context.opt_anchors());
+               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());
 
                // If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be
                // counted as dust when it shouldn't be.
-               let htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.context.opt_anchors()) / 1000) + chan.context.holder_dust_limit_satoshis + 1) * 1000;
+               let htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.holder_dust_limit_satoshis + 1) * 1000;
                let htlc_candidate = HTLCCandidate::new(htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
                let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
                assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
 
                // If swapped: this HTLC would be counted as non-dust when it shouldn't be.
-               let dust_htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.context.opt_anchors()) / 1000) + chan.context.holder_dust_limit_satoshis - 1) * 1000;
+               let dust_htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.holder_dust_limit_satoshis - 1) * 1000;
                let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_below_success, HTLCInitiator::RemoteOffered);
                let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
                assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
@@ -7583,13 +7718,13 @@ mod tests {
                chan.context.channel_transaction_parameters.is_outbound_from_holder = false;
 
                // If swapped: this HTLC would be counted as non-dust when it shouldn't be.
-               let dust_htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.context.opt_anchors()) / 1000) + chan.context.counterparty_dust_limit_satoshis + 1) * 1000;
+               let dust_htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.counterparty_dust_limit_satoshis + 1) * 1000;
                let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
                let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(htlc_candidate, None);
                assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
 
                // If swapped: this HTLC would be counted as dust when it shouldn't be.
-               let htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.context.opt_anchors()) / 1000) + chan.context.counterparty_dust_limit_satoshis - 1) * 1000;
+               let htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.counterparty_dust_limit_satoshis - 1) * 1000;
                let htlc_candidate = HTLCCandidate::new(htlc_amt_below_success, HTLCInitiator::RemoteOffered);
                let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(htlc_candidate, None);
                assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
@@ -7628,7 +7763,7 @@ mod tests {
                        value: 10000000, script_pubkey: output_script.clone(),
                }]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
-               let (mut node_a_chan, funding_created_msg) = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap();
+               let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap();
                let (mut node_b_chan, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
 
                // Node B --> Node A: funding signed
@@ -7816,7 +7951,7 @@ mod tests {
                        value: 10000000, script_pubkey: output_script.clone(),
                }]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
-               let (mut node_a_chan, funding_created_msg) = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap();
+               let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap();
                let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
 
                // Node B --> Node A: funding signed
@@ -7937,15 +8072,15 @@ mod tests {
 
                macro_rules! test_commitment {
                        ( $counterparty_sig_hex: expr, $sig_hex: expr, $tx_hex: expr, $($remain:tt)* ) => {
-                               chan.context.channel_transaction_parameters.opt_anchors = None;
-                               test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, false, $($remain)*);
+                               chan.context.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::only_static_remote_key();
+                               test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, &ChannelTypeFeatures::only_static_remote_key(), $($remain)*);
                        };
                }
 
                macro_rules! test_commitment_with_anchors {
                        ( $counterparty_sig_hex: expr, $sig_hex: expr, $tx_hex: expr, $($remain:tt)* ) => {
-                               chan.context.channel_transaction_parameters.opt_anchors = Some(());
-                               test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, true, $($remain)*);
+                               chan.context.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
+                               test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), $($remain)*);
                        };
                }
 
@@ -8004,9 +8139,9 @@ mod tests {
                                        let ref htlc = htlcs[$htlc_idx];
                                        let htlc_tx = chan_utils::build_htlc_transaction(&unsigned_tx.txid, chan.context.feerate_per_kw,
                                                chan.context.get_counterparty_selected_contest_delay().unwrap(),
-                                               &htlc, $opt_anchors, false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+                                               &htlc, $opt_anchors, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
                                        let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, $opt_anchors, &keys);
-                                       let htlc_sighashtype = if $opt_anchors { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
+                                       let htlc_sighashtype = if $opt_anchors.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
                                        let htlc_sighash = Message::from_slice(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]).unwrap();
                                        assert!(secp_ctx.verify_ecdsa(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key).is_ok(), "verify counterparty htlc sig");
 
@@ -8023,7 +8158,7 @@ mod tests {
                                        }
 
                                        let htlc_sig = htlc_sig_iter.next().unwrap();
-                                       let num_anchors = if $opt_anchors { 2 } else { 0 };
+                                       let num_anchors = if $opt_anchors.supports_anchors_zero_fee_htlc_tx() { 2 } else { 0 };
                                        assert_eq!((htlc_sig.0).0.transaction_output_index, Some($htlc_idx + num_anchors), "output index");
 
                                        let signature = Signature::from_der(&hex::decode($htlc_sig_hex).unwrap()[..]).unwrap();
@@ -8086,6 +8221,7 @@ mod tests {
                                payment_hash: PaymentHash([0; 32]),
                                state: OutboundHTLCState::Committed,
                                source: HTLCSource::dummy(),
+                               skimmed_fee_msat: None,
                        };
                        out.payment_hash.0 = Sha256::hash(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).into_inner();
                        out
@@ -8098,6 +8234,7 @@ mod tests {
                                payment_hash: PaymentHash([0; 32]),
                                state: OutboundHTLCState::Committed,
                                source: HTLCSource::dummy(),
+                               skimmed_fee_msat: None,
                        };
                        out.payment_hash.0 = Sha256::hash(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).into_inner();
                        out
@@ -8342,6 +8479,8 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 2185;
                chan.context.holder_dust_limit_satoshis = 2001;
+               let cached_channel_type = chan.context.channel_type;
+               chan.context.channel_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
 
                test_commitment_with_anchors!("3044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c0",
                                 "3045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd5",
@@ -8362,6 +8501,7 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 3702;
                chan.context.holder_dust_limit_satoshis = 546;
+               chan.context.channel_type = cached_channel_type.clone();
 
                test_commitment!("304502210092a587aeb777f869e7ff0d7898ea619ee26a3dacd1f3672b945eea600be431100220077ee9eae3528d15251f2a52b607b189820e57a6ccfac8d1af502b132ee40169",
                                 "3045022100e5efb73c32d32da2d79702299b6317de6fb24a60476e3855926d78484dd1b3c802203557cb66a42c944ef06e00bcc4da35a5bcb2f185aab0f8e403e519e1d66aaf75",
@@ -8396,6 +8536,7 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 3687;
                chan.context.holder_dust_limit_satoshis = 3001;
+               chan.context.channel_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
 
                test_commitment_with_anchors!("3045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c228377",
                                 "3045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d",
@@ -8411,6 +8552,7 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 4914;
                chan.context.holder_dust_limit_satoshis = 546;
+               chan.context.channel_type = cached_channel_type.clone();
 
                test_commitment!("3045022100b4b16d5f8cc9fc4c1aff48831e832a0d8990e133978a66e302c133550954a44d022073573ce127e2200d316f6b612803a5c0c97b8d20e1e44dbe2ac0dd2fb8c95244",
                                 "3045022100d72638bc6308b88bb6d45861aae83e5b9ff6e10986546e13bce769c70036e2620220320be7c6d66d22f30b9fcd52af66531505b1310ca3b848c19285b38d8a1a8c19",
@@ -8435,6 +8577,7 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 4894;
                chan.context.holder_dust_limit_satoshis = 4001;
+               chan.context.channel_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
 
                test_commitment_with_anchors!("3045022100e784a66b1588575801e237d35e510fd92a81ae3a4a2a1b90c031ad803d07b3f3022021bc5f16501f167607d63b681442da193eb0a76b4b7fd25c2ed4f8b28fd35b95",
                                 "30450221009f16ac85d232e4eddb3fcd750a68ebf0b58e3356eaada45d3513ede7e817bf4c02207c2b043b4e5f971261975406cb955219fa56bffe5d834a833694b5abc1ce4cfd",
@@ -8444,6 +8587,7 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 9651180;
                chan.context.holder_dust_limit_satoshis = 546;
+               chan.context.channel_type = cached_channel_type.clone();
 
                test_commitment!("304402200a8544eba1d216f5c5e530597665fa9bec56943c0f66d98fc3d028df52d84f7002201e45fa5c6bc3a506cc2553e7d1c0043a9811313fc39c954692c0d47cfce2bbd3",
                                 "3045022100e11b638c05c650c2f63a421d36ef8756c5ce82f2184278643520311cdf50aa200220259565fb9c8e4a87ccaf17f27a3b9ca4f20625754a0920d9c6c239d8156a11de",
@@ -8461,6 +8605,7 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 6216010;
                chan.context.holder_dust_limit_satoshis = 4001;
+               chan.context.channel_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
 
                test_commitment_with_anchors!("30450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf",
                                 "30450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1",
@@ -8470,6 +8615,7 @@ mod tests {
                chan.context.value_to_self_msat = 6993000000; // 7000000000 - 7000000
                chan.context.feerate_per_kw = 9651936;
                chan.context.holder_dust_limit_satoshis = 546;
+               chan.context.channel_type = cached_channel_type;
 
                test_commitment!("304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a2",
                                 "304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379",
@@ -8499,6 +8645,7 @@ mod tests {
                                payment_hash: PaymentHash([0; 32]),
                                state: OutboundHTLCState::Committed,
                                source: HTLCSource::dummy(),
+                               skimmed_fee_msat: None,
                        };
                        out.payment_hash.0 = Sha256::hash(&hex::decode("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).into_inner();
                        out
@@ -8511,6 +8658,7 @@ mod tests {
                                payment_hash: PaymentHash([0; 32]),
                                state: OutboundHTLCState::Committed,
                                source: HTLCSource::dummy(),
+                               skimmed_fee_msat: None,
                        };
                        out.payment_hash.0 = Sha256::hash(&hex::decode("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).into_inner();
                        out
@@ -8534,6 +8682,7 @@ mod tests {
                                  "020000000001014bdccf28653066a2c554cafeffdfe1e678e64a69b056684deb0c4fba909423ec02000000000000000001e1120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220471c9f3ad92e49b13b7b8059f43ecf8f7887b0dccbb9fdb54bfe23d62a8ae332022024bd22fae0740e86a44228c35330da9526fd7306dffb2b9dc362d5e78abef7cc0147304402207157f452f2506d73c315192311893800cfb3cc235cc1185b1cfcc136b55230db022014be242dbc6c5da141fec4034e7f387f74d6ff1899453d72ba957467540e1ecb01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6868fa010000" }
                } );
 
+               chan.context.channel_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
                test_commitment_with_anchors!("3044022027b38dfb654c34032ffb70bb43022981652fce923cbbe3cbe7394e2ade8b34230220584195b78da6e25c2e8da6b4308d9db25b65b64975db9266163ef592abb7c725",
                                 "3045022100b4014970d9d7962853f3f85196144671d7d5d87426250f0a5fdaf9a55292e92502205360910c9abb397467e19dbd63d081deb4a3240903114c98cec0a23591b79b76",
                                 "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5e881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aad9c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100b4014970d9d7962853f3f85196144671d7d5d87426250f0a5fdaf9a55292e92502205360910c9abb397467e19dbd63d081deb4a3240903114c98cec0a23591b79b7601473044022027b38dfb654c34032ffb70bb43022981652fce923cbbe3cbe7394e2ade8b34230220584195b78da6e25c2e8da6b4308d9db25b65b64975db9266163ef592abb7c72501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {
@@ -8630,7 +8779,6 @@ mod tests {
                assert!(res.is_ok());
        }
 
-       #[cfg(anchors)]
        #[test]
        fn test_supports_anchors_zero_htlc_tx_fee() {
                // Tests that if both sides support and negotiate `anchors_zero_fee_htlc_tx`, it is the
@@ -8676,7 +8824,6 @@ mod tests {
                assert_eq!(channel_b.context.channel_type, expected_channel_type);
        }
 
-       #[cfg(anchors)]
        #[test]
        fn test_rejects_implicit_simple_anchors() {
                // Tests that if `option_anchors` is being negotiated implicitly through the intersection of
@@ -8717,7 +8864,6 @@ mod tests {
                assert!(channel_b.is_err());
        }
 
-       #[cfg(anchors)]
        #[test]
        fn test_rejects_simple_anchors_channel_type() {
                // Tests that if `option_anchors` is being negotiated through the `channel_type` feature,
@@ -8739,8 +8885,8 @@ mod tests {
                let simple_anchors_raw_features = static_remote_key_required | simple_anchors_required;
                let simple_anchors_init = InitFeatures::from_le_bytes(simple_anchors_raw_features.to_le_bytes().to_vec());
                let simple_anchors_channel_type = ChannelTypeFeatures::from_le_bytes(simple_anchors_raw_features.to_le_bytes().to_vec());
-               assert!(simple_anchors_init.requires_unknown_bits());
-               assert!(simple_anchors_channel_type.requires_unknown_bits());
+               assert!(!simple_anchors_init.requires_unknown_bits());
+               assert!(!simple_anchors_channel_type.requires_unknown_bits());
 
                // First, we'll try to open a channel between A and B where A requests a channel type for
                // the original `option_anchors` feature (non zero fee htlc tx). This should be rejected by
index 164e4c2242d772c57523cac9596e68bda3269d1a..b22c3716ccbbdb795981d94e270424e089e25392 100644 (file)
@@ -40,17 +40,17 @@ use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, Messa
 // Since this struct is returned in `list_channels` methods, expose it here in case users want to
 // construct one themselves.
 use crate::ln::{inbound_payment, PaymentHash, PaymentPreimage, PaymentSecret};
-use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
+use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
 use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 #[cfg(any(feature = "_test_utils", test))]
-use crate::ln::features::InvoiceFeatures;
+use crate::ln::features::Bolt11InvoiceFeatures;
 use crate::routing::gossip::NetworkGraph;
-use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteHop, RouteParameters, Router};
+use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteParameters, Router};
 use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
 use crate::ln::msgs;
 use crate::ln::onion_utils;
 use crate::ln::onion_utils::HTLCFailReason;
-use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT};
+use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
 #[cfg(test)]
 use crate::ln::outbound_payment;
 use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment};
@@ -131,6 +131,9 @@ pub(super) struct PendingHTLCInfo {
        /// may overshoot this in either case)
        pub(super) outgoing_amt_msat: u64,
        pub(super) outgoing_cltv_value: u32,
+       /// The fee being skimmed off the top of this HTLC. If this is a forward, it'll be the fee we are
+       /// skimming. If we're receiving this HTLC, it's the fee that our counterparty skimmed.
+       pub(super) skimmed_fee_msat: Option<u64>,
 }
 
 #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
@@ -210,6 +213,8 @@ struct ClaimableHTLC {
        total_value_received: Option<u64>,
        /// The sender intended sum total of all MPP parts specified in the onion
        total_msat: u64,
+       /// The extra fee our counterparty skimmed off the top of this HTLC.
+       counterparty_skimmed_fee_msat: Option<u64>,
 }
 
 /// A payment identifier used to uniquely identify a payment to LDK.
@@ -312,7 +317,7 @@ impl core::hash::Hash for HTLCSource {
        }
 }
 impl HTLCSource {
-       #[cfg(not(feature = "grind_signatures"))]
+       #[cfg(all(feature = "_test_vectors", not(feature = "grind_signatures")))]
        #[cfg(test)]
        pub fn dummy() -> Self {
                HTLCSource::OutboundRoute {
@@ -502,19 +507,19 @@ struct ClaimablePayments {
 /// running normally, and specifically must be processed before any other non-background
 /// [`ChannelMonitorUpdate`]s are applied.
 enum BackgroundEvent {
-       /// Handle a ChannelMonitorUpdate which closes the channel. This is only separated from
-       /// [`Self::MonitorUpdateRegeneratedOnStartup`] as the maybe-non-closing variant needs a public
-       /// key to handle channel resumption, whereas if the channel has been force-closed we do not
-       /// need the counterparty node_id.
+       /// Handle a ChannelMonitorUpdate which closes the channel or for an already-closed channel.
+       /// This is only separated from [`Self::MonitorUpdateRegeneratedOnStartup`] as the
+       /// maybe-non-closing variant needs a public key to handle channel resumption, whereas if the
+       /// channel has been force-closed we do not need the counterparty node_id.
        ///
        /// Note that any such events are lost on shutdown, so in general they must be updates which
        /// are regenerated on startup.
-       ClosingMonitorUpdateRegeneratedOnStartup((OutPoint, ChannelMonitorUpdate)),
+       ClosedMonitorUpdateRegeneratedOnStartup((OutPoint, ChannelMonitorUpdate)),
        /// Handle a ChannelMonitorUpdate which may or may not close the channel and may unblock the
        /// channel to continue normal operation.
        ///
        /// In general this should be used rather than
-       /// [`Self::ClosingMonitorUpdateRegeneratedOnStartup`], however in cases where the
+       /// [`Self::ClosedMonitorUpdateRegeneratedOnStartup`], however in cases where the
        /// `counterparty_node_id` is not available as the channel has closed from a [`ChannelMonitor`]
        /// error the other variant is acceptable.
        ///
@@ -525,6 +530,13 @@ enum BackgroundEvent {
                funding_txo: OutPoint,
                update: ChannelMonitorUpdate
        },
+       /// Some [`ChannelMonitorUpdate`] (s) completed before we were serialized but we still have
+       /// them marked pending, thus we need to run any [`MonitorUpdateCompletionAction`] (s) pending
+       /// on a channel.
+       MonitorUpdatesComplete {
+               counterparty_node_id: PublicKey,
+               channel_id: [u8; 32],
+       },
 }
 
 #[derive(Debug)]
@@ -628,6 +640,13 @@ pub(super) struct PeerState<Signer: ChannelSigner> {
        /// Messages to send to the peer - pushed to in the same lock that they are generated in (except
        /// for broadcast messages, where ordering isn't as strict).
        pub(super) pending_msg_events: Vec<MessageSendEvent>,
+       /// Map from Channel IDs to pending [`ChannelMonitorUpdate`]s which have been passed to the
+       /// user but which have not yet completed.
+       ///
+       /// Note that the channel may no longer exist. For example if the channel was closed but we
+       /// later needed to claim an HTLC which is pending on-chain, we may generate a monitor update
+       /// for a missing channel.
+       in_flight_monitor_updates: BTreeMap<OutPoint, Vec<ChannelMonitorUpdate>>,
        /// Map from a specific channel to some action(s) that should be taken when all pending
        /// [`ChannelMonitorUpdate`]s for the channel complete updating.
        ///
@@ -663,9 +682,10 @@ impl <Signer: ChannelSigner> PeerState<Signer> {
                        return false
                }
                self.channel_by_id.is_empty() && self.monitor_update_blocked_actions.is_empty()
+                       && self.in_flight_monitor_updates.is_empty()
        }
 
-       // Returns a count of all channels we have with this peer, including pending channels.
+       // Returns a count of all channels we have with this peer, including unfunded channels.
        fn total_channel_count(&self) -> usize {
                self.channel_by_id.len() +
                        self.outbound_v1_channel_by_id.len() +
@@ -739,7 +759,23 @@ pub type SimpleArcChannelManager<M, T, F, L> = ChannelManager<
 /// of [`KeysManager`] and [`DefaultRouter`].
 ///
 /// This is not exported to bindings users as Arcs don't make sense in bindings
-pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> = ChannelManager<&'a M, &'b T, &'c KeysManager, &'c KeysManager, &'c KeysManager, &'d F, &'e DefaultRouter<&'f NetworkGraph<&'g L>, &'g L, &'h Mutex<ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, ProbabilisticScoringFeeParameters, ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, &'g L>;
+pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> =
+       ChannelManager<
+               &'a M,
+               &'b T,
+               &'c KeysManager,
+               &'c KeysManager,
+               &'c KeysManager,
+               &'d F,
+               &'e DefaultRouter<
+                       &'f NetworkGraph<&'g L>,
+                       &'g L,
+                       &'h Mutex<ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>,
+                       ProbabilisticScoringFeeParameters,
+                       ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>
+               >,
+               &'g L
+       >;
 
 macro_rules! define_test_pub_trait { ($vis: vis) => {
 /// A trivial trait which describes any [`ChannelManager`] used in testing.
@@ -1085,7 +1121,6 @@ where
        /// Notifier the lock contains sends out a notification when the lock is released.
        total_consistency_lock: RwLock<()>,
 
-       #[cfg(debug_assertions)]
        background_events_processed_since_startup: AtomicBool,
 
        persistence_notifier: Notifier,
@@ -1451,6 +1486,9 @@ pub struct ChannelDetails {
        ///
        /// [`confirmations_required`]: ChannelDetails::confirmations_required
        pub is_channel_ready: bool,
+       /// The stage of the channel's shutdown.
+       /// `None` for `ChannelDetails` serialized on LDK versions prior to 0.0.116.
+       pub channel_shutdown_state: Option<ChannelShutdownState>,
        /// True if the channel is (a) confirmed and channel_ready messages have been exchanged, (b)
        /// the peer is connected, and (c) the channel is not currently negotiating a shutdown.
        ///
@@ -1490,10 +1528,13 @@ impl ChannelDetails {
                self.short_channel_id.or(self.outbound_scid_alias)
        }
 
-       fn from_channel_context<Signer: WriteableEcdsaChannelSigner>(context: &ChannelContext<Signer>,
-               best_block_height: u32, latest_features: InitFeatures) -> Self {
-
-               let balance = context.get_available_balances();
+       fn from_channel_context<Signer: WriteableEcdsaChannelSigner, F: Deref>(
+               context: &ChannelContext<Signer>, best_block_height: u32, latest_features: InitFeatures,
+               fee_estimator: &LowerBoundedFeeEstimator<F>
+       ) -> Self
+       where F::Target: FeeEstimator
+       {
+               let balance = context.get_available_balances(fee_estimator);
                let (to_remote_reserve_satoshis, to_self_reserve_satoshis) =
                        context.get_holder_counterparty_selected_channel_reserve_satoshis();
                ChannelDetails {
@@ -1538,10 +1579,33 @@ impl ChannelDetails {
                        inbound_htlc_minimum_msat: Some(context.get_holder_htlc_minimum_msat()),
                        inbound_htlc_maximum_msat: context.get_holder_htlc_maximum_msat(),
                        config: Some(context.config()),
+                       channel_shutdown_state: Some(context.shutdown_state()),
                }
        }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+/// Further information on the details of the channel shutdown.
+/// Upon channels being forced closed (i.e. commitment transaction confirmation detected
+/// by `ChainMonitor`), ChannelShutdownState will be set to `ShutdownComplete` or
+/// the channel will be removed shortly.
+/// Also note, that in normal operation, peers could disconnect at any of these states
+/// and require peer re-connection before making progress onto other states
+pub enum ChannelShutdownState {
+       /// Channel has not sent or received a shutdown message.
+       NotShuttingDown,
+       /// Local node has sent a shutdown message for this channel.
+       ShutdownInitiated,
+       /// Shutdown message exchanges have concluded and the channels are in the midst of
+       /// resolving all existing open HTLCs before closing can continue.
+       ResolvingHTLCs,
+       /// All HTLCs have been resolved, nodes are currently negotiating channel close onchain fee rates.
+       NegotiatingClosingFee,
+       /// We've successfully negotiated a closing_signed dance. At this point `ChannelManager` is about
+       /// to drop the channel.
+       ShutdownComplete,
+}
+
 /// Used by [`ChannelManager::list_recent_payments`] to express the status of recent payments.
 /// These include payments that have yet to find a successful path, or have unresolved HTLCs.
 #[derive(Debug, PartialEq)]
@@ -1685,12 +1749,12 @@ macro_rules! convert_chan_err {
                        },
                }
        };
-       ($self: ident, $err: expr, $channel_context: expr, $channel_id: expr, PREFUNDED) => {
+       ($self: ident, $err: expr, $channel_context: expr, $channel_id: expr, UNFUNDED) => {
                match $err {
-                       // We should only ever have `ChannelError::Close` when prefunded channels error.
+                       // We should only ever have `ChannelError::Close` when unfunded channels error.
                        // In any case, just close the channel.
                        ChannelError::Warn(msg) | ChannelError::Ignore(msg) | ChannelError::Close(msg) => {
-                               log_error!($self.logger, "Closing prefunded channel {} due to an error: {}", log_bytes!($channel_id[..]), msg);
+                               log_error!($self.logger, "Closing unfunded channel {} due to an error: {}", log_bytes!($channel_id[..]), msg);
                                update_maps_on_chan_removal!($self, &$channel_context);
                                let shutdown_res = $channel_context.force_shutdown(false);
                                (true, MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, $channel_context.get_user_id(),
@@ -1720,7 +1784,7 @@ macro_rules! try_v1_outbound_chan_entry {
                match $res {
                        Ok(res) => res,
                        Err(e) => {
-                               let (drop, res) = convert_chan_err!($self, e, $entry.get_mut().context, $entry.key(), PREFUNDED);
+                               let (drop, res) = convert_chan_err!($self, e, $entry.get_mut().context, $entry.key(), UNFUNDED);
                                if drop {
                                        $entry.remove_entry();
                                }
@@ -1806,7 +1870,7 @@ macro_rules! emit_channel_ready_event {
 }
 
 macro_rules! handle_monitor_update_completion {
-       ($self: ident, $update_id: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr) => { {
+       ($self: ident, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr) => { {
                let mut updates = $chan.monitor_updating_restored(&$self.logger,
                        &$self.node_signer, $self.genesis_hash, &$self.default_configuration,
                        $self.best_block.read().unwrap().height());
@@ -1855,24 +1919,22 @@ macro_rules! handle_monitor_update_completion {
 }
 
 macro_rules! handle_new_monitor_update {
-       ($self: ident, $update_res: expr, $update_id: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr, MANUALLY_REMOVING, $remove: expr) => { {
+       ($self: ident, $update_res: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr, _internal, $remove: expr, $completed: expr) => { {
                // update_maps_on_chan_removal needs to be able to take id_to_peer, so make sure we can in
                // any case so that it won't deadlock.
                debug_assert_ne!($self.id_to_peer.held_by_thread(), LockHeldState::HeldByThread);
-               #[cfg(debug_assertions)] {
-                       debug_assert!($self.background_events_processed_since_startup.load(Ordering::Acquire));
-               }
+               debug_assert!($self.background_events_processed_since_startup.load(Ordering::Acquire));
                match $update_res {
                        ChannelMonitorUpdateStatus::InProgress => {
                                log_debug!($self.logger, "ChannelMonitor update for {} in flight, holding messages until the update completes.",
                                        log_bytes!($chan.context.channel_id()[..]));
-                               Ok(())
+                               Ok(false)
                        },
                        ChannelMonitorUpdateStatus::PermanentFailure => {
                                log_error!($self.logger, "Closing channel {} due to monitor update ChannelMonitorUpdateStatus::PermanentFailure",
                                        log_bytes!($chan.context.channel_id()[..]));
                                update_maps_on_chan_removal!($self, &$chan.context);
-                               let res: Result<(), _> = Err(MsgHandleErrInternal::from_finish_shutdown(
+                               let res = Err(MsgHandleErrInternal::from_finish_shutdown(
                                        "ChannelMonitor storage failure".to_owned(), $chan.context.channel_id(),
                                        $chan.context.get_user_id(), $chan.context.force_shutdown(false),
                                        $self.get_channel_update_for_broadcast(&$chan).ok()));
@@ -1880,16 +1942,42 @@ macro_rules! handle_new_monitor_update {
                                res
                        },
                        ChannelMonitorUpdateStatus::Completed => {
-                               $chan.complete_one_mon_update($update_id);
-                               if $chan.no_monitor_updates_pending() {
-                                       handle_monitor_update_completion!($self, $update_id, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan);
-                               }
-                               Ok(())
+                               $completed;
+                               Ok(true)
                        },
                }
        } };
-       ($self: ident, $update_res: expr, $update_id: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan_entry: expr) => {
-               handle_new_monitor_update!($self, $update_res, $update_id, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan_entry.get_mut(), MANUALLY_REMOVING, $chan_entry.remove_entry())
+       ($self: ident, $update_res: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr, MANUALLY_REMOVING_INITIAL_MONITOR, $remove: expr) => {
+               handle_new_monitor_update!($self, $update_res, $peer_state_lock, $peer_state,
+                       $per_peer_state_lock, $chan, _internal, $remove,
+                       handle_monitor_update_completion!($self, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan))
+       };
+       ($self: ident, $update_res: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan_entry: expr, INITIAL_MONITOR) => {
+               handle_new_monitor_update!($self, $update_res, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan_entry.get_mut(), MANUALLY_REMOVING_INITIAL_MONITOR, $chan_entry.remove_entry())
+       };
+       ($self: ident, $funding_txo: expr, $update: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr, MANUALLY_REMOVING, $remove: expr) => { {
+               let in_flight_updates = $peer_state.in_flight_monitor_updates.entry($funding_txo)
+                       .or_insert_with(Vec::new);
+               // During startup, we push monitor updates as background events through to here in
+               // order to replay updates that were in-flight when we shut down. Thus, we have to
+               // filter for uniqueness here.
+               let idx = in_flight_updates.iter().position(|upd| upd == &$update)
+                       .unwrap_or_else(|| {
+                               in_flight_updates.push($update);
+                               in_flight_updates.len() - 1
+                       });
+               let update_res = $self.chain_monitor.update_channel($funding_txo, &in_flight_updates[idx]);
+               handle_new_monitor_update!($self, update_res, $peer_state_lock, $peer_state,
+                       $per_peer_state_lock, $chan, _internal, $remove,
+                       {
+                               let _ = in_flight_updates.remove(idx);
+                               if in_flight_updates.is_empty() && $chan.blocked_monitor_updates_pending() == 0 {
+                                       handle_monitor_update_completion!($self, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan);
+                               }
+                       })
+       } };
+       ($self: ident, $funding_txo: expr, $update: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan_entry: expr) => {
+               handle_new_monitor_update!($self, $funding_txo, $update, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan_entry.get_mut(), MANUALLY_REMOVING, $chan_entry.remove_entry())
        }
 }
 
@@ -1939,6 +2027,8 @@ macro_rules! process_events_body {
                                let mut pending_events = $self.pending_events.lock().unwrap();
                                pending_events.drain(..num_events);
                                processed_all_events = pending_events.is_empty();
+                               // Note that `push_pending_forwards_ev` relies on `pending_events_processor` being
+                               // updated here with the `pending_events` lock acquired.
                                $self.pending_events_processor.store(false, Ordering::Release);
                        }
 
@@ -1968,6 +2058,8 @@ where
 {
        /// Constructs a new `ChannelManager` to hold several channels and route between them.
        ///
+       /// The current time or latest block header time can be provided as the `current_timestamp`.
+       ///
        /// This is the main "logic hub" for all channel-related actions, and implements
        /// [`ChannelMessageHandler`].
        ///
@@ -1981,7 +2073,11 @@ where
        /// [`block_connected`]: chain::Listen::block_connected
        /// [`block_disconnected`]: chain::Listen::block_disconnected
        /// [`params.best_block.block_hash`]: chain::BestBlock::block_hash
-       pub fn new(fee_est: F, chain_monitor: M, tx_broadcaster: T, router: R, logger: L, entropy_source: ES, node_signer: NS, signer_provider: SP, config: UserConfig, params: ChainParameters) -> Self {
+       pub fn new(
+               fee_est: F, chain_monitor: M, tx_broadcaster: T, router: R, logger: L, entropy_source: ES,
+               node_signer: NS, signer_provider: SP, config: UserConfig, params: ChainParameters,
+               current_timestamp: u32,
+       ) -> Self {
                let mut secp_ctx = Secp256k1::new();
                secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
                let inbound_pmt_key_material = node_signer.get_inbound_payment_key_material();
@@ -2013,7 +2109,7 @@ where
 
                        probing_cookie_secret: entropy_source.get_secure_random_bytes(),
 
-                       highest_seen_timestamp: AtomicUsize::new(0),
+                       highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
 
                        per_peer_state: FairRwLock::new(HashMap::new()),
 
@@ -2021,7 +2117,6 @@ where
                        pending_events_processor: AtomicBool::new(false),
                        pending_background_events: Mutex::new(Vec::new()),
                        total_consistency_lock: RwLock::new(()),
-                       #[cfg(debug_assertions)]
                        background_events_processed_since_startup: AtomicBool::new(false),
                        persistence_notifier: Notifier::new(),
 
@@ -2151,9 +2246,10 @@ where
                        for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
                                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                                let peer_state = &mut *peer_state_lock;
+                               // Only `Channels` in the channel_by_id map can be considered funded.
                                for (_channel_id, channel) in peer_state.channel_by_id.iter().filter(f) {
                                        let details = ChannelDetails::from_channel_context(&channel.context, best_block_height,
-                                               peer_state.latest_features.clone());
+                                               peer_state.latest_features.clone(), &self.fee_estimator);
                                        res.push(details);
                                }
                        }
@@ -2179,17 +2275,17 @@ where
                                let peer_state = &mut *peer_state_lock;
                                for (_channel_id, channel) in peer_state.channel_by_id.iter() {
                                        let details = ChannelDetails::from_channel_context(&channel.context, best_block_height,
-                                               peer_state.latest_features.clone());
+                                               peer_state.latest_features.clone(), &self.fee_estimator);
                                        res.push(details);
                                }
                                for (_channel_id, channel) in peer_state.inbound_v1_channel_by_id.iter() {
                                        let details = ChannelDetails::from_channel_context(&channel.context, best_block_height,
-                                               peer_state.latest_features.clone());
+                                               peer_state.latest_features.clone(), &self.fee_estimator);
                                        res.push(details);
                                }
                                for (_channel_id, channel) in peer_state.outbound_v1_channel_by_id.iter() {
                                        let details = ChannelDetails::from_channel_context(&channel.context, best_block_height,
-                                               peer_state.latest_features.clone());
+                                               peer_state.latest_features.clone(), &self.fee_estimator);
                                        res.push(details);
                                }
                        }
@@ -2219,10 +2315,15 @@ where
                        let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                        let peer_state = &mut *peer_state_lock;
                        let features = &peer_state.latest_features;
+                       let chan_context_to_details = |context| {
+                               ChannelDetails::from_channel_context(context, best_block_height, features.clone(), &self.fee_estimator)
+                       };
                        return peer_state.channel_by_id
                                .iter()
-                               .map(|(_, channel)|
-                                       ChannelDetails::from_channel_context(&channel.context, best_block_height, features.clone()))
+                               .map(|(_, channel)| &channel.context)
+                               .chain(peer_state.outbound_v1_channel_by_id.iter().map(|(_, channel)| &channel.context))
+                               .chain(peer_state.inbound_v1_channel_by_id.iter().map(|(_, channel)| &channel.context))
+                               .map(chan_context_to_details)
                                .collect();
                }
                vec![]
@@ -2279,49 +2380,58 @@ where
 
                let mut failed_htlcs: Vec<(HTLCSource, PaymentHash)>;
                let result: Result<(), _> = loop {
-                       let per_peer_state = self.per_peer_state.read().unwrap();
+                       {
+                               let per_peer_state = self.per_peer_state.read().unwrap();
 
-                       let peer_state_mutex = per_peer_state.get(counterparty_node_id)
-                               .ok_or_else(|| APIError::ChannelUnavailable { err: format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id) })?;
+                               let peer_state_mutex = per_peer_state.get(counterparty_node_id)
+                                       .ok_or_else(|| APIError::ChannelUnavailable { err: format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id) })?;
 
-                       let mut peer_state_lock = peer_state_mutex.lock().unwrap();
-                       let peer_state = &mut *peer_state_lock;
-                       match peer_state.channel_by_id.entry(channel_id.clone()) {
-                               hash_map::Entry::Occupied(mut chan_entry) => {
-                                       let funding_txo_opt = chan_entry.get().context.get_funding_txo();
-                                       let their_features = &peer_state.latest_features;
-                                       let (shutdown_msg, mut monitor_update_opt, htlcs) = chan_entry.get_mut()
-                                               .get_shutdown(&self.signer_provider, their_features, target_feerate_sats_per_1000_weight, override_shutdown_script)?;
-                                       failed_htlcs = htlcs;
+                               let mut peer_state_lock = peer_state_mutex.lock().unwrap();
+                               let peer_state = &mut *peer_state_lock;
 
-                                       // We can send the `shutdown` message before updating the `ChannelMonitor`
-                                       // here as we don't need the monitor update to complete until we send a
-                                       // `shutdown_signed`, which we'll delay if we're pending a monitor update.
-                                       peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
-                                               node_id: *counterparty_node_id,
-                                               msg: shutdown_msg,
-                                       });
+                               match peer_state.channel_by_id.entry(channel_id.clone()) {
+                                       hash_map::Entry::Occupied(mut chan_entry) => {
+                                               let funding_txo_opt = chan_entry.get().context.get_funding_txo();
+                                               let their_features = &peer_state.latest_features;
+                                               let (shutdown_msg, mut monitor_update_opt, htlcs) = chan_entry.get_mut()
+                                                       .get_shutdown(&self.signer_provider, their_features, target_feerate_sats_per_1000_weight, override_shutdown_script)?;
+                                               failed_htlcs = htlcs;
 
-                                       // Update the monitor with the shutdown script if necessary.
-                                       if let Some(monitor_update) = monitor_update_opt.take() {
-                                               let update_id = monitor_update.update_id;
-                                               let update_res = self.chain_monitor.update_channel(funding_txo_opt.unwrap(), monitor_update);
-                                               break handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, peer_state, per_peer_state, chan_entry);
-                                       }
+                                               // We can send the `shutdown` message before updating the `ChannelMonitor`
+                                               // here as we don't need the monitor update to complete until we send a
+                                               // `shutdown_signed`, which we'll delay if we're pending a monitor update.
+                                               peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
+                                                       node_id: *counterparty_node_id,
+                                                       msg: shutdown_msg,
+                                               });
 
-                                       if chan_entry.get().is_shutdown() {
-                                               let channel = remove_channel!(self, chan_entry);
-                                               if let Ok(channel_update) = self.get_channel_update_for_broadcast(&channel) {
-                                                       peer_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
-                                                               msg: channel_update
-                                                       });
+                                               // Update the monitor with the shutdown script if necessary.
+                                               if let Some(monitor_update) = monitor_update_opt.take() {
+                                                       break handle_new_monitor_update!(self, funding_txo_opt.unwrap(), monitor_update,
+                                                               peer_state_lock, peer_state, per_peer_state, chan_entry).map(|_| ());
                                                }
-                                               self.issue_channel_close_events(&channel.context, ClosureReason::HolderForceClosed);
-                                       }
-                                       break Ok(());
-                               },
-                               hash_map::Entry::Vacant(_) => return Err(APIError::ChannelUnavailable{err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*channel_id), counterparty_node_id) })
+
+                                               if chan_entry.get().is_shutdown() {
+                                                       let channel = remove_channel!(self, chan_entry);
+                                                       if let Ok(channel_update) = self.get_channel_update_for_broadcast(&channel) {
+                                                               peer_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                                                                       msg: channel_update
+                                                               });
+                                                       }
+                                                       self.issue_channel_close_events(&channel.context, ClosureReason::HolderForceClosed);
+                                               }
+                                               break Ok(());
+                                       },
+                                       hash_map::Entry::Vacant(_) => (),
+                               }
                        }
+                       // If we reach this point, it means that the channel_id either refers to an unfunded channel or
+                       // it does not exist for this peer. Either way, we can attempt to force-close it.
+                       //
+                       // An appropriate error will be returned for non-existence of the channel if that's the case.
+                       return self.force_close_channel_with_peer(&channel_id, counterparty_node_id, None, false).map(|_| ())
+                       // TODO(dunxen): This is still not ideal as we're doing some extra lookups.
+                       // Fix this with https://github.com/lightningdevkit/rust-lightning/issues/2422
                };
 
                for htlc_source in failed_htlcs.drain(..) {
@@ -2440,14 +2550,14 @@ where
                                self.issue_channel_close_events(&chan.get().context, closure_reason);
                                let mut chan = remove_channel!(self, chan);
                                self.finish_force_close_channel(chan.context.force_shutdown(false));
-                               // Prefunded channel has no update
+                               // Unfunded channel has no update
                                (None, chan.context.get_counterparty_node_id())
                        } else if let hash_map::Entry::Occupied(chan) = peer_state.inbound_v1_channel_by_id.entry(channel_id.clone()) {
                                log_error!(self.logger, "Force-closing channel {}", log_bytes!(channel_id[..]));
                                self.issue_channel_close_events(&chan.get().context, closure_reason);
                                let mut chan = remove_channel!(self, chan);
                                self.finish_force_close_channel(chan.context.force_shutdown(false));
-                               // Prefunded channel has no update
+                               // Unfunded channel has no update
                                (None, chan.context.get_counterparty_node_id())
                        } else {
                                return Err(APIError::ChannelUnavailable{ err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*channel_id), peer_node_id) });
@@ -2521,9 +2631,11 @@ where
                }
        }
 
-       fn construct_recv_pending_htlc_info(&self, hop_data: msgs::OnionHopData, shared_secret: [u8; 32],
-               payment_hash: PaymentHash, amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>) -> Result<PendingHTLCInfo, ReceiveError>
-       {
+       fn construct_recv_pending_htlc_info(
+               &self, hop_data: msgs::OnionHopData, shared_secret: [u8; 32], payment_hash: PaymentHash,
+               amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
+               counterparty_skimmed_fee_msat: Option<u64>,
+       ) -> Result<PendingHTLCInfo, ReceiveError> {
                // final_incorrect_cltv_expiry
                if hop_data.outgoing_cltv_value > cltv_expiry {
                        return Err(ReceiveError {
@@ -2549,7 +2661,10 @@ where
                                msg: "The final CLTV expiry is too soon to handle",
                        });
                }
-               if hop_data.amt_to_forward > amt_msat {
+               if (!allow_underpay && hop_data.amt_to_forward > amt_msat) ||
+                       (allow_underpay && hop_data.amt_to_forward >
+                        amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
+               {
                        return Err(ReceiveError {
                                err_code: 19,
                                err_data: amt_msat.to_be_bytes().to_vec(),
@@ -2616,15 +2731,18 @@ where
                        incoming_amt_msat: Some(amt_msat),
                        outgoing_amt_msat: hop_data.amt_to_forward,
                        outgoing_cltv_value: hop_data.outgoing_cltv_value,
+                       skimmed_fee_msat: counterparty_skimmed_fee_msat,
                })
        }
 
-       fn decode_update_add_htlc_onion(&self, msg: &msgs::UpdateAddHTLC) -> PendingHTLCStatus {
+       fn decode_update_add_htlc_onion(
+               &self, msg: &msgs::UpdateAddHTLC
+       ) -> Result<(onion_utils::Hop, [u8; 32], Option<Result<PublicKey, secp256k1::Error>>), HTLCFailureMsg> {
                macro_rules! return_malformed_err {
                        ($msg: expr, $err_code: expr) => {
                                {
                                        log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
-                                       return PendingHTLCStatus::Fail(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
+                                       return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
                                                channel_id: msg.channel_id,
                                                htlc_id: msg.htlc_id,
                                                sha256_of_onion: Sha256::hash(&msg.onion_routing_packet.hop_data).into_inner(),
@@ -2655,7 +2773,7 @@ where
                        ($msg: expr, $err_code: expr, $data: expr) => {
                                {
                                        log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
-                                       return PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
+                                       return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
                                                channel_id: msg.channel_id,
                                                htlc_id: msg.htlc_id,
                                                reason: HTLCFailReason::reason($err_code, $data.to_vec())
@@ -2674,11 +2792,186 @@ where
                                return_err!(err_msg, err_code, &[0; 0]);
                        },
                };
+               let (outgoing_scid, outgoing_amt_msat, outgoing_cltv_value, next_packet_pk_opt) = match next_hop {
+                       onion_utils::Hop::Forward {
+                               next_hop_data: msgs::OnionHopData {
+                                       format: msgs::OnionHopDataFormat::NonFinalNode { short_channel_id }, amt_to_forward,
+                                       outgoing_cltv_value,
+                               }, ..
+                       } => {
+                               let next_pk = onion_utils::next_hop_packet_pubkey(&self.secp_ctx,
+                                       msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
+                               (short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_pk))
+                       },
+                       // We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
+                       // inbound channel's state.
+                       onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
+                       onion_utils::Hop::Forward {
+                               next_hop_data: msgs::OnionHopData { format: msgs::OnionHopDataFormat::FinalNode { .. }, .. }, ..
+                       } => {
+                               return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0; 0]);
+                       }
+               };
 
-               let pending_forward_info = match next_hop {
+               // Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
+               // can't hold the outbound peer state lock at the same time as the inbound peer state lock.
+               if let Some((err, mut code, chan_update)) = loop {
+                       let id_option = self.short_to_chan_info.read().unwrap().get(&outgoing_scid).cloned();
+                       let forwarding_chan_info_opt = match id_option {
+                               None => { // unknown_next_peer
+                                       // Note that this is likely a timing oracle for detecting whether an scid is a
+                                       // phantom or an intercept.
+                                       if (self.default_configuration.accept_intercept_htlcs &&
+                                               fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, outgoing_scid, &self.genesis_hash)) ||
+                                               fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, outgoing_scid, &self.genesis_hash)
+                                       {
+                                               None
+                                       } else {
+                                               break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
+                                       }
+                               },
+                               Some((cp_id, id)) => Some((cp_id.clone(), id.clone())),
+                       };
+                       let chan_update_opt = if let Some((counterparty_node_id, forwarding_id)) = forwarding_chan_info_opt {
+                               let per_peer_state = self.per_peer_state.read().unwrap();
+                               let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
+                               if peer_state_mutex_opt.is_none() {
+                                       break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
+                               }
+                               let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
+                               let peer_state = &mut *peer_state_lock;
+                               let chan = match peer_state.channel_by_id.get_mut(&forwarding_id) {
+                                       None => {
+                                               // Channel was removed. The short_to_chan_info and channel_by_id maps
+                                               // have no consistency guarantees.
+                                               break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
+                                       },
+                                       Some(chan) => chan
+                               };
+                               if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
+                                       // Note that the behavior here should be identical to the above block - we
+                                       // should NOT reveal the existence or non-existence of a private channel if
+                                       // we don't allow forwards outbound over them.
+                                       break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
+                               }
+                               if chan.context.get_channel_type().supports_scid_privacy() && outgoing_scid != chan.context.outbound_scid_alias() {
+                                       // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
+                                       // "refuse to forward unless the SCID alias was used", so we pretend
+                                       // we don't have the channel here.
+                                       break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
+                               }
+                               let chan_update_opt = self.get_channel_update_for_onion(outgoing_scid, chan).ok();
+
+                               // Note that we could technically not return an error yet here and just hope
+                               // that the connection is reestablished or monitor updated by the time we get
+                               // around to doing the actual forward, but better to fail early if we can and
+                               // hopefully an attacker trying to path-trace payments cannot make this occur
+                               // on a small/per-node/per-channel scale.
+                               if !chan.context.is_live() { // channel_disabled
+                                       // If the channel_update we're going to return is disabled (i.e. the
+                                       // peer has been disabled for some time), return `channel_disabled`,
+                                       // otherwise return `temporary_channel_failure`.
+                                       if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
+                                               break Some(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
+                                       } else {
+                                               break Some(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
+                                       }
+                               }
+                               if outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
+                                       break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
+                               }
+                               if let Err((err, code)) = chan.htlc_satisfies_config(&msg, outgoing_amt_msat, outgoing_cltv_value) {
+                                       break Some((err, code, chan_update_opt));
+                               }
+                               chan_update_opt
+                       } else {
+                               if (msg.cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
+                                       // We really should set `incorrect_cltv_expiry` here but as we're not
+                                       // forwarding over a real channel we can't generate a channel_update
+                                       // for it. Instead we just return a generic temporary_node_failure.
+                                       break Some((
+                                                       "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
+                                                       0x2000 | 2, None,
+                                       ));
+                               }
+                               None
+                       };
+
+                       let cur_height = self.best_block.read().unwrap().height() + 1;
+                       // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
+                       // but we want to be robust wrt to counterparty packet sanitization (see
+                       // HTLC_FAIL_BACK_BUFFER rationale).
+                       if msg.cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
+                               break Some(("CLTV expiry is too close", 0x1000 | 14, chan_update_opt));
+                       }
+                       if msg.cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
+                               break Some(("CLTV expiry is too far in the future", 21, None));
+                       }
+                       // If the HTLC expires ~now, don't bother trying to forward it to our
+                       // counterparty. They should fail it anyway, but we don't want to bother with
+                       // the round-trips or risk them deciding they definitely want the HTLC and
+                       // force-closing to ensure they get it if we're offline.
+                       // We previously had a much more aggressive check here which tried to ensure
+                       // our counterparty receives an HTLC which has *our* risk threshold met on it,
+                       // but there is no need to do that, and since we're a bit conservative with our
+                       // risk threshold it just results in failing to forward payments.
+                       if (outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
+                               break Some(("Outgoing CLTV value is too soon", 0x1000 | 14, chan_update_opt));
+                       }
+
+                       break None;
+               }
+               {
+                       let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 2 + 8 + 2));
+                       if let Some(chan_update) = chan_update {
+                               if code == 0x1000 | 11 || code == 0x1000 | 12 {
+                                       msg.amount_msat.write(&mut res).expect("Writes cannot fail");
+                               }
+                               else if code == 0x1000 | 13 {
+                                       msg.cltv_expiry.write(&mut res).expect("Writes cannot fail");
+                               }
+                               else if code == 0x1000 | 20 {
+                                       // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
+                                       0u16.write(&mut res).expect("Writes cannot fail");
+                               }
+                               (chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
+                               msgs::ChannelUpdate::TYPE.write(&mut res).expect("Writes cannot fail");
+                               chan_update.write(&mut res).expect("Writes cannot fail");
+                       } else if code & 0x1000 == 0x1000 {
+                               // If we're trying to return an error that requires a `channel_update` but
+                               // we're forwarding to a phantom or intercept "channel" (i.e. cannot
+                               // generate an update), just use the generic "temporary_node_failure"
+                               // instead.
+                               code = 0x2000 | 2;
+                       }
+                       return_err!(err, code, &res.0[..]);
+               }
+               Ok((next_hop, shared_secret, next_packet_pk_opt))
+       }
+
+       fn construct_pending_htlc_status<'a>(
+               &self, msg: &msgs::UpdateAddHTLC, shared_secret: [u8; 32], decoded_hop: onion_utils::Hop,
+               allow_underpay: bool, next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
+       ) -> PendingHTLCStatus {
+               macro_rules! return_err {
+                       ($msg: expr, $err_code: expr, $data: expr) => {
+                               {
+                                       log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
+                                       return PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
+                                               channel_id: msg.channel_id,
+                                               htlc_id: msg.htlc_id,
+                                               reason: HTLCFailReason::reason($err_code, $data.to_vec())
+                                                       .get_encrypted_failure_packet(&shared_secret, &None),
+                                       }));
+                               }
+                       }
+               }
+               match decoded_hop {
                        onion_utils::Hop::Receive(next_hop_data) => {
                                // OUR PAYMENT!
-                               match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, None) {
+                               match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash,
+                                       msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat)
+                               {
                                        Ok(info) => {
                                                // Note that we could obviously respond immediately with an update_fulfill_htlc
                                                // message, however that would leak that we are the recipient of this payment, so
@@ -2690,10 +2983,10 @@ where
                                }
                        },
                        onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
-                               let new_pubkey = msg.onion_routing_packet.public_key.unwrap();
+                               debug_assert!(next_packet_pubkey_opt.is_some());
                                let outgoing_packet = msgs::OnionPacket {
                                        version: 0,
-                                       public_key: onion_utils::next_hop_packet_pubkey(&self.secp_ctx, new_pubkey, &shared_secret),
+                                       public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
                                        hop_data: new_packet_bytes,
                                        hmac: next_hop_hmac.clone(),
                                };
@@ -2715,150 +3008,10 @@ where
                                        incoming_amt_msat: Some(msg.amount_msat),
                                        outgoing_amt_msat: next_hop_data.amt_to_forward,
                                        outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
+                                       skimmed_fee_msat: None,
                                })
                        }
-               };
-
-               if let &PendingHTLCStatus::Forward(PendingHTLCInfo { ref routing, ref outgoing_amt_msat, ref outgoing_cltv_value, .. }) = &pending_forward_info {
-                       // If short_channel_id is 0 here, we'll reject the HTLC as there cannot be a channel
-                       // with a short_channel_id of 0. This is important as various things later assume
-                       // short_channel_id is non-0 in any ::Forward.
-                       if let &PendingHTLCRouting::Forward { ref short_channel_id, .. } = routing {
-                               if let Some((err, mut code, chan_update)) = loop {
-                                       let id_option = self.short_to_chan_info.read().unwrap().get(short_channel_id).cloned();
-                                       let forwarding_chan_info_opt = match id_option {
-                                               None => { // unknown_next_peer
-                                                       // Note that this is likely a timing oracle for detecting whether an scid is a
-                                                       // phantom or an intercept.
-                                                       if (self.default_configuration.accept_intercept_htlcs &&
-                                                          fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash)) ||
-                                                          fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash)
-                                                       {
-                                                               None
-                                                       } else {
-                                                               break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
-                                                       }
-                                               },
-                                               Some((cp_id, id)) => Some((cp_id.clone(), id.clone())),
-                                       };
-                                       let chan_update_opt = if let Some((counterparty_node_id, forwarding_id)) = forwarding_chan_info_opt {
-                                               let per_peer_state = self.per_peer_state.read().unwrap();
-                                               let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
-                                               if peer_state_mutex_opt.is_none() {
-                                                       break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
-                                               }
-                                               let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
-                                               let peer_state = &mut *peer_state_lock;
-                                               let chan = match peer_state.channel_by_id.get_mut(&forwarding_id) {
-                                                       None => {
-                                                               // Channel was removed. The short_to_chan_info and channel_by_id maps
-                                                               // have no consistency guarantees.
-                                                               break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
-                                                       },
-                                                       Some(chan) => chan
-                                               };
-                                               if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
-                                                       // Note that the behavior here should be identical to the above block - we
-                                                       // should NOT reveal the existence or non-existence of a private channel if
-                                                       // we don't allow forwards outbound over them.
-                                                       break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
-                                               }
-                                               if chan.context.get_channel_type().supports_scid_privacy() && *short_channel_id != chan.context.outbound_scid_alias() {
-                                                       // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
-                                                       // "refuse to forward unless the SCID alias was used", so we pretend
-                                                       // we don't have the channel here.
-                                                       break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
-                                               }
-                                               let chan_update_opt = self.get_channel_update_for_onion(*short_channel_id, chan).ok();
-
-                                               // Note that we could technically not return an error yet here and just hope
-                                               // that the connection is reestablished or monitor updated by the time we get
-                                               // around to doing the actual forward, but better to fail early if we can and
-                                               // hopefully an attacker trying to path-trace payments cannot make this occur
-                                               // on a small/per-node/per-channel scale.
-                                               if !chan.context.is_live() { // channel_disabled
-                                                       // If the channel_update we're going to return is disabled (i.e. the
-                                                       // peer has been disabled for some time), return `channel_disabled`,
-                                                       // otherwise return `temporary_channel_failure`.
-                                                       if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
-                                                               break Some(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
-                                                       } else {
-                                                               break Some(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
-                                                       }
-                                               }
-                                               if *outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
-                                                       break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
-                                               }
-                                               if let Err((err, code)) = chan.htlc_satisfies_config(&msg, *outgoing_amt_msat, *outgoing_cltv_value) {
-                                                       break Some((err, code, chan_update_opt));
-                                               }
-                                               chan_update_opt
-                                       } else {
-                                               if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
-                                                       // We really should set `incorrect_cltv_expiry` here but as we're not
-                                                       // forwarding over a real channel we can't generate a channel_update
-                                                       // for it. Instead we just return a generic temporary_node_failure.
-                                                       break Some((
-                                                               "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
-                                                               0x2000 | 2, None,
-                                                       ));
-                                               }
-                                               None
-                                       };
-
-                                       let cur_height = self.best_block.read().unwrap().height() + 1;
-                                       // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
-                                       // but we want to be robust wrt to counterparty packet sanitization (see
-                                       // HTLC_FAIL_BACK_BUFFER rationale).
-                                       if msg.cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
-                                               break Some(("CLTV expiry is too close", 0x1000 | 14, chan_update_opt));
-                                       }
-                                       if msg.cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
-                                               break Some(("CLTV expiry is too far in the future", 21, None));
-                                       }
-                                       // If the HTLC expires ~now, don't bother trying to forward it to our
-                                       // counterparty. They should fail it anyway, but we don't want to bother with
-                                       // the round-trips or risk them deciding they definitely want the HTLC and
-                                       // force-closing to ensure they get it if we're offline.
-                                       // We previously had a much more aggressive check here which tried to ensure
-                                       // our counterparty receives an HTLC which has *our* risk threshold met on it,
-                                       // but there is no need to do that, and since we're a bit conservative with our
-                                       // risk threshold it just results in failing to forward payments.
-                                       if (*outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
-                                               break Some(("Outgoing CLTV value is too soon", 0x1000 | 14, chan_update_opt));
-                                       }
-
-                                       break None;
-                               }
-                               {
-                                       let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 2 + 8 + 2));
-                                       if let Some(chan_update) = chan_update {
-                                               if code == 0x1000 | 11 || code == 0x1000 | 12 {
-                                                       msg.amount_msat.write(&mut res).expect("Writes cannot fail");
-                                               }
-                                               else if code == 0x1000 | 13 {
-                                                       msg.cltv_expiry.write(&mut res).expect("Writes cannot fail");
-                                               }
-                                               else if code == 0x1000 | 20 {
-                                                       // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
-                                                       0u16.write(&mut res).expect("Writes cannot fail");
-                                               }
-                                               (chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
-                                               msgs::ChannelUpdate::TYPE.write(&mut res).expect("Writes cannot fail");
-                                               chan_update.write(&mut res).expect("Writes cannot fail");
-                                       } else if code & 0x1000 == 0x1000 {
-                                               // If we're trying to return an error that requires a `channel_update` but
-                                               // we're forwarding to a phantom or intercept "channel" (i.e. cannot
-                                               // generate an update), just use the generic "temporary_node_failure"
-                                               // instead.
-                                               code = 0x2000 | 2;
-                                       }
-                                       return_err!(err, code, &res.0[..]);
-                               }
-                       }
                }
-
-               pending_forward_info
        }
 
        /// Gets the current [`channel_update`] for the given channel. This first checks if the channel is
@@ -2984,22 +3137,21 @@ where
                                                session_priv: session_priv.clone(),
                                                first_hop_htlc_msat: htlc_msat,
                                                payment_id,
-                                       }, onion_packet, &self.logger);
+                                       }, onion_packet, None, &self.fee_estimator, &self.logger);
                                match break_chan_entry!(self, send_res, chan) {
                                        Some(monitor_update) => {
-                                               let update_id = monitor_update.update_id;
-                                               let update_res = self.chain_monitor.update_channel(funding_txo, monitor_update);
-                                               if let Err(e) = handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, peer_state, per_peer_state, chan) {
-                                                       break Err(e);
-                                               }
-                                               if update_res == ChannelMonitorUpdateStatus::InProgress {
-                                                       // Note that MonitorUpdateInProgress here indicates (per function
-                                                       // docs) that we will resend the commitment update once monitor
-                                                       // updating completes. Therefore, we must return an error
-                                                       // indicating that it is unsafe to retry the payment wholesale,
-                                                       // which we do in the send_payment check for
-                                                       // MonitorUpdateInProgress, below.
-                                                       return Err(APIError::MonitorUpdateInProgress);
+                                               match handle_new_monitor_update!(self, funding_txo, monitor_update, peer_state_lock, peer_state, per_peer_state, chan) {
+                                                       Err(e) => break Err(e),
+                                                       Ok(false) => {
+                                                               // Note that MonitorUpdateInProgress here indicates (per function
+                                                               // docs) that we will resend the commitment update once monitor
+                                                               // updating completes. Therefore, we must return an error
+                                                               // indicating that it is unsafe to retry the payment wholesale,
+                                                               // which we do in the send_payment check for
+                                                               // MonitorUpdateInProgress, below.
+                                                               return Err(APIError::MonitorUpdateInProgress);
+                                                       },
+                                                       Ok(true) => {},
                                                }
                                        },
                                        None => { },
@@ -3068,6 +3220,7 @@ where
        /// irrevocably committed to on our end. In such a case, do NOT retry the payment with a
        /// different route unless you intend to pay twice!
        ///
+       /// [`RouteHop`]: crate::routing::router::RouteHop
        /// [`Event::PaymentSent`]: events::Event::PaymentSent
        /// [`Event::PaymentFailed`]: events::Event::PaymentFailed
        /// [`UpdateHTLCs`]: events::MessageSendEvent::UpdateHTLCs
@@ -3212,7 +3365,7 @@ where
                        Some(chan) => {
                                let funding_txo = find_funding_output(&chan, &funding_transaction)?;
 
-                               let funding_res = chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger)
+                               let funding_res = chan.get_funding_created(funding_transaction, funding_txo, &self.logger)
                                        .map_err(|(mut chan, e)| if let ChannelError::Close(msg) = e {
                                                let channel_id = chan.context.channel_id();
                                                let user_id = chan.context.get_user_id();
@@ -3385,27 +3538,48 @@ where
                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                let peer_state = &mut *peer_state_lock;
                for channel_id in channel_ids {
-                       if !peer_state.channel_by_id.contains_key(channel_id) {
+                       if !peer_state.has_channel(channel_id) {
                                return Err(APIError::ChannelUnavailable {
                                        err: format!("Channel with ID {} was not found for the passed counterparty_node_id {}", log_bytes!(*channel_id), counterparty_node_id),
                                });
-                       }
+                       };
                }
                for channel_id in channel_ids {
-                       let channel = peer_state.channel_by_id.get_mut(channel_id).unwrap();
-                       let mut config = channel.context.config();
-                       config.apply(config_update);
-                       if !channel.context.update_config(&config) {
+                       if let Some(channel) = peer_state.channel_by_id.get_mut(channel_id) {
+                               let mut config = channel.context.config();
+                               config.apply(config_update);
+                               if !channel.context.update_config(&config) {
+                                       continue;
+                               }
+                               if let Ok(msg) = self.get_channel_update_for_broadcast(channel) {
+                                       peer_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { msg });
+                               } else if let Ok(msg) = self.get_channel_update_for_unicast(channel) {
+                                       peer_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
+                                               node_id: channel.context.get_counterparty_node_id(),
+                                               msg,
+                                       });
+                               }
                                continue;
                        }
-                       if let Ok(msg) = self.get_channel_update_for_broadcast(channel) {
-                               peer_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { msg });
-                       } else if let Ok(msg) = self.get_channel_update_for_unicast(channel) {
-                               peer_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
-                                       node_id: channel.context.get_counterparty_node_id(),
-                                       msg,
+
+                       let context = if let Some(channel) = peer_state.inbound_v1_channel_by_id.get_mut(channel_id) {
+                               &mut channel.context
+                       } else if let Some(channel) = peer_state.outbound_v1_channel_by_id.get_mut(channel_id) {
+                               &mut channel.context
+                       } else {
+                               // This should not be reachable as we've already checked for non-existence in the previous channel_id loop.
+                               debug_assert!(false);
+                               return Err(APIError::ChannelUnavailable {
+                                       err: format!(
+                                               "Channel with ID {} for passed counterparty_node_id {} disappeared after we confirmed its existence - this should not be reachable!",
+                                               log_bytes!(*channel_id), counterparty_node_id),
                                });
-                       }
+                       };
+                       let mut config = context.config();
+                       config.apply(config_update);
+                       // We update the config, but we MUST NOT broadcast a `channel_update` before `channel_ready`
+                       // which would be the case for pending inbound/outbound channels.
+                       context.update_config(&config);
                }
                Ok(())
        }
@@ -3451,13 +3625,16 @@ where
        /// [`ChannelManager::fail_intercepted_htlc`] MUST be called in response to the event.
        ///
        /// Note that LDK does not enforce fee requirements in `amt_to_forward_msat`, and will not stop
-       /// you from forwarding more than you received.
+       /// you from forwarding more than you received. See
+       /// [`HTLCIntercepted::expected_outbound_amount_msat`] for more on forwarding a different amount
+       /// than expected.
        ///
        /// Errors if the event was not handled in time, in which case the HTLC was automatically failed
        /// backwards.
        ///
        /// [`UserConfig::accept_intercept_htlcs`]: crate::util::config::UserConfig::accept_intercept_htlcs
        /// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
+       /// [`HTLCIntercepted::expected_outbound_amount_msat`]: events::Event::HTLCIntercepted::expected_outbound_amount_msat
        // TODO: when we move to deciding the best outbound channel at forward time, only take
        // `next_node_id` and not `next_hop_channel_id`
        pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {
@@ -3496,7 +3673,10 @@ where
                        },
                        _ => unreachable!() // Only `PendingHTLCRouting::Forward`s are intercepted
                };
+               let skimmed_fee_msat =
+                       payment.forward_info.outgoing_amt_msat.saturating_sub(amt_to_forward_msat);
                let pending_htlc_info = PendingHTLCInfo {
+                       skimmed_fee_msat: if skimmed_fee_msat == 0 { None } else { Some(skimmed_fee_msat) },
                        outgoing_amt_msat: amt_to_forward_msat, routing, ..payment.forward_info
                };
 
@@ -3566,7 +3746,7 @@ where
                                                                                prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id,
                                                                                forward_info: PendingHTLCInfo {
                                                                                        routing, incoming_shared_secret, payment_hash, outgoing_amt_msat,
-                                                                                       outgoing_cltv_value, incoming_amt_msat: _
+                                                                                       outgoing_cltv_value, ..
                                                                                }
                                                                        }) => {
                                                                                macro_rules! failure_handler {
@@ -3628,7 +3808,10 @@ where
                                                                                                };
                                                                                                match next_hop {
                                                                                                        onion_utils::Hop::Receive(hop_data) => {
-                                                                                                               match self.construct_recv_pending_htlc_info(hop_data, incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value, Some(phantom_shared_secret)) {
+                                                                                                               match self.construct_recv_pending_htlc_info(hop_data,
+                                                                                                                       incoming_shared_secret, payment_hash, outgoing_amt_msat,
+                                                                                                                       outgoing_cltv_value, Some(phantom_shared_secret), false, None)
+                                                                                                               {
                                                                                                                        Ok(info) => phantom_receives.push((prev_short_channel_id, prev_funding_outpoint, prev_user_channel_id, vec![(info, prev_htlc_id)])),
                                                                                                                        Err(ReceiveError { err_code, err_data, msg }) => failed_payment!(msg, err_code, err_data, Some(phantom_shared_secret))
                                                                                                                }
@@ -3679,7 +3862,7 @@ where
                                                                                prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id: _,
                                                                                forward_info: PendingHTLCInfo {
                                                                                        incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
-                                                                                       routing: PendingHTLCRouting::Forward { onion_packet, .. }, incoming_amt_msat: _,
+                                                                                       routing: PendingHTLCRouting::Forward { onion_packet, .. }, skimmed_fee_msat, ..
                                                                                },
                                                                        }) => {
                                                                                log_trace!(self.logger, "Adding HTLC from short id {} with payment_hash {} to channel with short id {} after delay", prev_short_channel_id, log_bytes!(payment_hash.0), short_chan_id);
@@ -3693,7 +3876,8 @@ where
                                                                                });
                                                                                if let Err(e) = chan.get_mut().queue_add_htlc(outgoing_amt_msat,
                                                                                        payment_hash, outgoing_cltv_value, htlc_source.clone(),
-                                                                                       onion_packet, &self.logger)
+                                                                                       onion_packet, skimmed_fee_msat, &self.fee_estimator,
+                                                                                       &self.logger)
                                                                                {
                                                                                        if let ChannelError::Ignore(msg) = e {
                                                                                                log_trace!(self.logger, "Failed to forward HTLC with payment_hash {}: {}", log_bytes!(payment_hash.0), msg);
@@ -3737,7 +3921,8 @@ where
                                                        HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
                                                                prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id,
                                                                forward_info: PendingHTLCInfo {
-                                                                       routing, incoming_shared_secret, payment_hash, incoming_amt_msat, outgoing_amt_msat, ..
+                                                                       routing, incoming_shared_secret, payment_hash, incoming_amt_msat, outgoing_amt_msat,
+                                                                       skimmed_fee_msat, ..
                                                                }
                                                        }) => {
                                                                let (cltv_expiry, onion_payload, payment_data, phantom_shared_secret, mut onion_fields) = match routing {
@@ -3778,6 +3963,7 @@ where
                                                                        total_msat: if let Some(data) = &payment_data { data.total_msat } else { outgoing_amt_msat },
                                                                        cltv_expiry,
                                                                        onion_payload,
+                                                                       counterparty_skimmed_fee_msat: skimmed_fee_msat,
                                                                };
 
                                                                let mut committed_to_claimable = false;
@@ -3874,11 +4060,16 @@ where
                                                                                        htlcs.push(claimable_htlc);
                                                                                        let amount_msat = htlcs.iter().map(|htlc| htlc.value).sum();
                                                                                        htlcs.iter_mut().for_each(|htlc| htlc.total_value_received = Some(amount_msat));
+                                                                                       let counterparty_skimmed_fee_msat = htlcs.iter()
+                                                                                               .map(|htlc| htlc.counterparty_skimmed_fee_msat.unwrap_or(0)).sum();
+                                                                                       debug_assert!(total_value.saturating_sub(amount_msat) <=
+                                                                                               counterparty_skimmed_fee_msat);
                                                                                        new_events.push_back((events::Event::PaymentClaimable {
                                                                                                receiver_node_id: Some(receiver_node_id),
                                                                                                payment_hash,
                                                                                                purpose: $purpose,
                                                                                                amount_msat,
+                                                                                               counterparty_skimmed_fee_msat,
                                                                                                via_channel_id: Some(prev_channel_id),
                                                                                                via_user_channel_id: Some(prev_user_channel_id),
                                                                                                claim_deadline: Some(earliest_expiry - HTLC_FAIL_BACK_BUFFER),
@@ -4001,7 +4192,6 @@ where
        fn process_background_events(&self) -> NotifyOption {
                debug_assert_ne!(self.total_consistency_lock.held_by_thread(), LockHeldState::NotHeldByThread);
 
-               #[cfg(debug_assertions)]
                self.background_events_processed_since_startup.store(true, Ordering::Release);
 
                let mut background_events = Vec::new();
@@ -4012,14 +4202,13 @@ where
 
                for event in background_events.drain(..) {
                        match event {
-                               BackgroundEvent::ClosingMonitorUpdateRegeneratedOnStartup((funding_txo, update)) => {
+                               BackgroundEvent::ClosedMonitorUpdateRegeneratedOnStartup((funding_txo, update)) => {
                                        // The channel has already been closed, so no use bothering to care about the
                                        // monitor updating completing.
                                        let _ = self.chain_monitor.update_channel(funding_txo, &update);
                                },
                                BackgroundEvent::MonitorUpdateRegeneratedOnStartup { counterparty_node_id, funding_txo, update } => {
-                                       let update_res = self.chain_monitor.update_channel(funding_txo, &update);
-
+                                       let mut updated_chan = false;
                                        let res = {
                                                let per_peer_state = self.per_peer_state.read().unwrap();
                                                if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) {
@@ -4027,12 +4216,18 @@ where
                                                        let peer_state = &mut *peer_state_lock;
                                                        match peer_state.channel_by_id.entry(funding_txo.to_channel_id()) {
                                                                hash_map::Entry::Occupied(mut chan) => {
-                                                                       handle_new_monitor_update!(self, update_res, update.update_id, peer_state_lock, peer_state, per_peer_state, chan)
+                                                                       updated_chan = true;
+                                                                       handle_new_monitor_update!(self, funding_txo, update.clone(),
+                                                                               peer_state_lock, peer_state, per_peer_state, chan).map(|_| ())
                                                                },
                                                                hash_map::Entry::Vacant(_) => Ok(()),
                                                        }
                                                } else { Ok(()) }
                                        };
+                                       if !updated_chan {
+                                               // TODO: Track this as in-flight even though the channel is closed.
+                                               let _ = self.chain_monitor.update_channel(funding_txo, &update);
+                                       }
                                        // TODO: If this channel has since closed, we're likely providing a payment
                                        // preimage update, which we must ensure is durable! We currently don't,
                                        // however, ensure that.
@@ -4042,6 +4237,22 @@ where
                                        }
                                        let _ = handle_error!(self, res, counterparty_node_id);
                                },
+                               BackgroundEvent::MonitorUpdatesComplete { counterparty_node_id, channel_id } => {
+                                       let per_peer_state = self.per_peer_state.read().unwrap();
+                                       if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) {
+                                               let mut peer_state_lock = peer_state_mutex.lock().unwrap();
+                                               let peer_state = &mut *peer_state_lock;
+                                               if let Some(chan) = peer_state.channel_by_id.get_mut(&channel_id) {
+                                                       handle_monitor_update_completion!(self, peer_state_lock, peer_state, per_peer_state, chan);
+                                               } else {
+                                                       let update_actions = peer_state.monitor_update_blocked_actions
+                                                               .remove(&channel_id).unwrap_or(Vec::new());
+                                                       mem::drop(peer_state_lock);
+                                                       mem::drop(per_peer_state);
+                                                       self.handle_monitor_update_completion_actions(update_actions);
+                                               }
+                                       }
+                               },
                        }
                }
                NotifyOption::DoPersist
@@ -4070,7 +4281,7 @@ where
                log_trace!(self.logger, "Channel {} qualifies for a feerate change from {} to {}.",
                        log_bytes!(chan_id[..]), chan.context.get_feerate_sat_per_1000_weight(), new_feerate);
 
-               chan.queue_update_fee(new_feerate, &self.logger);
+               chan.queue_update_fee(new_feerate, &self.fee_estimator, &self.logger);
                NotifyOption::DoPersist
        }
 
@@ -4083,13 +4294,19 @@ where
                PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || {
                        let mut should_persist = self.process_background_events();
 
-                       let new_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
+                       let normal_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
+                       let min_mempool_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MempoolMinimum);
 
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
                                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                                let peer_state = &mut *peer_state_lock;
                                for (chan_id, chan) in peer_state.channel_by_id.iter_mut() {
+                                       let new_feerate = if chan.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                                               min_mempool_feerate
+                                       } else {
+                                               normal_feerate
+                                       };
                                        let chan_needs_persist = self.update_channel_fee(chan_id, chan, new_feerate);
                                        if chan_needs_persist == NotifyOption::DoPersist { should_persist = NotifyOption::DoPersist; }
                                }
@@ -4109,6 +4326,7 @@ where
        ///  * Expiring a channel's previous [`ChannelConfig`] if necessary to only allow forwarding HTLCs
        ///    with the current [`ChannelConfig`].
        ///  * Removing peers which have disconnected but and no longer have any channels.
+       ///  * Force-closing and removing channels which have not completed establishment in a timely manner.
        ///
        /// Note that this may cause reentrancy through [`chain::Watch::update_channel`] calls or feerate
        /// estimate fetches.
@@ -4119,7 +4337,8 @@ where
                PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || {
                        let mut should_persist = self.process_background_events();
 
-                       let new_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
+                       let normal_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
+                       let min_mempool_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MempoolMinimum);
 
                        let mut handle_errors: Vec<(Result<(), _>, _)> = Vec::new();
                        let mut timed_out_mpp_htlcs = Vec::new();
@@ -4132,6 +4351,11 @@ where
                                        let pending_msg_events = &mut peer_state.pending_msg_events;
                                        let counterparty_node_id = *counterparty_node_id;
                                        peer_state.channel_by_id.retain(|chan_id, chan| {
+                                               let new_feerate = if chan.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                                                       min_mempool_feerate
+                                               } else {
+                                                       normal_feerate
+                                               };
                                                let chan_needs_persist = self.update_channel_fee(chan_id, chan, new_feerate);
                                                if chan_needs_persist == NotifyOption::DoPersist { should_persist = NotifyOption::DoPersist; }
 
@@ -4197,6 +4421,26 @@ where
 
                                                true
                                        });
+
+                                       let process_unfunded_channel_tick = |
+                                               chan_id: &[u8; 32],
+                                               chan_context: &mut ChannelContext<<SP::Target as SignerProvider>::Signer>,
+                                               unfunded_chan_context: &mut UnfundedChannelContext,
+                                       | {
+                                               chan_context.maybe_expire_prev_config();
+                                               if unfunded_chan_context.should_expire_unfunded_channel() {
+                                                       log_error!(self.logger, "Force-closing pending outbound channel {} for not establishing in a timely manner", log_bytes!(&chan_id[..]));
+                                                       update_maps_on_chan_removal!(self, &chan_context);
+                                                       self.issue_channel_close_events(&chan_context, ClosureReason::HolderForceClosed);
+                                                       self.finish_force_close_channel(chan_context.force_shutdown(false));
+                                                       false
+                                               } else {
+                                                       true
+                                               }
+                                       };
+                                       peer_state.outbound_v1_channel_by_id.retain(|chan_id, chan| process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context));
+                                       peer_state.inbound_v1_channel_by_id.retain(|chan_id, chan| process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context));
+
                                        if peer_state.ok_to_remove(true) {
                                                pending_peers_awaiting_removal.push(counterparty_node_id);
                                        }
@@ -4587,6 +4831,11 @@ where
        -> Result<(), (PublicKey, MsgHandleErrInternal)> {
                //TODO: Delay the claimed_funds relaying just like we do outbound relay!
 
+               // If we haven't yet run background events assume we're still deserializing and shouldn't
+               // actually pass `ChannelMonitorUpdate`s to users yet. Instead, queue them up as
+               // `BackgroundEvent`s.
+               let during_init = !self.background_events_processed_since_startup.load(Ordering::Acquire);
+
                {
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        let chan_id = prev_hop.outpoint.to_channel_id();
@@ -4613,16 +4862,26 @@ where
                                                                log_bytes!(chan_id), action);
                                                        peer_state.monitor_update_blocked_actions.entry(chan_id).or_insert(Vec::new()).push(action);
                                                }
-                                               let update_id = monitor_update.update_id;
-                                               let update_res = self.chain_monitor.update_channel(prev_hop.outpoint, monitor_update);
-                                               let res = handle_new_monitor_update!(self, update_res, update_id, peer_state_lock,
-                                                       peer_state, per_peer_state, chan);
-                                               if let Err(e) = res {
-                                                       // TODO: This is a *critical* error - we probably updated the outbound edge
-                                                       // of the HTLC's monitor with a preimage. We should retry this monitor
-                                                       // update over and over again until morale improves.
-                                                       log_error!(self.logger, "Failed to update channel monitor with preimage {:?}", payment_preimage);
-                                                       return Err((counterparty_node_id, e));
+                                               if !during_init {
+                                                       let res = handle_new_monitor_update!(self, prev_hop.outpoint, monitor_update, peer_state_lock,
+                                                               peer_state, per_peer_state, chan);
+                                                       if let Err(e) = res {
+                                                               // TODO: This is a *critical* error - we probably updated the outbound edge
+                                                               // of the HTLC's monitor with a preimage. We should retry this monitor
+                                                               // update over and over again until morale improves.
+                                                               log_error!(self.logger, "Failed to update channel monitor with preimage {:?}", payment_preimage);
+                                                               return Err((counterparty_node_id, e));
+                                                       }
+                                               } else {
+                                                       // If we're running during init we cannot update a monitor directly -
+                                                       // they probably haven't actually been loaded yet. Instead, push the
+                                                       // monitor update as a background event.
+                                                       self.pending_background_events.lock().unwrap().push(
+                                                               BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
+                                                                       counterparty_node_id,
+                                                                       funding_txo: prev_hop.outpoint,
+                                                                       update: monitor_update.clone(),
+                                                               });
                                                }
                                        }
                                        return Ok(());
@@ -4635,16 +4894,34 @@ where
                                payment_preimage,
                        }],
                };
-               // We update the ChannelMonitor on the backward link, after
-               // receiving an `update_fulfill_htlc` from the forward link.
-               let update_res = self.chain_monitor.update_channel(prev_hop.outpoint, &preimage_update);
-               if update_res != ChannelMonitorUpdateStatus::Completed {
-                       // TODO: This needs to be handled somehow - if we receive a monitor update
-                       // with a preimage we *must* somehow manage to propagate it to the upstream
-                       // channel, or we must have an ability to receive the same event and try
-                       // again on restart.
-                       log_error!(self.logger, "Critical error: failed to update channel monitor with preimage {:?}: {:?}",
-                               payment_preimage, update_res);
+
+               if !during_init {
+                       // We update the ChannelMonitor on the backward link, after
+                       // receiving an `update_fulfill_htlc` from the forward link.
+                       let update_res = self.chain_monitor.update_channel(prev_hop.outpoint, &preimage_update);
+                       if update_res != ChannelMonitorUpdateStatus::Completed {
+                               // TODO: This needs to be handled somehow - if we receive a monitor update
+                               // with a preimage we *must* somehow manage to propagate it to the upstream
+                               // channel, or we must have an ability to receive the same event and try
+                               // again on restart.
+                               log_error!(self.logger, "Critical error: failed to update channel monitor with preimage {:?}: {:?}",
+                                       payment_preimage, update_res);
+                       }
+               } else {
+                       // If we're running during init we cannot update a monitor directly - they probably
+                       // haven't actually been loaded yet. Instead, push the monitor update as a background
+                       // event.
+                       // Note that while it's safe to use `ClosedMonitorUpdateRegeneratedOnStartup` here (the
+                       // channel is already closed) we need to ultimately handle the monitor update
+                       // completion action only after we've completed the monitor update. This is the only
+                       // way to guarantee this update *will* be regenerated on startup (otherwise if this was
+                       // from a forwarded HTLC the downstream preimage may be deleted before we claim
+                       // upstream). Thus, we need to transition to some new `BackgroundEvent` type which will
+                       // complete the monitor update completion action from `completion_action`.
+                       self.pending_background_events.lock().unwrap().push(
+                               BackgroundEvent::ClosedMonitorUpdateRegeneratedOnStartup((
+                                       prev_hop.outpoint, preimage_update,
+                               )));
                }
                // Note that we do process the completion action here. This totally could be a
                // duplicate claim, but we have no way of knowing without interrogating the
@@ -4662,6 +4939,8 @@ where
        fn claim_funds_internal(&self, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, next_channel_id: [u8; 32]) {
                match source {
                        HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
+                               debug_assert!(self.background_events_processed_since_startup.load(Ordering::Acquire),
+                                       "We don't support claim_htlc claims during startup - monitors may not be available yet");
                                self.pending_outbound_payments.claim_htlc(payment_id, payment_preimage, session_priv, path, from_onchain, &self.pending_events, &self.logger);
                        },
                        HTLCSource::PreviousHopData(hop_data) => {
@@ -4817,18 +5096,29 @@ where
                if peer_state_mutex_opt.is_none() { return }
                peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
                let peer_state = &mut *peer_state_lock;
-               let mut channel = {
-                       match peer_state.channel_by_id.entry(funding_txo.to_channel_id()){
-                               hash_map::Entry::Occupied(chan) => chan,
-                               hash_map::Entry::Vacant(_) => return,
-                       }
-               };
-               log_trace!(self.logger, "ChannelMonitor updated to {}. Current highest is {}",
-                       highest_applied_update_id, channel.get().context.get_latest_monitor_update_id());
-               if !channel.get().is_awaiting_monitor_update() || channel.get().context.get_latest_monitor_update_id() != highest_applied_update_id {
+               let channel =
+                       if let Some(chan) = peer_state.channel_by_id.get_mut(&funding_txo.to_channel_id()) {
+                               chan
+                       } else {
+                               let update_actions = peer_state.monitor_update_blocked_actions
+                                       .remove(&funding_txo.to_channel_id()).unwrap_or(Vec::new());
+                               mem::drop(peer_state_lock);
+                               mem::drop(per_peer_state);
+                               self.handle_monitor_update_completion_actions(update_actions);
+                               return;
+                       };
+               let remaining_in_flight =
+                       if let Some(pending) = peer_state.in_flight_monitor_updates.get_mut(funding_txo) {
+                               pending.retain(|upd| upd.update_id > highest_applied_update_id);
+                               pending.len()
+                       } else { 0 };
+               log_trace!(self.logger, "ChannelMonitor updated to {}. Current highest is {}. {} pending in-flight updates.",
+                       highest_applied_update_id, channel.context.get_latest_monitor_update_id(),
+                       remaining_in_flight);
+               if !channel.is_awaiting_monitor_update() || channel.context.get_latest_monitor_update_id() != highest_applied_update_id {
                        return;
                }
-               handle_monitor_update_completion!(self, highest_applied_update_id, peer_state_lock, peer_state, per_peer_state, channel.get_mut());
+               handle_monitor_update_completion!(self, peer_state_lock, peer_state, per_peer_state, channel);
        }
 
        /// Accepts a request to open a channel after a [`Event::OpenChannelRequest`].
@@ -5039,9 +5329,13 @@ where
                        return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision for the same peer!".to_owned(), msg.temporary_channel_id.clone()))
                } else {
                        if !self.default_configuration.manually_accept_inbound_channels {
-                               if channel.context.get_channel_type().requires_zero_conf() {
+                               let channel_type = channel.context.get_channel_type();
+                               if channel_type.requires_zero_conf() {
                                        return Err(MsgHandleErrInternal::send_err_msg_no_close("No zero confirmation channels accepted".to_owned(), msg.temporary_channel_id.clone()));
                                }
+                               if channel_type.requires_anchors_zero_fee_htlc_tx() {
+                                       return Err(MsgHandleErrInternal::send_err_msg_no_close("No channels with anchor outputs accepted".to_owned(), msg.temporary_channel_id.clone()));
+                               }
                                peer_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
                                        node_id: counterparty_node_id.clone(),
                                        msg: channel.accept_inbound_channel(user_channel_id),
@@ -5151,8 +5445,9 @@ where
                                let monitor_res = self.chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor);
 
                                let chan = e.insert(chan);
-                               let mut res = handle_new_monitor_update!(self, monitor_res, 0, peer_state_lock, peer_state,
-                                       per_peer_state, chan, MANUALLY_REMOVING, { peer_state.channel_by_id.remove(&new_channel_id) });
+                               let mut res = handle_new_monitor_update!(self, monitor_res, peer_state_lock, peer_state,
+                                       per_peer_state, chan, MANUALLY_REMOVING_INITIAL_MONITOR,
+                                       { peer_state.channel_by_id.remove(&new_channel_id) });
 
                                // Note that we reply with the new channel_id in error messages if we gave up on the
                                // channel, not the temporary_channel_id. This is compatible with ourselves, but the
@@ -5164,7 +5459,7 @@ where
                                if let Err(MsgHandleErrInternal { shutdown_finish: Some((res, _)), .. }) = &mut res {
                                        res.0 = None;
                                }
-                               res
+                               res.map(|_| ())
                        }
                }
        }
@@ -5185,7 +5480,7 @@ where
                                let monitor = try_chan_entry!(self,
                                        chan.get_mut().funding_signed(&msg, best_block, &self.signer_provider, &self.logger), chan);
                                let update_res = self.chain_monitor.watch_channel(chan.get().context.get_funding_txo().unwrap(), monitor);
-                               let mut res = handle_new_monitor_update!(self, update_res, 0, peer_state_lock, peer_state, per_peer_state, chan);
+                               let mut res = handle_new_monitor_update!(self, update_res, peer_state_lock, peer_state, per_peer_state, chan, INITIAL_MONITOR);
                                if let Err(MsgHandleErrInternal { ref mut shutdown_finish, .. }) = res {
                                        // We weren't able to watch the channel to begin with, so no updates should be made on
                                        // it. Previously, full_stack_target found an (unreachable) panic when the
@@ -5194,7 +5489,7 @@ where
                                                shutdown_finish.0.take();
                                        }
                                }
-                               res
+                               res.map(|_| ())
                        },
                        hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
                }
@@ -5256,39 +5551,50 @@ where
                                })?;
                        let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                        let peer_state = &mut *peer_state_lock;
-                       match peer_state.channel_by_id.entry(msg.channel_id.clone()) {
-                               hash_map::Entry::Occupied(mut chan_entry) => {
-
-                                       if !chan_entry.get().received_shutdown() {
-                                               log_info!(self.logger, "Received a shutdown message from our counterparty for channel {}{}.",
-                                                       log_bytes!(msg.channel_id),
-                                                       if chan_entry.get().sent_shutdown() { " after we initiated shutdown" } else { "" });
-                                       }
+                       // TODO(dunxen): Fix this duplication when we switch to a single map with enums as per
+                       // https://github.com/lightningdevkit/rust-lightning/issues/2422
+                       if let hash_map::Entry::Occupied(chan_entry) = peer_state.outbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
+                               log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
+                               self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
+                               let mut chan = remove_channel!(self, chan_entry);
+                               self.finish_force_close_channel(chan.context.force_shutdown(false));
+                               return Ok(());
+                       } else if let hash_map::Entry::Occupied(chan_entry) = peer_state.inbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
+                               log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
+                               self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
+                               let mut chan = remove_channel!(self, chan_entry);
+                               self.finish_force_close_channel(chan.context.force_shutdown(false));
+                               return Ok(());
+                       } else if let hash_map::Entry::Occupied(mut chan_entry) = peer_state.channel_by_id.entry(msg.channel_id.clone()) {
+                               if !chan_entry.get().received_shutdown() {
+                                       log_info!(self.logger, "Received a shutdown message from our counterparty for channel {}{}.",
+                                               log_bytes!(msg.channel_id),
+                                               if chan_entry.get().sent_shutdown() { " after we initiated shutdown" } else { "" });
+                               }
 
-                                       let funding_txo_opt = chan_entry.get().context.get_funding_txo();
-                                       let (shutdown, monitor_update_opt, htlcs) = try_chan_entry!(self,
-                                               chan_entry.get_mut().shutdown(&self.signer_provider, &peer_state.latest_features, &msg), chan_entry);
-                                       dropped_htlcs = htlcs;
+                               let funding_txo_opt = chan_entry.get().context.get_funding_txo();
+                               let (shutdown, monitor_update_opt, htlcs) = try_chan_entry!(self,
+                                       chan_entry.get_mut().shutdown(&self.signer_provider, &peer_state.latest_features, &msg), chan_entry);
+                               dropped_htlcs = htlcs;
 
-                                       if let Some(msg) = shutdown {
-                                               // We can send the `shutdown` message before updating the `ChannelMonitor`
-                                               // here as we don't need the monitor update to complete until we send a
-                                               // `shutdown_signed`, which we'll delay if we're pending a monitor update.
-                                               peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
-                                                       node_id: *counterparty_node_id,
-                                                       msg,
-                                               });
-                                       }
+                               if let Some(msg) = shutdown {
+                                       // We can send the `shutdown` message before updating the `ChannelMonitor`
+                                       // here as we don't need the monitor update to complete until we send a
+                                       // `shutdown_signed`, which we'll delay if we're pending a monitor update.
+                                       peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
+                                               node_id: *counterparty_node_id,
+                                               msg,
+                                       });
+                               }
 
-                                       // Update the monitor with the shutdown script if necessary.
-                                       if let Some(monitor_update) = monitor_update_opt {
-                                               let update_id = monitor_update.update_id;
-                                               let update_res = self.chain_monitor.update_channel(funding_txo_opt.unwrap(), monitor_update);
-                                               break handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, peer_state, per_peer_state, chan_entry);
-                                       }
-                                       break Ok(());
-                               },
-                               hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
+                               // Update the monitor with the shutdown script if necessary.
+                               if let Some(monitor_update) = monitor_update_opt {
+                                       break handle_new_monitor_update!(self, funding_txo_opt.unwrap(), monitor_update,
+                                               peer_state_lock, peer_state, per_peer_state, chan_entry).map(|_| ());
+                               }
+                               break Ok(());
+                       } else {
+                               return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
                        }
                };
                for htlc_source in dropped_htlcs.drain(..) {
@@ -5358,7 +5664,7 @@ where
                //encrypted with the same key. It's not immediately obvious how to usefully exploit that,
                //but we should prevent it anyway.
 
-               let pending_forward_info = self.decode_update_add_htlc_onion(msg);
+               let decoded_hop_res = self.decode_update_add_htlc_onion(msg);
                let per_peer_state = self.per_peer_state.read().unwrap();
                let peer_state_mutex = per_peer_state.get(counterparty_node_id)
                        .ok_or_else(|| {
@@ -5370,6 +5676,12 @@ where
                match peer_state.channel_by_id.entry(msg.channel_id) {
                        hash_map::Entry::Occupied(mut chan) => {
 
+                               let pending_forward_info = match decoded_hop_res {
+                                       Ok((next_hop, shared_secret, next_packet_pk_opt)) =>
+                                               self.construct_pending_htlc_status(msg, shared_secret, next_hop,
+                                                       chan.get().context.config().accept_underpaying_htlcs, next_packet_pk_opt),
+                                       Err(e) => PendingHTLCStatus::Fail(e)
+                               };
                                let create_pending_htlc_status = |chan: &Channel<<SP::Target as SignerProvider>::Signer>, pending_forward_info: PendingHTLCStatus, error_code: u16| {
                                        // If the update_add is completely bogus, the call will Err and we will close,
                                        // but if we've sent a shutdown and they haven't acknowledged it yet, we just
@@ -5392,7 +5704,7 @@ where
                                                _ => pending_forward_info
                                        }
                                };
-                               try_chan_entry!(self, chan.get_mut().update_add_htlc(&msg, pending_forward_info, create_pending_htlc_status, &self.logger), chan);
+                               try_chan_entry!(self, chan.get_mut().update_add_htlc(&msg, pending_forward_info, create_pending_htlc_status, &self.fee_estimator, &self.logger), chan);
                        },
                        hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
                }
@@ -5474,10 +5786,8 @@ where
                                let funding_txo = chan.get().context.get_funding_txo();
                                let monitor_update_opt = try_chan_entry!(self, chan.get_mut().commitment_signed(&msg, &self.logger), chan);
                                if let Some(monitor_update) = monitor_update_opt {
-                                       let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update);
-                                       let update_id = monitor_update.update_id;
-                                       handle_new_monitor_update!(self, update_res, update_id, peer_state_lock,
-                                               peer_state, per_peer_state, chan)
+                                       handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update, peer_state_lock,
+                                               peer_state, per_peer_state, chan).map(|_| ())
                                } else { Ok(()) }
                        },
                        hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
@@ -5567,22 +5877,27 @@ where
                }
        }
 
-       // We only want to push a PendingHTLCsForwardable event if no others are queued.
        fn push_pending_forwards_ev(&self) {
                let mut pending_events = self.pending_events.lock().unwrap();
-               let forward_ev_exists = pending_events.iter()
-                       .find(|(ev, _)| if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false })
-                       .is_some();
-               if !forward_ev_exists {
-                       pending_events.push_back((events::Event::PendingHTLCsForwardable {
-                               time_forwardable:
-                                       Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
+               let is_processing_events = self.pending_events_processor.load(Ordering::Acquire);
+               let num_forward_events = pending_events.iter().filter(|(ev, _)|
+                       if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false }
+               ).count();
+               // We only want to push a PendingHTLCsForwardable event if no others are queued. Processing
+               // events is done in batches and they are not removed until we're done processing each
+               // batch. Since handling a `PendingHTLCsForwardable` event will call back into the
+               // `ChannelManager`, we'll still see the original forwarding event not removed. Phantom
+               // payments will need an additional forwarding event before being claimed to make them look
+               // real by taking more time.
+               if (is_processing_events && num_forward_events <= 1) || num_forward_events < 1 {
+                       pending_events.push_back((Event::PendingHTLCsForwardable {
+                               time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
                        }, None));
                }
        }
 
        /// Checks whether [`ChannelMonitorUpdate`]s generated by the receipt of a remote
-       /// [`msgs::RevokeAndACK`] should be held for the given channel until some other event
+       /// [`msgs::RevokeAndACK`] should be held for the given channel until some other action
        /// completes. Note that this needs to happen in the same [`PeerState`] mutex as any release of
        /// the [`ChannelMonitorUpdate`] in question.
        fn raa_monitor_updates_held(&self,
@@ -5611,12 +5926,10 @@ where
                        match peer_state.channel_by_id.entry(msg.channel_id) {
                                hash_map::Entry::Occupied(mut chan) => {
                                        let funding_txo = chan.get().context.get_funding_txo();
-                                       let (htlcs_to_fail, monitor_update_opt) = try_chan_entry!(self, chan.get_mut().revoke_and_ack(&msg, &self.logger), chan);
+                                       let (htlcs_to_fail, monitor_update_opt) = try_chan_entry!(self, chan.get_mut().revoke_and_ack(&msg, &self.fee_estimator, &self.logger), chan);
                                        let res = if let Some(monitor_update) = monitor_update_opt {
-                                               let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update);
-                                               let update_id = monitor_update.update_id;
-                                               handle_new_monitor_update!(self, update_res, update_id,
-                                                       peer_state_lock, peer_state, per_peer_state, chan)
+                                               handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
+                                                       peer_state_lock, peer_state, per_peer_state, chan).map(|_| ())
                                        } else { Ok(()) };
                                        (htlcs_to_fail, res)
                                },
@@ -5884,18 +6197,15 @@ where
                                                let counterparty_node_id = chan.context.get_counterparty_node_id();
                                                let funding_txo = chan.context.get_funding_txo();
                                                let (monitor_opt, holding_cell_failed_htlcs) =
-                                                       chan.maybe_free_holding_cell_htlcs(&self.logger);
+                                                       chan.maybe_free_holding_cell_htlcs(&self.fee_estimator, &self.logger);
                                                if !holding_cell_failed_htlcs.is_empty() {
                                                        failed_htlcs.push((holding_cell_failed_htlcs, *channel_id, counterparty_node_id));
                                                }
                                                if let Some(monitor_update) = monitor_opt {
                                                        has_monitor_update = true;
 
-                                                       let update_res = self.chain_monitor.update_channel(
-                                                               funding_txo.expect("channel is live"), monitor_update);
-                                                       let update_id = monitor_update.update_id;
                                                        let channel_id: [u8; 32] = *channel_id;
-                                                       let res = handle_new_monitor_update!(self, update_res, update_id,
+                                                       let res = handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
                                                                peer_state_lock, peer_state, per_peer_state, chan, MANUALLY_REMOVING,
                                                                peer_state.channel_by_id.remove(&channel_id));
                                                        if res.is_err() {
@@ -6005,37 +6315,6 @@ where
                }
        }
 
-       fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option<PaymentPreimage>, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<PaymentSecret, APIError> {
-               assert!(invoice_expiry_delta_secs <= 60*60*24*365); // Sadly bitcoin timestamps are u32s, so panic before 2106
-
-               if min_value_msat.is_some() && min_value_msat.unwrap() > MAX_VALUE_MSAT {
-                       return Err(APIError::APIMisuseError { err: format!("min_value_msat of {} greater than total 21 million bitcoin supply", min_value_msat.unwrap()) });
-               }
-
-               let payment_secret = PaymentSecret(self.entropy_source.get_secure_random_bytes());
-
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
-               let mut payment_secrets = self.pending_inbound_payments.lock().unwrap();
-               match payment_secrets.entry(payment_hash) {
-                       hash_map::Entry::Vacant(e) => {
-                               e.insert(PendingInboundPayment {
-                                       payment_secret, min_value_msat, payment_preimage,
-                                       user_payment_id: 0, // For compatibility with version 0.0.103 and earlier
-                                       // We assume that highest_seen_timestamp is pretty close to the current time -
-                                       // it's updated when we receive a new block with the maximum time we've seen in
-                                       // a header. It should never be more than two hours in the future.
-                                       // Thus, we add two hours here as a buffer to ensure we absolutely
-                                       // never fail a payment too early.
-                                       // Note that we assume that received blocks have reasonably up-to-date
-                                       // timestamps.
-                                       expiry_time: self.highest_seen_timestamp.load(Ordering::Acquire) as u64 + invoice_expiry_delta_secs as u64 + 7200,
-                               });
-                       },
-                       hash_map::Entry::Occupied(_) => return Err(APIError::APIMisuseError { err: "Duplicate payment hash".to_owned() }),
-               }
-               Ok(payment_secret)
-       }
-
        /// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
        /// to pay us.
        ///
@@ -6075,23 +6354,6 @@ where
                        min_final_cltv_expiry_delta)
        }
 
-       /// Legacy version of [`create_inbound_payment`]. Use this method if you wish to share
-       /// serialized state with LDK node(s) running 0.0.103 and earlier.
-       ///
-       /// May panic if `invoice_expiry_delta_secs` is greater than one year.
-       ///
-       /// # Note
-       /// This method is deprecated and will be removed soon.
-       ///
-       /// [`create_inbound_payment`]: Self::create_inbound_payment
-       #[deprecated]
-       pub fn create_inbound_payment_legacy(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<(PaymentHash, PaymentSecret), APIError> {
-               let payment_preimage = PaymentPreimage(self.entropy_source.get_secure_random_bytes());
-               let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
-               let payment_secret = self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs)?;
-               Ok((payment_hash, payment_secret))
-       }
-
        /// Gets a [`PaymentSecret`] for a given [`PaymentHash`], for which the payment preimage is
        /// stored external to LDK.
        ///
@@ -6145,20 +6407,6 @@ where
                        min_final_cltv_expiry)
        }
 
-       /// Legacy version of [`create_inbound_payment_for_hash`]. Use this method if you wish to share
-       /// serialized state with LDK node(s) running 0.0.103 and earlier.
-       ///
-       /// May panic if `invoice_expiry_delta_secs` is greater than one year.
-       ///
-       /// # Note
-       /// This method is deprecated and will be removed soon.
-       ///
-       /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
-       #[deprecated]
-       pub fn create_inbound_payment_for_hash_legacy(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<PaymentSecret, APIError> {
-               self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs)
-       }
-
        /// Gets an LDK-generated payment preimage from a payment hash and payment secret that were
        /// previously returned from [`create_inbound_payment`].
        ///
@@ -6233,7 +6481,7 @@ where
                inflight_htlcs
        }
 
-       #[cfg(any(test, fuzzing, feature = "_test_utils"))]
+       #[cfg(any(test, feature = "_test_utils"))]
        pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
                let events = core::cell::RefCell::new(Vec::new());
                let event_handler = |event: events::Event| events.borrow_mut().push(event);
@@ -6266,7 +6514,7 @@ where
        /// When something which was blocking a channel from updating its [`ChannelMonitor`] (e.g. an
        /// [`Event`] being handled) completes, this should be called to restore the channel to normal
        /// operation. It will double-check that nothing *else* is also blocking the same channel from
-       /// making progress and then any blocked [`ChannelMonitorUpdate`]s fly.
+       /// making progress and then let any blocked [`ChannelMonitorUpdate`]s fly.
        fn handle_monitor_update_release(&self, counterparty_node_id: PublicKey, channel_funding_outpoint: OutPoint, mut completed_blocker: Option<RAAMonitorUpdateBlockingAction>) {
                let mut errors = Vec::new();
                loop {
@@ -6299,9 +6547,7 @@ where
                                        if let Some((monitor_update, further_update_exists)) = chan.get_mut().unblock_next_blocked_monitor_update() {
                                                log_debug!(self.logger, "Unlocking monitor updating for channel {} and updating monitor",
                                                        log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
-                                               let update_res = self.chain_monitor.update_channel(channel_funding_outpoint, monitor_update);
-                                               let update_id = monitor_update.update_id;
-                                               if let Err(e) = handle_new_monitor_update!(self, update_res, update_id,
+                                               if let Err(e) = handle_new_monitor_update!(self, channel_funding_outpoint, monitor_update,
                                                        peer_state_lck, peer_state, per_peer_state, chan)
                                                {
                                                        errors.push((e, counterparty_node_id));
@@ -6763,13 +7009,13 @@ where
                provided_node_features(&self.default_configuration)
        }
 
-       /// Fetches the set of [`InvoiceFeatures`] flags which are provided by or required by
+       /// Fetches the set of [`Bolt11InvoiceFeatures`] flags which are provided by or required by
        /// [`ChannelManager`].
        ///
        /// Note that the invoice feature flags can vary depending on if the invoice is a "phantom invoice"
        /// or not. Thus, this method is not public.
        #[cfg(any(feature = "_test_utils", test))]
-       pub fn invoice_features(&self) -> InvoiceFeatures {
+       pub fn invoice_features(&self) -> Bolt11InvoiceFeatures {
                provided_invoice_features(&self.default_configuration)
        }
 
@@ -7022,6 +7268,7 @@ where
                                                inbound_v1_channel_by_id: HashMap::new(),
                                                latest_features: init_msg.features.clone(),
                                                pending_msg_events: Vec::new(),
+                                               in_flight_monitor_updates: BTreeMap::new(),
                                                monitor_update_blocked_actions: BTreeMap::new(),
                                                actions_blocking_raa_monitor_updates: BTreeMap::new(),
                                                is_connected: true,
@@ -7048,37 +7295,20 @@ where
                log_debug!(self.logger, "Generating channel_reestablish events for {}", log_pubkey!(counterparty_node_id));
 
                let per_peer_state = self.per_peer_state.read().unwrap();
-               for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
+               if let Some(peer_state_mutex) = per_peer_state.get(counterparty_node_id) {
                        let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                        let peer_state = &mut *peer_state_lock;
                        let pending_msg_events = &mut peer_state.pending_msg_events;
-                       peer_state.channel_by_id.retain(|_, chan| {
-                               let retain = if chan.context.get_counterparty_node_id() == *counterparty_node_id {
-                                       if !chan.context.have_received_message() {
-                                               // If we created this (outbound) channel while we were disconnected from the
-                                               // peer we probably failed to send the open_channel message, which is now
-                                               // lost. We can't have had anything pending related to this channel, so we just
-                                               // drop it.
-                                               false
-                                       } else {
-                                               pending_msg_events.push(events::MessageSendEvent::SendChannelReestablish {
-                                                       node_id: chan.context.get_counterparty_node_id(),
-                                                       msg: chan.get_channel_reestablish(&self.logger),
-                                               });
-                                               true
-                                       }
-                               } else { true };
-                               if retain && chan.context.get_counterparty_node_id() != *counterparty_node_id {
-                                       if let Some(msg) = chan.get_signed_channel_announcement(&self.node_signer, self.genesis_hash.clone(), self.best_block.read().unwrap().height(), &self.default_configuration) {
-                                               if let Ok(update_msg) = self.get_channel_update_for_broadcast(chan) {
-                                                       pending_msg_events.push(events::MessageSendEvent::SendChannelAnnouncement {
-                                                               node_id: *counterparty_node_id,
-                                                               msg, update_msg,
-                                                       });
-                                               }
-                                       }
-                               }
-                               retain
+
+                       // Since unfunded channel maps are cleared upon disconnecting a peer, and they're not persisted
+                       // (so won't be recovered after a crash) we don't need to bother closing unfunded channels and
+                       // clearing their maps here. Instead we can just send queue channel_reestablish messages for
+                       // channels in the channel_by_id map.
+                       peer_state.channel_by_id.iter_mut().for_each(|(_, chan)| {
+                               pending_msg_events.push(events::MessageSendEvent::SendChannelReestablish {
+                                       node_id: chan.context.get_counterparty_node_id(),
+                                       msg: chan.get_channel_reestablish(&self.logger),
+                               });
                        });
                }
                //TODO: Also re-broadcast announcement_signatures
@@ -7112,7 +7342,7 @@ where
                                let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
                                let peer_state = &mut *peer_state_lock;
                                if let Some(chan) = peer_state.outbound_v1_channel_by_id.get_mut(&msg.channel_id) {
-                                       if let Ok(msg) = chan.maybe_handle_error_without_close(self.genesis_hash) {
+                                       if let Ok(msg) = chan.maybe_handle_error_without_close(self.genesis_hash, &self.fee_estimator) {
                                                peer_state.pending_msg_events.push(events::MessageSendEvent::SendOpenChannel {
                                                        node_id: *counterparty_node_id,
                                                        msg,
@@ -7200,13 +7430,13 @@ pub(crate) fn provided_node_features(config: &UserConfig) -> NodeFeatures {
        provided_init_features(config).to_context()
 }
 
-/// Fetches the set of [`InvoiceFeatures`] flags which are provided by or required by
+/// Fetches the set of [`Bolt11InvoiceFeatures`] flags which are provided by or required by
 /// [`ChannelManager`].
 ///
 /// Note that the invoice feature flags can vary depending on if the invoice is a "phantom invoice"
 /// or not. Thus, this method is not public.
 #[cfg(any(feature = "_test_utils", test))]
-pub(crate) fn provided_invoice_features(config: &UserConfig) -> InvoiceFeatures {
+pub(crate) fn provided_invoice_features(config: &UserConfig) -> Bolt11InvoiceFeatures {
        provided_init_features(config).to_context()
 }
 
@@ -7224,7 +7454,7 @@ pub(crate) fn provided_channel_type_features(config: &UserConfig) -> ChannelType
 
 /// Fetches the set of [`InitFeatures`] flags which are provided by or required by
 /// [`ChannelManager`].
-pub fn provided_init_features(_config: &UserConfig) -> InitFeatures {
+pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
        // Note that if new features are added here which other peers may (eventually) require, we
        // should also add the corresponding (optional) bit to the [`ChannelMessageHandler`] impl for
        // [`ErroringMessageHandler`].
@@ -7240,11 +7470,8 @@ pub fn provided_init_features(_config: &UserConfig) -> InitFeatures {
        features.set_channel_type_optional();
        features.set_scid_privacy_optional();
        features.set_zero_conf_optional();
-       #[cfg(anchors)]
-       { // Attributes are not allowed on if expressions on our current MSRV of 1.41.
-               if _config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx {
-                       features.set_anchors_zero_fee_htlc_tx_optional();
-               }
+       if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx {
+               features.set_anchors_zero_fee_htlc_tx_optional();
        }
        features
 }
@@ -7301,6 +7528,7 @@ impl Writeable for ChannelDetails {
                        (35, self.inbound_htlc_maximum_msat, option),
                        (37, user_channel_id_high_opt, option),
                        (39, self.feerate_sat_per_1000_weight, option),
+                       (41, self.channel_shutdown_state, option),
                });
                Ok(())
        }
@@ -7338,6 +7566,7 @@ impl Readable for ChannelDetails {
                        (35, inbound_htlc_maximum_msat, option),
                        (37, user_channel_id_high_opt, option),
                        (39, feerate_sat_per_1000_weight, option),
+                       (41, channel_shutdown_state, option),
                });
 
                // `user_channel_id` used to be a single u64 value. In order to remain backwards compatible with
@@ -7373,12 +7602,13 @@ impl Readable for ChannelDetails {
                        inbound_htlc_minimum_msat,
                        inbound_htlc_maximum_msat,
                        feerate_sat_per_1000_weight,
+                       channel_shutdown_state,
                })
        }
 }
 
 impl_writeable_tlv_based!(PhantomRouteHints, {
-       (2, channels, vec_type),
+       (2, channels, required_vec),
        (4, phantom_scid, required),
        (6, real_node_pubkey, required),
 });
@@ -7409,6 +7639,7 @@ impl_writeable_tlv_based!(PendingHTLCInfo, {
        (6, outgoing_amt_msat, required),
        (8, outgoing_cltv_value, required),
        (9, incoming_amt_msat, option),
+       (10, skimmed_fee_msat, option),
 });
 
 
@@ -7507,6 +7738,7 @@ impl Writeable for ClaimableHTLC {
                        (5, self.total_value_received, option),
                        (6, self.cltv_expiry, required),
                        (8, keysend_preimage, option),
+                       (10, self.counterparty_skimmed_fee_msat, option),
                });
                Ok(())
        }
@@ -7514,24 +7746,19 @@ impl Writeable for ClaimableHTLC {
 
 impl Readable for ClaimableHTLC {
        fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
-               let mut prev_hop = crate::util::ser::RequiredWrapper(None);
-               let mut value = 0;
-               let mut sender_intended_value = None;
-               let mut payment_data: Option<msgs::FinalOnionHopData> = None;
-               let mut cltv_expiry = 0;
-               let mut total_value_received = None;
-               let mut total_msat = None;
-               let mut keysend_preimage: Option<PaymentPreimage> = None;
-               read_tlv_fields!(reader, {
+               _init_and_read_tlv_fields!(reader, {
                        (0, prev_hop, required),
                        (1, total_msat, option),
-                       (2, value, required),
+                       (2, value_ser, required),
                        (3, sender_intended_value, option),
-                       (4, payment_data, option),
+                       (4, payment_data_opt, option),
                        (5, total_value_received, option),
                        (6, cltv_expiry, required),
-                       (8, keysend_preimage, option)
+                       (8, keysend_preimage, option),
+                       (10, counterparty_skimmed_fee_msat, option),
                });
+               let payment_data: Option<msgs::FinalOnionHopData> = payment_data_opt;
+               let value = value_ser.0.unwrap();
                let onion_payload = match keysend_preimage {
                        Some(p) => {
                                if payment_data.is_some() {
@@ -7560,7 +7787,8 @@ impl Readable for ClaimableHTLC {
                        total_value_received,
                        total_msat: total_msat.unwrap(),
                        onion_payload,
-                       cltv_expiry,
+                       cltv_expiry: cltv_expiry.0.unwrap(),
+                       counterparty_skimmed_fee_msat,
                })
        }
 }
@@ -7572,7 +7800,7 @@ impl Readable for HTLCSource {
                        0 => {
                                let mut session_priv: crate::util::ser::RequiredWrapper<SecretKey> = crate::util::ser::RequiredWrapper(None);
                                let mut first_hop_htlc_msat: u64 = 0;
-                               let mut path_hops: Option<Vec<RouteHop>> = Some(Vec::new());
+                               let mut path_hops = Vec::new();
                                let mut payment_id = None;
                                let mut payment_params: Option<PaymentParameters> = None;
                                let mut blinded_tail: Option<BlindedTail> = None;
@@ -7580,7 +7808,7 @@ impl Readable for HTLCSource {
                                        (0, session_priv, required),
                                        (1, payment_id, option),
                                        (2, first_hop_htlc_msat, required),
-                                       (4, path_hops, vec_type),
+                                       (4, path_hops, required_vec),
                                        (5, payment_params, (option: ReadableArgs, 0)),
                                        (6, blinded_tail, option),
                                });
@@ -7589,7 +7817,7 @@ impl Readable for HTLCSource {
                                        // instead.
                                        payment_id = Some(PaymentId(*session_priv.0.unwrap().as_ref()));
                                }
-                               let path = Path { hops: path_hops.ok_or(DecodeError::InvalidValue)?, blinded_tail };
+                               let path = Path { hops: path_hops, blinded_tail };
                                if path.hops.len() == 0 {
                                        return Err(DecodeError::InvalidValue);
                                }
@@ -7624,7 +7852,7 @@ impl Writeable for HTLCSource {
                                        (1, payment_id_opt, option),
                                        (2, first_hop_htlc_msat, required),
                                        // 3 was previously used to write a PaymentSecret for the payment.
-                                       (4, path.hops, vec_type),
+                                       (4, path.hops, required_vec),
                                        (5, None::<PaymentParameters>, option), // payment_params in LDK versions prior to 0.0.115
                                        (6, path.blinded_tail, option),
                                 });
@@ -7855,6 +8083,16 @@ where
                        pending_claiming_payments = None;
                }
 
+               let mut in_flight_monitor_updates: Option<HashMap<(&PublicKey, &OutPoint), &Vec<ChannelMonitorUpdate>>> = None;
+               for ((counterparty_id, _), peer_state) in per_peer_state.iter().zip(peer_states.iter()) {
+                       for (funding_outpoint, updates) in peer_state.in_flight_monitor_updates.iter() {
+                               if !updates.is_empty() {
+                                       if in_flight_monitor_updates.is_none() { in_flight_monitor_updates = Some(HashMap::new()); }
+                                       in_flight_monitor_updates.as_mut().unwrap().insert((counterparty_id, funding_outpoint), updates);
+                               }
+                       }
+               }
+
                write_tlv_fields!(writer, {
                        (1, pending_outbound_payments_no_retry, required),
                        (2, pending_intercepted_htlcs, option),
@@ -7864,7 +8102,8 @@ where
                        (6, monitor_update_blocked_actions_per_peer, option),
                        (7, self.fake_scid_rand_bytes, required),
                        (8, if events_not_backwards_compatible { Some(&*events) } else { None }, option),
-                       (9, htlc_purposes, vec_type),
+                       (9, htlc_purposes, required_vec),
+                       (10, in_flight_monitor_updates, option),
                        (11, self.probing_cookie_secret, required),
                        (13, htlc_onion_fields, optional_vec),
                });
@@ -7914,6 +8153,14 @@ impl Readable for VecDeque<(Event, Option<EventCompletionAction>)> {
        }
 }
 
+impl_writeable_tlv_based_enum!(ChannelShutdownState,
+       (0, NotShuttingDown) => {},
+       (2, ShutdownInitiated) => {},
+       (4, ResolvingHTLCs) => {},
+       (6, NegotiatingClosingFee) => {},
+       (8, ShutdownComplete) => {}, ;
+);
+
 /// Arguments for the creation of a ChannelManager that are not deserialized.
 ///
 /// At a high-level, the process for deserializing a ChannelManager and resuming normal operation
@@ -8081,7 +8328,7 @@ where
                let mut id_to_peer = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
                let mut short_to_chan_info = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
                let mut channel_closures = VecDeque::new();
-               let mut pending_background_events = Vec::new();
+               let mut close_background_events = Vec::new();
                for _ in 0..channel_count {
                        let mut channel: Channel<<SP::Target as SignerProvider>::Signer> = Channel::read(reader, (
                                &args.entropy_source, &args.signer_provider, best_block_height, &provided_channel_type_features(&args.default_config)
@@ -8089,17 +8336,7 @@ where
                        let funding_txo = channel.context.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
                        funding_txo_set.insert(funding_txo.clone());
                        if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
-                               if channel.get_latest_complete_monitor_update_id() > monitor.get_latest_update_id() {
-                                       // If the channel is ahead of the monitor, return InvalidValue:
-                                       log_error!(args.logger, "A ChannelMonitor is stale compared to the current ChannelManager! This indicates a potentially-critical violation of the chain::Watch API!");
-                                       log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} but the ChannelManager is at update_id {}.",
-                                               log_bytes!(channel.context.channel_id()), monitor.get_latest_update_id(), channel.get_latest_complete_monitor_update_id());
-                                       log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
-                                       log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
-                                       log_error!(args.logger, " Without the latest ChannelMonitor we cannot continue without risking funds.");
-                                       log_error!(args.logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/lightningdevkit/rust-lightning");
-                                       return Err(DecodeError::InvalidValue);
-                               } else if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() ||
+                               if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() ||
                                                channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() ||
                                                channel.get_cur_counterparty_commitment_transaction_number() > monitor.get_cur_counterparty_commitment_number() ||
                                                channel.context.get_latest_monitor_update_id() < monitor.get_latest_update_id() {
@@ -8110,7 +8347,7 @@ where
                                                log_bytes!(channel.context.channel_id()), monitor.get_latest_update_id(), channel.context.get_latest_monitor_update_id());
                                        let (monitor_update, mut new_failed_htlcs) = channel.context.force_shutdown(true);
                                        if let Some((counterparty_node_id, funding_txo, update)) = monitor_update {
-                                               pending_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
+                                               close_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
                                                        counterparty_node_id, funding_txo, update
                                                });
                                        }
@@ -8143,7 +8380,6 @@ where
                                        log_info!(args.logger, "Successfully loaded channel {} at update_id {} against monitor at update id {}",
                                                log_bytes!(channel.context.channel_id()), channel.context.get_latest_monitor_update_id(),
                                                monitor.get_latest_update_id());
-                                       channel.complete_all_mon_updates_through(monitor.get_latest_update_id());
                                        if let Some(short_channel_id) = channel.context.get_short_channel_id() {
                                                short_to_chan_info.insert(short_channel_id, (channel.context.get_counterparty_node_id(), channel.context.channel_id()));
                                        }
@@ -8190,7 +8426,7 @@ where
                                        update_id: CLOSED_CHANNEL_UPDATE_ID,
                                        updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast: true }],
                                };
-                               pending_background_events.push(BackgroundEvent::ClosingMonitorUpdateRegeneratedOnStartup((*funding_txo, monitor_update)));
+                               close_background_events.push(BackgroundEvent::ClosedMonitorUpdateRegeneratedOnStartup((*funding_txo, monitor_update)));
                        }
                }
 
@@ -8219,20 +8455,27 @@ where
                        claimable_htlcs_list.push((payment_hash, previous_hops));
                }
 
-               let peer_count: u64 = Readable::read(reader)?;
-               let mut per_peer_state = HashMap::with_capacity(cmp::min(peer_count as usize, MAX_ALLOC_SIZE/mem::size_of::<(PublicKey, Mutex<PeerState<<SP::Target as SignerProvider>::Signer>>)>()));
-               for _ in 0..peer_count {
-                       let peer_pubkey = Readable::read(reader)?;
-                       let peer_state = PeerState {
-                               channel_by_id: peer_channels.remove(&peer_pubkey).unwrap_or(HashMap::new()),
+               let peer_state_from_chans = |channel_by_id| {
+                       PeerState {
+                               channel_by_id,
                                outbound_v1_channel_by_id: HashMap::new(),
                                inbound_v1_channel_by_id: HashMap::new(),
-                               latest_features: Readable::read(reader)?,
+                               latest_features: InitFeatures::empty(),
                                pending_msg_events: Vec::new(),
+                               in_flight_monitor_updates: BTreeMap::new(),
                                monitor_update_blocked_actions: BTreeMap::new(),
                                actions_blocking_raa_monitor_updates: BTreeMap::new(),
                                is_connected: false,
-                       };
+                       }
+               };
+
+               let peer_count: u64 = Readable::read(reader)?;
+               let mut per_peer_state = HashMap::with_capacity(cmp::min(peer_count as usize, MAX_ALLOC_SIZE/mem::size_of::<(PublicKey, Mutex<PeerState<<SP::Target as SignerProvider>::Signer>>)>()));
+               for _ in 0..peer_count {
+                       let peer_pubkey = Readable::read(reader)?;
+                       let peer_chans = peer_channels.remove(&peer_pubkey).unwrap_or(HashMap::new());
+                       let mut peer_state = peer_state_from_chans(peer_chans);
+                       peer_state.latest_features = Readable::read(reader)?;
                        per_peer_state.insert(peer_pubkey, Mutex::new(peer_state));
                }
 
@@ -8260,24 +8503,6 @@ where
                        }
                }
 
-               for (node_id, peer_mtx) in per_peer_state.iter() {
-                       let peer_state = peer_mtx.lock().unwrap();
-                       for (_, chan) in peer_state.channel_by_id.iter() {
-                               for update in chan.uncompleted_unblocked_mon_updates() {
-                                       if let Some(funding_txo) = chan.context.get_funding_txo() {
-                                               log_trace!(args.logger, "Replaying ChannelMonitorUpdate {} for channel {}",
-                                                       update.update_id, log_bytes!(funding_txo.to_channel_id()));
-                                               pending_background_events.push(
-                                                       BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
-                                                               counterparty_node_id: *node_id, funding_txo, update: update.clone(),
-                                                       });
-                                       } else {
-                                               return Err(DecodeError::InvalidValue);
-                                       }
-                               }
-                       }
-               }
-
                let _last_node_announcement_serial: u32 = Readable::read(reader)?; // Only used < 0.0.111
                let highest_seen_timestamp: u32 = Readable::read(reader)?;
 
@@ -8314,6 +8539,7 @@ where
                let mut pending_claiming_payments = Some(HashMap::new());
                let mut monitor_update_blocked_actions_per_peer: Option<Vec<(_, BTreeMap<_, Vec<_>>)>> = Some(Vec::new());
                let mut events_override = None;
+               let mut in_flight_monitor_updates: Option<HashMap<(PublicKey, OutPoint), Vec<ChannelMonitorUpdate>>> = None;
                read_tlv_fields!(reader, {
                        (1, pending_outbound_payments_no_retry, option),
                        (2, pending_intercepted_htlcs, option),
@@ -8323,7 +8549,8 @@ where
                        (6, monitor_update_blocked_actions_per_peer, option),
                        (7, fake_scid_rand_bytes, option),
                        (8, events_override, option),
-                       (9, claimable_htlc_purposes, vec_type),
+                       (9, claimable_htlc_purposes, optional_vec),
+                       (10, in_flight_monitor_updates, option),
                        (11, probing_cookie_secret, option),
                        (13, claimable_htlc_onion_fields, optional_vec),
                });
@@ -8357,6 +8584,118 @@ where
                        retry_lock: Mutex::new(())
                };
 
+               // We have to replay (or skip, if they were completed after we wrote the `ChannelManager`)
+               // each `ChannelMonitorUpdate` in `in_flight_monitor_updates`. After doing so, we have to
+               // check that each channel we have isn't newer than the latest `ChannelMonitorUpdate`(s) we
+               // replayed, and for each monitor update we have to replay we have to ensure there's a
+               // `ChannelMonitor` for it.
+               //
+               // In order to do so we first walk all of our live channels (so that we can check their
+               // state immediately after doing the update replays, when we have the `update_id`s
+               // available) and then walk any remaining in-flight updates.
+               //
+               // Because the actual handling of the in-flight updates is the same, it's macro'ized here:
+               let mut pending_background_events = Vec::new();
+               macro_rules! handle_in_flight_updates {
+                       ($counterparty_node_id: expr, $chan_in_flight_upds: expr, $funding_txo: expr,
+                        $monitor: expr, $peer_state: expr, $channel_info_log: expr
+                       ) => { {
+                               let mut max_in_flight_update_id = 0;
+                               $chan_in_flight_upds.retain(|upd| upd.update_id > $monitor.get_latest_update_id());
+                               for update in $chan_in_flight_upds.iter() {
+                                       log_trace!(args.logger, "Replaying ChannelMonitorUpdate {} for {}channel {}",
+                                               update.update_id, $channel_info_log, log_bytes!($funding_txo.to_channel_id()));
+                                       max_in_flight_update_id = cmp::max(max_in_flight_update_id, update.update_id);
+                                       pending_background_events.push(
+                                               BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
+                                                       counterparty_node_id: $counterparty_node_id,
+                                                       funding_txo: $funding_txo,
+                                                       update: update.clone(),
+                                               });
+                               }
+                               if $chan_in_flight_upds.is_empty() {
+                                       // We had some updates to apply, but it turns out they had completed before we
+                                       // were serialized, we just weren't notified of that. Thus, we may have to run
+                                       // the completion actions for any monitor updates, but otherwise are done.
+                                       pending_background_events.push(
+                                               BackgroundEvent::MonitorUpdatesComplete {
+                                                       counterparty_node_id: $counterparty_node_id,
+                                                       channel_id: $funding_txo.to_channel_id(),
+                                               });
+                               }
+                               if $peer_state.in_flight_monitor_updates.insert($funding_txo, $chan_in_flight_upds).is_some() {
+                                       log_error!(args.logger, "Duplicate in-flight monitor update set for the same channel!");
+                                       return Err(DecodeError::InvalidValue);
+                               }
+                               max_in_flight_update_id
+                       } }
+               }
+
+               for (counterparty_id, peer_state_mtx) in per_peer_state.iter_mut() {
+                       let mut peer_state_lock = peer_state_mtx.lock().unwrap();
+                       let peer_state = &mut *peer_state_lock;
+                       for (_, chan) in peer_state.channel_by_id.iter() {
+                               // Channels that were persisted have to be funded, otherwise they should have been
+                               // discarded.
+                               let funding_txo = chan.context.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
+                               let monitor = args.channel_monitors.get(&funding_txo)
+                                       .expect("We already checked for monitor presence when loading channels");
+                               let mut max_in_flight_update_id = monitor.get_latest_update_id();
+                               if let Some(in_flight_upds) = &mut in_flight_monitor_updates {
+                                       if let Some(mut chan_in_flight_upds) = in_flight_upds.remove(&(*counterparty_id, funding_txo)) {
+                                               max_in_flight_update_id = cmp::max(max_in_flight_update_id,
+                                                       handle_in_flight_updates!(*counterparty_id, chan_in_flight_upds,
+                                                               funding_txo, monitor, peer_state, ""));
+                                       }
+                               }
+                               if chan.get_latest_unblocked_monitor_update_id() > max_in_flight_update_id {
+                                       // If the channel is ahead of the monitor, return InvalidValue:
+                                       log_error!(args.logger, "A ChannelMonitor is stale compared to the current ChannelManager! This indicates a potentially-critical violation of the chain::Watch API!");
+                                       log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} with update_id through {} in-flight",
+                                               log_bytes!(chan.context.channel_id()), monitor.get_latest_update_id(), max_in_flight_update_id);
+                                       log_error!(args.logger, " but the ChannelManager is at update_id {}.", chan.get_latest_unblocked_monitor_update_id());
+                                       log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
+                                       log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
+                                       log_error!(args.logger, " Without the latest ChannelMonitor we cannot continue without risking funds.");
+                                       log_error!(args.logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/lightningdevkit/rust-lightning");
+                                       return Err(DecodeError::InvalidValue);
+                               }
+                       }
+               }
+
+               if let Some(in_flight_upds) = in_flight_monitor_updates {
+                       for ((counterparty_id, funding_txo), mut chan_in_flight_updates) in in_flight_upds {
+                               if let Some(monitor) = args.channel_monitors.get(&funding_txo) {
+                                       // Now that we've removed all the in-flight monitor updates for channels that are
+                                       // still open, we need to replay any monitor updates that are for closed channels,
+                                       // creating the neccessary peer_state entries as we go.
+                                       let peer_state_mutex = per_peer_state.entry(counterparty_id).or_insert_with(|| {
+                                               Mutex::new(peer_state_from_chans(HashMap::new()))
+                                       });
+                                       let mut peer_state = peer_state_mutex.lock().unwrap();
+                                       handle_in_flight_updates!(counterparty_id, chan_in_flight_updates,
+                                               funding_txo, monitor, peer_state, "closed ");
+                               } else {
+                                       log_error!(args.logger, "A ChannelMonitor is missing even though we have in-flight updates for it! This indicates a potentially-critical violation of the chain::Watch API!");
+                                       log_error!(args.logger, " The ChannelMonitor for channel {} is missing.",
+                                               log_bytes!(funding_txo.to_channel_id()));
+                                       log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
+                                       log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
+                                       log_error!(args.logger, " Without the latest ChannelMonitor we cannot continue without risking funds.");
+                                       log_error!(args.logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/lightningdevkit/rust-lightning");
+                                       return Err(DecodeError::InvalidValue);
+                               }
+                       }
+               }
+
+               // Note that we have to do the above replays before we push new monitor updates.
+               pending_background_events.append(&mut close_background_events);
+
+               // If there's any preimages for forwarded HTLCs hanging around in ChannelMonitors we
+               // should ensure we try them again on the inbound edge. We put them here and do so after we
+               // have a fully-constructed `ChannelManager` at the end.
+               let mut pending_claims_to_replay = Vec::new();
+
                {
                        // If we're tracking pending payments, ensure we haven't lost any by looking at the
                        // ChannelMonitor data for any channels for which we do not have authorative state
@@ -8367,7 +8706,8 @@ where
                        // We only rebuild the pending payments map if we were most recently serialized by
                        // 0.0.102+
                        for (_, monitor) in args.channel_monitors.iter() {
-                               if id_to_peer.get(&monitor.get_funding_txo().0.to_channel_id()).is_none() {
+                               let counterparty_opt = id_to_peer.get(&monitor.get_funding_txo().0.to_channel_id());
+                               if counterparty_opt.is_none() {
                                        for (htlc_source, (htlc, _)) in monitor.get_pending_or_resolved_outbound_htlcs() {
                                                if let HTLCSource::OutboundRoute { payment_id, session_priv, path, .. } = htlc_source {
                                                        if path.hops.is_empty() {
@@ -8461,6 +8801,33 @@ where
                                                }
                                        }
                                }
+
+                               // Whether the downstream channel was closed or not, try to re-apply any payment
+                               // preimages from it which may be needed in upstream channels for forwarded
+                               // payments.
+                               let outbound_claimed_htlcs_iter = monitor.get_all_current_outbound_htlcs()
+                                       .into_iter()
+                                       .filter_map(|(htlc_source, (htlc, preimage_opt))| {
+                                               if let HTLCSource::PreviousHopData(_) = htlc_source {
+                                                       if let Some(payment_preimage) = preimage_opt {
+                                                               Some((htlc_source, payment_preimage, htlc.amount_msat,
+                                                                       // Check if `counterparty_opt.is_none()` to see if the
+                                                                       // downstream chan is closed (because we don't have a
+                                                                       // channel_id -> peer map entry).
+                                                                       counterparty_opt.is_none(),
+                                                                       monitor.get_funding_txo().0.to_channel_id()))
+                                                       } else { None }
+                                               } else {
+                                                       // If it was an outbound payment, we've handled it above - if a preimage
+                                                       // came in and we persisted the `ChannelManager` we either handled it and
+                                                       // are good to go or the channel force-closed - we don't have to handle the
+                                                       // channel still live case here.
+                                                       None
+                                               }
+                                       });
+                               for tuple in outbound_claimed_htlcs_iter {
+                                       pending_claims_to_replay.push(tuple);
+                               }
                        }
                }
 
@@ -8648,6 +9015,12 @@ where
                                                                blocked_peer_state.lock().unwrap().actions_blocking_raa_monitor_updates
                                                                        .entry(blocked_channel_outpoint.to_channel_id())
                                                                        .or_insert_with(Vec::new).push(blocking_action.clone());
+                                                       } else {
+                                                               // If the channel we were blocking has closed, we don't need to
+                                                               // worry about it - the blocked monitor update should never have
+                                                               // been released from the `Channel` object so it can't have
+                                                               // completed, and if the channel closed there's no reason to bother
+                                                               // anymore.
                                                        }
                                                }
                                        }
@@ -8693,7 +9066,6 @@ where
                        pending_events_processor: AtomicBool::new(false),
                        pending_background_events: Mutex::new(pending_background_events),
                        total_consistency_lock: RwLock::new(()),
-                       #[cfg(debug_assertions)]
                        background_events_processed_since_startup: AtomicBool::new(false),
                        persistence_notifier: Notifier::new(),
 
@@ -8712,6 +9084,14 @@ where
                        channel_manager.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
                }
 
+               for (source, preimage, downstream_value, downstream_closed, downstream_chan_id) in pending_claims_to_replay {
+                       // We use `downstream_closed` in place of `from_onchain` here just as a guess - we
+                       // don't remember in the `ChannelMonitor` where we got a preimage from, but if the
+                       // channel is closed we just assume that it probably came from an on-chain claim.
+                       channel_manager.claim_funds_internal(source, preimage, Some(downstream_value),
+                               downstream_closed, downstream_chan_id);
+               }
+
                //TODO: Broadcast channel update for closed channels, but only after we've made a
                //connection or two.
 
@@ -8729,7 +9109,7 @@ mod tests {
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use crate::ln::channelmanager::{inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId};
        use crate::ln::functional_test_utils::*;
-       use crate::ln::msgs;
+       use crate::ln::msgs::{self, ErrorAction};
        use crate::ln::msgs::ChannelMessageHandler;
        use crate::routing::router::{PaymentParameters, RouteParameters, find_route};
        use crate::util::errors::APIError;
@@ -9681,7 +10061,94 @@ mod tests {
                get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, last_random_pk);
        }
 
-       #[cfg(anchors)]
+       #[test]
+       fn reject_excessively_underpaying_htlcs() {
+               let chanmon_cfg = create_chanmon_cfgs(1);
+               let node_cfg = create_node_cfgs(1, &chanmon_cfg);
+               let node_chanmgr = create_node_chanmgrs(1, &node_cfg, &[None]);
+               let node = create_network(1, &node_cfg, &node_chanmgr);
+               let sender_intended_amt_msat = 100;
+               let extra_fee_msat = 10;
+               let hop_data = msgs::OnionHopData {
+                       amt_to_forward: 100,
+                       outgoing_cltv_value: 42,
+                       format: msgs::OnionHopDataFormat::FinalNode {
+                               keysend_preimage: None,
+                               payment_metadata: None,
+                               payment_data: Some(msgs::FinalOnionHopData {
+                                       payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
+                               }),
+                       }
+               };
+               // Check that if the amount we received + the penultimate hop extra fee is less than the sender
+               // intended amount, we fail the payment.
+               if let Err(crate::ln::channelmanager::ReceiveError { err_code, .. }) =
+                       node[0].node.construct_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
+                               sender_intended_amt_msat - extra_fee_msat - 1, 42, None, true, Some(extra_fee_msat))
+               {
+                       assert_eq!(err_code, 19);
+               } else { panic!(); }
+
+               // If amt_received + extra_fee is equal to the sender intended amount, we're fine.
+               let hop_data = msgs::OnionHopData { // This is the same hop_data as above, OnionHopData doesn't implement Clone
+                       amt_to_forward: 100,
+                       outgoing_cltv_value: 42,
+                       format: msgs::OnionHopDataFormat::FinalNode {
+                               keysend_preimage: None,
+                               payment_metadata: None,
+                               payment_data: Some(msgs::FinalOnionHopData {
+                                       payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
+                               }),
+                       }
+               };
+               assert!(node[0].node.construct_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
+                       sender_intended_amt_msat - extra_fee_msat, 42, None, true, Some(extra_fee_msat)).is_ok());
+       }
+
+       #[test]
+       fn test_inbound_anchors_manual_acceptance() {
+               // Tests that we properly limit inbound channels when we have the manual-channel-acceptance
+               // flag set and (sometimes) accept channels as 0conf.
+               let mut anchors_cfg = test_default_channel_config();
+               anchors_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+
+               let mut anchors_manual_accept_cfg = anchors_cfg.clone();
+               anchors_manual_accept_cfg.manually_accept_inbound_channels = true;
+
+               let chanmon_cfgs = create_chanmon_cfgs(3);
+               let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+               let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs,
+                       &[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();
+               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);
+               assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+               let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
+               match &msg_events[0] {
+                       MessageSendEvent::HandleError { node_id, action } => {
+                               assert_eq!(*node_id, nodes[0].node.get_our_node_id());
+                               match action {
+                                       ErrorAction::SendErrorMessage { msg } =>
+                                               assert_eq!(msg.data, "No channels with anchor outputs accepted".to_owned()),
+                                       _ => panic!("Unexpected error action"),
+                               }
+                       }
+                       _ => panic!("Unexpected event"),
+               }
+
+               nodes[2].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
+               let events = nodes[2].node.get_and_clear_pending_events();
+               match events[0] {
+                       Event::OpenChannelRequest { temporary_channel_id, .. } =>
+                               nodes[2].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23).unwrap(),
+                       _ => panic!("Unexpected event"),
+               }
+               get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
+       }
+
        #[test]
        fn test_anchors_zero_fee_htlc_tx_fallback() {
                // Tests that if both nodes support anchors, but the remote node does not want to accept
@@ -9771,6 +10238,25 @@ mod tests {
                        MessageSendEvent::BroadcastChannelUpdate { .. } => {},
                        _ => panic!("expected BroadcastChannelUpdate event"),
                }
+
+               // If we provide a channel_id not associated with the peer, we should get an error and no updates
+               // should be applied to ensure update atomicity as specified in the API docs.
+               let bad_channel_id = [10; 32];
+               let current_fee = nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_proportional_millionths;
+               let new_fee = current_fee + 100;
+               assert!(
+                       matches!(
+                               nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id, bad_channel_id], &ChannelConfigUpdate {
+                                       forwarding_fee_proportional_millionths: Some(new_fee),
+                                       ..Default::default()
+                               }),
+                               Err(APIError::ChannelUnavailable { err: _ }),
+                       )
+               );
+               // Check that the fee hasn't changed for the channel that exists.
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_proportional_millionths, current_fee);
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 0);
        }
 }
 
@@ -9786,7 +10272,7 @@ pub mod bench {
        use crate::routing::gossip::NetworkGraph;
        use crate::routing::router::{PaymentParameters, RouteParameters};
        use crate::util::test_utils;
-       use crate::util::config::UserConfig;
+       use crate::util::config::{UserConfig, MaxDustHTLCExposure};
 
        use bitcoin::hashes::Hash;
        use bitcoin::hashes::sha256::Hash as Sha256;
@@ -9824,6 +10310,7 @@ pub mod bench {
                // Note that this is unrealistic as each payment send will require at least two fsync
                // calls per node.
                let network = bitcoin::Network::Testnet;
+               let genesis_block = bitcoin::blockdata::constants::genesis_block(network);
 
                let tx_broadcaster = test_utils::TestBroadcaster::new(network);
                let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
@@ -9832,6 +10319,7 @@ pub mod bench {
                let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &scorer);
 
                let mut config: UserConfig = Default::default();
+               config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253);
                config.channel_handshake_config.minimum_depth = 1;
 
                let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a);
@@ -9840,7 +10328,7 @@ pub mod bench {
                let node_a = ChannelManager::new(&fee_estimator, &chain_monitor_a, &tx_broadcaster, &router, &logger_a, &keys_manager_a, &keys_manager_a, &keys_manager_a, config.clone(), ChainParameters {
                        network,
                        best_block: BestBlock::from_network(network),
-               });
+               }, genesis_block.header.time);
                let node_a_holder = ANodeHolder { node: &node_a };
 
                let logger_b = test_utils::TestLogger::with_id("node a".to_owned());
@@ -9850,7 +10338,7 @@ pub mod bench {
                let node_b = ChannelManager::new(&fee_estimator, &chain_monitor_b, &tx_broadcaster, &router, &logger_b, &keys_manager_b, &keys_manager_b, &keys_manager_b, config.clone(), ChainParameters {
                        network,
                        best_block: BestBlock::from_network(network),
-               });
+               }, genesis_block.header.time);
                let node_b_holder = ANodeHolder { node: &node_b };
 
                node_a.peer_connected(&node_b.get_our_node_id(), &Init {
index 41b15c97c9ae63c5aaae4f4f3ef1a810da11efaa..5de383b1f4469273207441892a90d1d2c063494d 100644 (file)
 //!     [BOLT-3](https://github.com/lightning/bolts/blob/master/03-transactions.md) for more
 //!     information).
 //!
+//! LDK knows about the following features, but does not support them:
+//! - `AnchorsNonzeroFeeHtlcTx` - the initial version of anchor outputs, which was later found to be
+//!     vulnerable (see this
+//!     [mailing list post](https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-September/002796.html)
+//!     for more information).
+//!
 //! [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md
 //! [messages]: crate::ln::msgs
 
 use crate::{io, io_extras};
 use crate::prelude::*;
 use core::{cmp, fmt};
+use core::borrow::Borrow;
 use core::hash::{Hash, Hasher};
 use core::marker::PhantomData;
 
@@ -134,7 +141,7 @@ mod sealed {
                // Byte 1
                VariableLengthOnion | StaticRemoteKey | PaymentSecret,
                // Byte 2
-               BasicMPP | Wumbo | AnchorsZeroFeeHtlcTx,
+               BasicMPP | Wumbo | AnchorsNonzeroFeeHtlcTx | AnchorsZeroFeeHtlcTx,
                // Byte 3
                ShutdownAnySegwit,
                // Byte 4
@@ -150,7 +157,7 @@ mod sealed {
                // Byte 1
                VariableLengthOnion | StaticRemoteKey | PaymentSecret,
                // Byte 2
-               BasicMPP | Wumbo | AnchorsZeroFeeHtlcTx,
+               BasicMPP | Wumbo | AnchorsNonzeroFeeHtlcTx | AnchorsZeroFeeHtlcTx,
                // Byte 3
                ShutdownAnySegwit,
                // Byte 4
@@ -161,7 +168,7 @@ mod sealed {
                ZeroConf | Keysend,
        ]);
        define_context!(ChannelContext, []);
-       define_context!(InvoiceContext, [
+       define_context!(Bolt11InvoiceContext, [
                // Byte 0
                ,
                // Byte 1
@@ -196,7 +203,7 @@ mod sealed {
                // Byte 1
                StaticRemoteKey,
                // Byte 2
-               AnchorsZeroFeeHtlcTx,
+               AnchorsNonzeroFeeHtlcTx | AnchorsZeroFeeHtlcTx,
                // Byte 3
                ,
                // Byte 4
@@ -362,22 +369,25 @@ mod sealed {
        define_feature!(7, GossipQueries, [InitContext, NodeContext],
                "Feature flags for `gossip_queries`.", set_gossip_queries_optional, set_gossip_queries_required,
                supports_gossip_queries, requires_gossip_queries);
-       define_feature!(9, VariableLengthOnion, [InitContext, NodeContext, InvoiceContext],
+       define_feature!(9, VariableLengthOnion, [InitContext, NodeContext, Bolt11InvoiceContext],
                "Feature flags for `var_onion_optin`.", set_variable_length_onion_optional,
                set_variable_length_onion_required, supports_variable_length_onion,
                requires_variable_length_onion);
        define_feature!(13, StaticRemoteKey, [InitContext, NodeContext, ChannelTypeContext],
                "Feature flags for `option_static_remotekey`.", set_static_remote_key_optional,
                set_static_remote_key_required, supports_static_remote_key, requires_static_remote_key);
-       define_feature!(15, PaymentSecret, [InitContext, NodeContext, InvoiceContext],
+       define_feature!(15, PaymentSecret, [InitContext, NodeContext, Bolt11InvoiceContext],
                "Feature flags for `payment_secret`.", set_payment_secret_optional, set_payment_secret_required,
                supports_payment_secret, requires_payment_secret);
-       define_feature!(17, BasicMPP, [InitContext, NodeContext, InvoiceContext, Bolt12InvoiceContext],
+       define_feature!(17, BasicMPP, [InitContext, NodeContext, Bolt11InvoiceContext, Bolt12InvoiceContext],
                "Feature flags for `basic_mpp`.", set_basic_mpp_optional, set_basic_mpp_required,
                supports_basic_mpp, requires_basic_mpp);
        define_feature!(19, Wumbo, [InitContext, NodeContext],
                "Feature flags for `option_support_large_channel` (aka wumbo channels).", set_wumbo_optional, set_wumbo_required,
                supports_wumbo, requires_wumbo);
+       define_feature!(21, AnchorsNonzeroFeeHtlcTx, [InitContext, NodeContext, ChannelTypeContext],
+               "Feature flags for `option_anchors_nonzero_fee_htlc_tx`.", set_anchors_nonzero_fee_htlc_tx_optional,
+               set_anchors_nonzero_fee_htlc_tx_required, supports_anchors_nonzero_fee_htlc_tx, requires_anchors_nonzero_fee_htlc_tx);
        define_feature!(23, AnchorsZeroFeeHtlcTx, [InitContext, NodeContext, ChannelTypeContext],
                "Feature flags for `option_anchors_zero_fee_htlc_tx`.", set_anchors_zero_fee_htlc_tx_optional,
                set_anchors_zero_fee_htlc_tx_required, supports_anchors_zero_fee_htlc_tx, requires_anchors_zero_fee_htlc_tx);
@@ -393,7 +403,7 @@ mod sealed {
        define_feature!(47, SCIDPrivacy, [InitContext, NodeContext, ChannelTypeContext],
                "Feature flags for only forwarding with SCID aliasing. Called `option_scid_alias` in the BOLTs",
                set_scid_privacy_optional, set_scid_privacy_required, supports_scid_privacy, requires_scid_privacy);
-       define_feature!(49, PaymentMetadata, [InvoiceContext],
+       define_feature!(49, PaymentMetadata, [Bolt11InvoiceContext],
                "Feature flags for payment metadata in invoices.", set_payment_metadata_optional,
                set_payment_metadata_required, supports_payment_metadata, requires_payment_metadata);
        define_feature!(51, ZeroConf, [InitContext, NodeContext, ChannelTypeContext],
@@ -406,7 +416,7 @@ mod sealed {
 
        #[cfg(test)]
        define_feature!(123456789, UnknownFeature,
-               [NodeContext, ChannelContext, InvoiceContext, OfferContext, InvoiceRequestContext, Bolt12InvoiceContext, BlindedHopContext],
+               [NodeContext, ChannelContext, Bolt11InvoiceContext, OfferContext, InvoiceRequestContext, Bolt12InvoiceContext, BlindedHopContext],
                "Feature flags for an unknown feature used in testing.", set_unknown_feature_optional,
                set_unknown_feature_required, supports_unknown_test_feature, requires_unknown_test_feature);
 }
@@ -422,15 +432,21 @@ pub struct Features<T: sealed::Context> {
        mark: PhantomData<T>,
 }
 
+impl<T: sealed::Context, Rhs: Borrow<Self>> core::ops::BitOrAssign<Rhs> for Features<T> {
+       fn bitor_assign(&mut self, rhs: Rhs) {
+               let total_feature_len = cmp::max(self.flags.len(), rhs.borrow().flags.len());
+               self.flags.resize(total_feature_len, 0u8);
+               for (byte, rhs_byte) in self.flags.iter_mut().zip(rhs.borrow().flags.iter()) {
+                       *byte |= *rhs_byte;
+               }
+       }
+}
+
 impl<T: sealed::Context> core::ops::BitOr for Features<T> {
        type Output = Self;
 
        fn bitor(mut self, o: Self) -> Self {
-               let total_feature_len = cmp::max(self.flags.len(), o.flags.len());
-               self.flags.resize(total_feature_len, 0u8);
-               for (byte, o_byte) in self.flags.iter_mut().zip(o.flags.iter()) {
-                       *byte |= *o_byte;
-               }
+               self |= o;
                self
        }
 }
@@ -476,7 +492,7 @@ pub type NodeFeatures = Features<sealed::NodeContext>;
 /// Features used within a `channel_announcement` message.
 pub type ChannelFeatures = Features<sealed::ChannelContext>;
 /// Features used within an invoice.
-pub type InvoiceFeatures = Features<sealed::InvoiceContext>;
+pub type Bolt11InvoiceFeatures = Features<sealed::Bolt11InvoiceContext>;
 /// Features used within an `offer`.
 pub type OfferFeatures = Features<sealed::OfferContext>;
 /// Features used within an `invoice_request`.
@@ -522,8 +538,8 @@ impl InitFeatures {
        }
 }
 
-impl InvoiceFeatures {
-       /// Converts `InvoiceFeatures` to `Features<C>`. Only known `InvoiceFeatures` relevant to
+impl Bolt11InvoiceFeatures {
+       /// Converts `Bolt11InvoiceFeatures` to `Features<C>`. Only known `Bolt11InvoiceFeatures` relevant to
        /// context `C` are included in the result.
        pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
                self.to_context_internal()
@@ -533,15 +549,15 @@ impl InvoiceFeatures {
        /// features (since they were not announced in a node announcement). However, keysend payments
        /// don't have an invoice to pull the payee's features from, so this method is provided for use in
        /// [`PaymentParameters::for_keysend`], thus omitting the need for payers to manually construct an
-       /// `InvoiceFeatures` for [`find_route`].
+       /// `Bolt11InvoiceFeatures` for [`find_route`].
        ///
        /// MPP keysend is not widely supported yet, so we parameterize support to allow the user to
        /// choose whether their router should find multi-part routes.
        ///
        /// [`PaymentParameters::for_keysend`]: crate::routing::router::PaymentParameters::for_keysend
        /// [`find_route`]: crate::routing::router::find_route
-       pub(crate) fn for_keysend(allow_mpp: bool) -> InvoiceFeatures {
-               let mut res = InvoiceFeatures::empty();
+       pub(crate) fn for_keysend(allow_mpp: bool) -> Bolt11InvoiceFeatures {
+               let mut res = Bolt11InvoiceFeatures::empty();
                res.set_variable_length_onion_optional();
                if allow_mpp {
                        res.set_basic_mpp_optional();
@@ -551,8 +567,8 @@ impl InvoiceFeatures {
 }
 
 impl Bolt12InvoiceFeatures {
-       /// Converts `Bolt12InvoiceFeatures` to `Features<C>`. Only known `Bolt12InvoiceFeatures` relevant
-       /// to context `C` are included in the result.
+       /// Converts [`Bolt12InvoiceFeatures`] to [`Features<C>`]. Only known [`Bolt12InvoiceFeatures`]
+       /// relevant to context `C` are included in the result.
        pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
                self.to_context_internal()
        }
@@ -578,9 +594,17 @@ impl ChannelTypeFeatures {
                <sealed::ChannelTypeContext as sealed::StaticRemoteKey>::set_required_bit(&mut ret.flags);
                ret
        }
+
+       /// Constructs a ChannelTypeFeatures with anchors support
+       pub(crate) fn anchors_zero_htlc_fee_and_dependencies() -> Self {
+               let mut ret = Self::empty();
+               <sealed::ChannelTypeContext as sealed::StaticRemoteKey>::set_required_bit(&mut ret.flags);
+               <sealed::ChannelTypeContext as sealed::AnchorsZeroFeeHtlcTx>::set_required_bit(&mut ret.flags);
+               ret
+       }
 }
 
-impl ToBase32 for InvoiceFeatures {
+impl ToBase32 for Bolt11InvoiceFeatures {
        fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
                // Explanation for the "4": the normal way to round up when dividing is to add the divisor
                // minus one before dividing
@@ -610,16 +634,16 @@ impl ToBase32 for InvoiceFeatures {
        }
 }
 
-impl Base32Len for InvoiceFeatures {
+impl Base32Len for Bolt11InvoiceFeatures {
        fn base32_len(&self) -> usize {
                self.to_base32().len()
        }
 }
 
-impl FromBase32 for InvoiceFeatures {
+impl FromBase32 for Bolt11InvoiceFeatures {
        type Err = bech32::Error;
 
-       fn from_base32(field_data: &[u5]) -> Result<InvoiceFeatures, bech32::Error> {
+       fn from_base32(field_data: &[u5]) -> Result<Bolt11InvoiceFeatures, bech32::Error> {
                // Explanation for the "7": the normal way to round up when dividing is to add the divisor
                // minus one before dividing
                let length_bytes = (field_data.len() * 5 + 7) / 8 as usize;
@@ -638,7 +662,7 @@ impl FromBase32 for InvoiceFeatures {
                while !res_bytes.is_empty() && res_bytes[res_bytes.len() - 1] == 0 {
                        res_bytes.pop();
                }
-               Ok(InvoiceFeatures::from_le_bytes(res_bytes))
+               Ok(Bolt11InvoiceFeatures::from_le_bytes(res_bytes))
        }
 }
 
@@ -704,7 +728,7 @@ impl<T: sealed::Context> Features<T> {
        }
 
        /// Returns true if this `Features` object contains required features unknown by `other`.
-       pub fn requires_unknown_bits_from(&self, other: &Features<T>) -> bool {
+       pub fn requires_unknown_bits_from(&self, other: &Self) -> bool {
                // Bitwise AND-ing with all even bits set except for known features will select required
                // unknown features.
                self.flags.iter().enumerate().any(|(i, &byte)| {
@@ -879,7 +903,7 @@ macro_rules! impl_feature_len_prefixed_write {
 impl_feature_len_prefixed_write!(InitFeatures);
 impl_feature_len_prefixed_write!(ChannelFeatures);
 impl_feature_len_prefixed_write!(NodeFeatures);
-impl_feature_len_prefixed_write!(InvoiceFeatures);
+impl_feature_len_prefixed_write!(Bolt11InvoiceFeatures);
 impl_feature_len_prefixed_write!(Bolt12InvoiceFeatures);
 impl_feature_len_prefixed_write!(BlindedHopFeatures);
 
@@ -919,7 +943,7 @@ impl<T: sealed::Context> Readable for WithoutLength<Features<T>> {
 
 #[cfg(test)]
 mod tests {
-       use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures, OfferFeatures, sealed};
+       use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, Bolt11InvoiceFeatures, NodeFeatures, OfferFeatures, sealed};
        use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5};
        use crate::util::ser::{Readable, WithoutLength, Writeable};
 
@@ -1034,17 +1058,17 @@ mod tests {
        fn convert_to_context_with_unknown_flags() {
                // Ensure the `from` context has fewer known feature bytes than the `to` context.
                assert!(<sealed::ChannelContext as sealed::Context>::KNOWN_FEATURE_MASK.len() <
-                       <sealed::InvoiceContext as sealed::Context>::KNOWN_FEATURE_MASK.len());
+                       <sealed::Bolt11InvoiceContext as sealed::Context>::KNOWN_FEATURE_MASK.len());
                let mut channel_features = ChannelFeatures::empty();
                channel_features.set_unknown_feature_optional();
                assert!(channel_features.supports_unknown_bits());
-               let invoice_features: InvoiceFeatures = channel_features.to_context_internal();
+               let invoice_features: Bolt11InvoiceFeatures = channel_features.to_context_internal();
                assert!(!invoice_features.supports_unknown_bits());
        }
 
        #[test]
        fn set_feature_bits() {
-               let mut features = InvoiceFeatures::empty();
+               let mut features = Bolt11InvoiceFeatures::empty();
                features.set_basic_mpp_optional();
                features.set_payment_secret_required();
                assert!(features.supports_basic_mpp());
@@ -1055,7 +1079,7 @@ mod tests {
 
        #[test]
        fn set_custom_bits() {
-               let mut features = InvoiceFeatures::empty();
+               let mut features = Bolt11InvoiceFeatures::empty();
                features.set_variable_length_onion_optional();
                assert_eq!(features.flags[1], 0b00000010);
 
@@ -1065,19 +1089,19 @@ mod tests {
                assert_eq!(features.flags[31], 0b00000000);
                assert_eq!(features.flags[32], 0b00000101);
 
-               let known_bit = <sealed::InvoiceContext as sealed::PaymentSecret>::EVEN_BIT;
-               let byte_offset = <sealed::InvoiceContext as sealed::PaymentSecret>::BYTE_OFFSET;
+               let known_bit = <sealed::Bolt11InvoiceContext as sealed::PaymentSecret>::EVEN_BIT;
+               let byte_offset = <sealed::Bolt11InvoiceContext as sealed::PaymentSecret>::BYTE_OFFSET;
                assert_eq!(byte_offset, 1);
                assert_eq!(features.flags[byte_offset], 0b00000010);
                assert!(features.set_required_custom_bit(known_bit).is_err());
                assert_eq!(features.flags[byte_offset], 0b00000010);
 
-               let mut features = InvoiceFeatures::empty();
+               let mut features = Bolt11InvoiceFeatures::empty();
                assert!(features.set_optional_custom_bit(256).is_ok());
                assert!(features.set_optional_custom_bit(259).is_ok());
                assert_eq!(features.flags[32], 0b00001010);
 
-               let mut features = InvoiceFeatures::empty();
+               let mut features = Bolt11InvoiceFeatures::empty();
                assert!(features.set_required_custom_bit(257).is_ok());
                assert!(features.set_required_custom_bit(258).is_ok());
                assert_eq!(features.flags[32], 0b00000101);
@@ -1114,7 +1138,7 @@ mod tests {
                        u5::try_from_u8(16).unwrap(),
                        u5::try_from_u8(1).unwrap(),
                ];
-               let features = InvoiceFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]);
+               let features = Bolt11InvoiceFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]);
 
                // Test length calculation.
                assert_eq!(features.base32_len(), 13);
@@ -1124,13 +1148,13 @@ mod tests {
                assert_eq!(features_as_u5s, features_serialized);
 
                // Test deserialization.
-               let features_deserialized = InvoiceFeatures::from_base32(&features_as_u5s).unwrap();
+               let features_deserialized = Bolt11InvoiceFeatures::from_base32(&features_as_u5s).unwrap();
                assert_eq!(features, features_deserialized);
        }
 
        #[test]
        fn test_channel_type_mapping() {
-               // If we map an InvoiceFeatures with StaticRemoteKey optional, it should map into a
+               // If we map an Bolt11InvoiceFeatures with StaticRemoteKey optional, it should map into a
                // required-StaticRemoteKey ChannelTypeFeatures.
                let mut init_features = InitFeatures::empty();
                init_features.set_static_remote_key_optional();
index 6107642cbf27c644bbe66691853adf3709d7fe8d..84bc1a1b3f0656476aa1d00771f0368d97003cd0 100644 (file)
@@ -15,6 +15,7 @@ use crate::sign::EntropySource;
 use crate::chain::channelmonitor::ChannelMonitor;
 use crate::chain::transaction::OutPoint;
 use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
+use crate::events::bump_transaction::{BumpTransactionEventHandler, Wallet, WalletSource};
 use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 use crate::ln::channelmanager::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA};
 use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
@@ -27,18 +28,16 @@ use crate::util::scid_utils;
 use crate::util::test_utils;
 use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface};
 use crate::util::errors::APIError;
-use crate::util::config::UserConfig;
+use crate::util::config::{UserConfig, MaxDustHTLCExposure};
 use crate::util::ser::{ReadableArgs, Writeable};
 
 use bitcoin::blockdata::block::{Block, BlockHeader};
 use bitcoin::blockdata::transaction::{Transaction, TxOut};
-use bitcoin::network::constants::Network;
-
 use bitcoin::hash_types::BlockHash;
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::hashes::Hash as _;
-
-use bitcoin::secp256k1::PublicKey;
+use bitcoin::network::constants::Network;
+use bitcoin::secp256k1::{PublicKey, SecretKey};
 
 use crate::io;
 use crate::prelude::*;
@@ -289,6 +288,19 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: Block, sk
        }
        call_claimable_balances(node);
        node.node.test_process_background_events();
+
+       for tx in &block.txdata {
+               for input in &tx.input {
+                       node.wallet_source.remove_utxo(input.previous_output);
+               }
+               let wallet_script = node.wallet_source.get_change_script().unwrap();
+               for (idx, output) in tx.output.iter().enumerate() {
+                       if output.script_pubkey == wallet_script {
+                               let outpoint = bitcoin::OutPoint { txid: tx.txid(), vout: idx as u32 };
+                               node.wallet_source.add_utxo(outpoint, output.value);
+                       }
+               }
+       }
 }
 
 pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) {
@@ -375,6 +387,13 @@ pub struct Node<'a, 'b: 'a, 'c: 'b> {
        pub blocks: Arc<Mutex<Vec<(Block, u32)>>>,
        pub connect_style: Rc<RefCell<ConnectStyle>>,
        pub override_init_features: Rc<RefCell<Option<InitFeatures>>>,
+       pub wallet_source: Arc<test_utils::TestWalletSource>,
+       pub bump_tx_handler: BumpTransactionEventHandler<
+               &'c test_utils::TestBroadcaster,
+               Arc<Wallet<Arc<test_utils::TestWalletSource>, &'c test_utils::TestLogger>>,
+               &'b test_utils::TestKeysInterface,
+               &'c test_utils::TestLogger,
+       >,
 }
 impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
        pub fn best_block_hash(&self) -> BlockHash {
@@ -818,13 +837,13 @@ macro_rules! get_feerate {
 }
 
 #[cfg(test)]
-macro_rules! get_opt_anchors {
+macro_rules! get_channel_type_features {
        ($node: expr, $counterparty_node: expr, $channel_id: expr) => {
                {
                        let mut per_peer_state_lock;
                        let mut peer_state_lock;
                        let chan = get_channel_ref!($node, $counterparty_node, per_peer_state_lock, peer_state_lock, $channel_id);
-                       chan.context.opt_anchors()
+                       chan.context.get_channel_type().clone()
                }
        }
 }
@@ -1100,6 +1119,15 @@ pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, '
        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);
        node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), &open_channel_msg);
+       if node_b.node.get_current_default_configuration().manually_accept_inbound_channels {
+               let events = node_b.node.get_and_clear_pending_events();
+               assert_eq!(events.len(), 1);
+               match &events[0] {
+                       Event::OpenChannelRequest { temporary_channel_id, counterparty_node_id, .. } =>
+                               node_b.node.accept_inbound_channel(temporary_channel_id, counterparty_node_id, 42).unwrap(),
+                       _ => panic!("Unexpected event"),
+               };
+       }
        let accept_channel_msg = get_event_msg!(node_b, MessageSendEvent::SendAcceptChannel, node_a.node.get_our_node_id());
        assert_eq!(accept_channel_msg.temporary_channel_id, create_chan_id);
        node_a.node.handle_accept_channel(&node_b.node.get_our_node_id(), &accept_channel_msg);
@@ -1797,6 +1825,28 @@ macro_rules! get_route_and_payment_hash {
        }}
 }
 
+pub fn check_payment_claimable(
+       event: &Event, expected_payment_hash: PaymentHash, expected_payment_secret: PaymentSecret,
+       expected_recv_value: u64, expected_payment_preimage: Option<PaymentPreimage>,
+       expected_receiver_node_id: PublicKey,
+) {
+       match event {
+               Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, .. } => {
+                       assert_eq!(expected_payment_hash, *payment_hash);
+                       assert_eq!(expected_recv_value, *amount_msat);
+                       assert_eq!(expected_receiver_node_id, receiver_node_id.unwrap());
+                       match purpose {
+                               PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
+                                       assert_eq!(&expected_payment_preimage, payment_preimage);
+                                       assert_eq!(expected_payment_secret, *payment_secret);
+                               },
+                               _ => {},
+                       }
+               },
+               _ => panic!("Unexpected event"),
+       }
+}
+
 #[macro_export]
 #[cfg(any(test, ldk_bench, feature = "_test_utils"))]
 macro_rules! expect_payment_claimable {
@@ -1806,22 +1856,8 @@ macro_rules! expect_payment_claimable {
        ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr, $expected_payment_preimage: expr, $expected_receiver_node_id: expr) => {
                let events = $node.node.get_and_clear_pending_events();
                assert_eq!(events.len(), 1);
-               match events[0] {
-                       $crate::events::Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, .. } => {
-                               assert_eq!($expected_payment_hash, *payment_hash);
-                               assert_eq!($expected_recv_value, amount_msat);
-                               assert_eq!($expected_receiver_node_id, receiver_node_id.unwrap());
-                               match purpose {
-                                       $crate::events::PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
-                                               assert_eq!(&$expected_payment_preimage, payment_preimage);
-                                               assert_eq!($expected_payment_secret, *payment_secret);
-                                       },
-                                       _ => {},
-                               }
-                       },
-                       _ => panic!("Unexpected event"),
-               }
-       }
+               $crate::ln::functional_test_utils::check_payment_claimable(&events[0], $expected_payment_hash, $expected_payment_secret, $expected_recv_value, $expected_payment_preimage, $expected_receiver_node_id)
+       };
 }
 
 #[macro_export]
@@ -1942,6 +1978,16 @@ macro_rules! expect_payment_forwarded {
        }
 }
 
+#[cfg(test)]
+#[macro_export]
+macro_rules! expect_channel_shutdown_state {
+       ($node: expr, $chan_id: expr, $state: path) => {
+               let chan_details = $node.node.list_channels().into_iter().filter(|cd| cd.channel_id == $chan_id).collect::<Vec<ChannelDetails>>();
+               assert_eq!(chan_details.len(), 1);
+               assert_eq!(chan_details[0].channel_shutdown_state, Some($state));
+       }
+}
+
 #[cfg(any(test, ldk_bench, feature = "_test_utils"))]
 pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) {
        let events = node.node.get_and_clear_pending_events();
@@ -2124,7 +2170,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p
                                match &events_2[0] {
                                        Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat,
                                                receiver_node_id, ref via_channel_id, ref via_user_channel_id,
-                                               claim_deadline, onion_fields,
+                                               claim_deadline, onion_fields, ..
                                        } => {
                                                assert_eq!(our_payment_hash, *payment_hash);
                                                assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap());
@@ -2186,7 +2232,20 @@ pub fn send_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, route: Route
        (our_payment_preimage, our_payment_hash, our_payment_secret, payment_id)
 }
 
-pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_preimage: PaymentPreimage) -> u64 {
+pub fn do_claim_payment_along_route<'a, 'b, 'c>(
+       origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], skip_last: bool,
+       our_payment_preimage: PaymentPreimage
+) -> u64 {
+       let extra_fees = vec![0; expected_paths.len()];
+       do_claim_payment_along_route_with_extra_penultimate_hop_fees(origin_node, expected_paths,
+               &extra_fees[..], skip_last, our_payment_preimage)
+}
+
+pub fn do_claim_payment_along_route_with_extra_penultimate_hop_fees<'a, 'b, 'c>(
+       origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], expected_extra_fees:
+       &[u32], skip_last: bool, our_payment_preimage: PaymentPreimage
+) -> u64 {
+       assert_eq!(expected_paths.len(), expected_extra_fees.len());
        for path in expected_paths.iter() {
                assert_eq!(path.last().unwrap().node.get_our_node_id(), expected_paths[0].last().unwrap().node.get_our_node_id());
        }
@@ -2236,7 +2295,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
                }
        }
 
-       for (expected_route, (path_msgs, next_hop)) in expected_paths.iter().zip(per_path_msgs.drain(..)) {
+       for (i, (expected_route, (path_msgs, next_hop))) in expected_paths.iter().zip(per_path_msgs.drain(..)).enumerate() {
                let mut next_msgs = Some(path_msgs);
                let mut expected_next_node = next_hop;
 
@@ -2251,10 +2310,10 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
                        }
                }
                macro_rules! mid_update_fulfill_dance {
-                       ($node: expr, $prev_node: expr, $next_node: expr, $new_msgs: expr) => {
+                       ($idx: expr, $node: expr, $prev_node: expr, $next_node: expr, $new_msgs: expr) => {
                                {
                                        $node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0);
-                                       let fee = {
+                                       let mut fee = {
                                                let per_peer_state = $node.node.per_peer_state.read().unwrap();
                                                let peer_state = per_peer_state.get(&$prev_node.node.get_our_node_id())
                                                        .unwrap().lock().unwrap();
@@ -2265,6 +2324,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
                                                        channel.context.config().forwarding_fee_base_msat
                                                }
                                        };
+                                       if $idx == 1 { fee += expected_extra_fees[i]; }
                                        expect_payment_forwarded!($node, $next_node, $prev_node, Some(fee as u64), false, false);
                                        expected_total_fee_msat += fee as u64;
                                        check_added_monitors!($node, 1);
@@ -2296,7 +2356,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
                                } else {
                                        next_node = expected_route[expected_route.len() - 1 - idx - 1];
                                }
-                               mid_update_fulfill_dance!(node, prev_node, next_node, update_next_msgs);
+                               mid_update_fulfill_dance!(idx, node, prev_node, next_node, update_next_msgs);
                        } else {
                                assert!(!update_next_msgs);
                                assert!(node.node.get_and_clear_pending_msg_events().is_empty());
@@ -2549,8 +2609,10 @@ pub fn test_default_channel_config() -> UserConfig {
        // It now defaults to 1, so we simply set it to the expected value here.
        default_config.channel_handshake_config.our_htlc_minimum_msat = 1000;
        // When most of our tests were written, we didn't have the notion of a `max_dust_htlc_exposure_msat`,
-       // It now defaults to 5_000_000 msat; to avoid interfering with tests we bump it to 50_000_000 msat.
-       default_config.channel_config.max_dust_htlc_exposure_msat = 50_000_000;
+       // to avoid interfering with tests we bump it to 50_000_000 msat (assuming the default test
+       // feerate of 253).
+       default_config.channel_config.max_dust_htlc_exposure =
+               MaxDustHTLCExposure::FeeRateMultiplier(50_000_000 / 253);
        default_config
 }
 
@@ -2558,12 +2620,13 @@ pub fn create_node_chanmgrs<'a, 'b>(node_count: usize, cfgs: &'a Vec<NodeCfg<'b>
        let mut chanmgrs = Vec::new();
        for i in 0..node_count {
                let network = Network::Testnet;
+               let genesis_block = bitcoin::blockdata::constants::genesis_block(network);
                let params = ChainParameters {
                        network,
                        best_block: BestBlock::from_network(network),
                };
                let node = ChannelManager::new(cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, &cfgs[i].router, cfgs[i].logger, cfgs[i].keys_manager,
-                       cfgs[i].keys_manager, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params);
+                       cfgs[i].keys_manager, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params, genesis_block.header.time);
                chanmgrs.push(node);
        }
 
@@ -2578,6 +2641,7 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
 
        for i in 0..node_count {
                let gossip_sync = P2PGossipSync::new(cfgs[i].network_graph.as_ref(), None, cfgs[i].logger);
+               let wallet_source = Arc::new(test_utils::TestWalletSource::new(SecretKey::from_slice(&[i as u8 + 1; 32]).unwrap()));
                nodes.push(Node{
                        chain_source: cfgs[i].chain_source, tx_broadcaster: cfgs[i].tx_broadcaster,
                        fee_estimator: cfgs[i].fee_estimator, router: &cfgs[i].router,
@@ -2588,6 +2652,11 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
                        blocks: Arc::clone(&cfgs[i].tx_broadcaster.blocks),
                        connect_style: Rc::clone(&connect_style),
                        override_init_features: Rc::clone(&cfgs[i].override_init_features),
+                       wallet_source: Arc::clone(&wallet_source),
+                       bump_tx_handler: BumpTransactionEventHandler::new(
+                               cfgs[i].tx_broadcaster, Arc::new(Wallet::new(Arc::clone(&wallet_source), cfgs[i].logger)),
+                               &cfgs[i].keys_manager, cfgs[i].logger,
+                       ),
                })
        }
 
@@ -2792,13 +2861,6 @@ macro_rules! get_chan_reestablish_msgs {
                                        panic!("Unexpected event")
                                }
                        }
-                       for chan in $src_node.node.list_channels() {
-                               if chan.is_public && chan.counterparty.node_id != $dst_node.node.get_our_node_id() {
-                                       if let Some(scid) = chan.short_channel_id {
-                                               assert!(announcements.remove(&scid));
-                                       }
-                               }
-                       }
                        assert!(announcements.is_empty());
                        res
                }
index f03ecd14f661bd575976f505d11ad061b0160057..8de2e9f631a53325ba5b6ba6b384392762017967 100644 (file)
@@ -27,7 +27,7 @@ use crate::ln::{chan_utils, onion_utils};
 use crate::ln::chan_utils::{OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
 use crate::routing::gossip::{NetworkGraph, NetworkUpdate};
 use crate::routing::router::{Path, PaymentParameters, Route, RouteHop, RouteParameters, find_route, get_route};
-use crate::ln::features::{ChannelFeatures, NodeFeatures};
+use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures};
 use crate::ln::msgs;
 use crate::ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, ErrorAction};
 use crate::util::enforcing_trait_impls::EnforcingSigner;
@@ -35,7 +35,7 @@ use crate::util::test_utils;
 use crate::util::errors::APIError;
 use crate::util::ser::{Writeable, ReadableArgs};
 use crate::util::string::UntrustedString;
-use crate::util::config::UserConfig;
+use crate::util::config::{UserConfig, MaxDustHTLCExposure};
 
 use bitcoin::hash_types::BlockHash;
 use bitcoin::blockdata::script::{Builder, Script};
@@ -61,6 +61,8 @@ use crate::sync::{Arc, Mutex};
 use crate::ln::functional_test_utils::*;
 use crate::ln::chan_utils::CommitmentTransaction;
 
+use super::channel::UNFUNDED_CHANNEL_AGE_LIMIT_TICKS;
+
 #[test]
 fn test_insane_channel_opens() {
        // Stand up a network of 2 nodes
@@ -155,8 +157,8 @@ fn do_test_counterparty_no_reserve(send_from_initiator: bool) {
        // Have node0 initiate a channel to node1 with aforementioned parameters
        let mut push_amt = 100_000_000;
        let feerate_per_kw = 253;
-       let opt_anchors = false;
-       push_amt -= feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + 4 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 * 1000;
+       let channel_type_features = ChannelTypeFeatures::only_static_remote_key();
+       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();
@@ -201,7 +203,7 @@ fn do_test_counterparty_no_reserve(send_from_initiator: bool) {
                        // Note that for outbound channels we have to consider the commitment tx fee and the
                        // "fee spike buffer", which is currently a multiple of the total commitment tx fee as
                        // well as an additional HTLC.
-                       - FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * commit_tx_fee_msat(feerate_per_kw, 2, opt_anchors));
+                       - FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * commit_tx_fee_msat(feerate_per_kw, 2, &channel_type_features));
        } else {
                send_payment(&nodes[1], &[&nodes[0]], push_amt);
        }
@@ -651,14 +653,14 @@ fn test_update_fee_that_funder_cannot_afford() {
        let default_config = UserConfig::default();
        let bs_channel_reserve_sats = get_holder_selected_channel_reserve_satoshis(channel_value, &default_config);
 
-       let opt_anchors = false;
+       let channel_type_features = ChannelTypeFeatures::only_static_remote_key();
 
        // Calculate the maximum feerate that A can afford. Note that we don't send an update_fee
        // CONCURRENT_INBOUND_HTLC_FEE_BUFFER HTLCs before actually running out of local balance, so we
        // calculate two different feerates here - the expected local limit as well as the expected
        // remote limit.
-       let feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / (commitment_tx_base_weight(opt_anchors) + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC)) as u32;
-       let non_buffer_feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / commitment_tx_base_weight(opt_anchors)) as u32;
+       let feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / (commitment_tx_base_weight(&channel_type_features) + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC)) as u32;
+       let non_buffer_feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / commitment_tx_base_weight(&channel_type_features)) as u32;
        {
                let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap();
                *feerate_lock = feerate;
@@ -677,7 +679,7 @@ fn test_update_fee_that_funder_cannot_afford() {
 
                //We made sure neither party's funds are below the dust limit and there are no HTLCs here
                assert_eq!(commitment_tx.output.len(), 2);
-               let total_fee: u64 = commit_tx_fee_msat(feerate, 0, opt_anchors) / 1000;
+               let total_fee: u64 = commit_tx_fee_msat(feerate, 0, &channel_type_features) / 1000;
                let mut actual_fee = commitment_tx.output.iter().fold(0, |acc, output| acc + output.value);
                actual_fee = channel_value - actual_fee;
                assert_eq!(total_fee, actual_fee);
@@ -729,8 +731,8 @@ fn test_update_fee_that_funder_cannot_afford() {
                let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        INITIAL_COMMITMENT_NUMBER - 1,
                        push_sats,
-                       channel_value - push_sats - commit_tx_fee_msat(non_buffer_feerate + 4, 0, opt_anchors) / 1000,
-                       opt_anchors, local_funding, remote_funding,
+                       channel_value - push_sats - commit_tx_fee_msat(non_buffer_feerate + 4, 0, &channel_type_features) / 1000,
+                       local_funding, remote_funding,
                        commit_tx_keys.clone(),
                        non_buffer_feerate + 4,
                        &mut htlcs,
@@ -1346,7 +1348,7 @@ fn test_basic_channel_reserve() {
        let channel_reserve = chan_stat.channel_reserve_msat;
 
        // The 2* and +1 are for the fee spike reserve.
-       let commit_tx_fee = 2 * commit_tx_fee_msat(get_feerate!(nodes[0], nodes[1], chan.2), 1 + 1, get_opt_anchors!(nodes[0], nodes[1], chan.2));
+       let commit_tx_fee = 2 * commit_tx_fee_msat(get_feerate!(nodes[0], nodes[1], chan.2), 1 + 1, &get_channel_type_features!(nodes[0], nodes[1], chan.2));
        let max_can_send = 5000000 - channel_reserve - commit_tx_fee;
        let (mut route, our_payment_hash, _, our_payment_secret) =
                get_route_and_payment_hash!(nodes[0], nodes[1], max_can_send);
@@ -1393,6 +1395,7 @@ fn test_fee_spike_violation_fails_htlc() {
                payment_hash: payment_hash,
                cltv_expiry: htlc_cltv,
                onion_routing_packet: onion_packet,
+               skimmed_fee_msat: None,
        };
 
        nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &msg);
@@ -1459,7 +1462,7 @@ fn test_fee_spike_violation_fails_htlc() {
                        commitment_number,
                        95000,
                        local_chan_balance,
-                       local_chan.context.opt_anchors(), local_funding, remote_funding,
+                       local_funding, remote_funding,
                        commit_tx_keys.clone(),
                        feerate_per_kw,
                        &mut vec![(accepted_htlc_info, ())],
@@ -1518,10 +1521,10 @@ fn test_chan_reserve_violation_outbound_htlc_inbound_chan() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
        let default_config = UserConfig::default();
-       let opt_anchors = false;
+       let channel_type_features = ChannelTypeFeatures::only_static_remote_key();
 
        let mut push_amt = 100_000_000;
-       push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors);
+       push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type_features);
 
        push_amt -= get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
 
@@ -1549,13 +1552,13 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
        let default_config = UserConfig::default();
-       let opt_anchors = false;
+       let channel_type_features = ChannelTypeFeatures::only_static_remote_key();
 
        // Set nodes[0]'s balance such that they will consider any above-dust received HTLC to be a
        // channel reserve violation (so their balance is channel reserve (1000 sats) + commitment
        // transaction fee with 0 HTLCs (183 sats)).
        let mut push_amt = 100_000_000;
-       push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors);
+       push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type_features);
        push_amt -= get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
        let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, push_amt);
 
@@ -1582,6 +1585,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
                payment_hash: payment_hash,
                cltv_expiry: htlc_cltv,
                onion_routing_packet: onion_packet,
+               skimmed_fee_msat: None,
        };
 
        nodes[0].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &msg);
@@ -1605,18 +1609,18 @@ fn test_chan_reserve_dust_inbound_htlcs_outbound_chan() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
        let default_config = UserConfig::default();
-       let opt_anchors = false;
+       let channel_type_features = ChannelTypeFeatures::only_static_remote_key();
 
        // Set nodes[0]'s balance such that they will consider any above-dust received HTLC to be a
        // channel reserve violation (so their balance is channel reserve (1000 sats) + commitment
        // transaction fee with 0 HTLCs (183 sats)).
        let mut push_amt = 100_000_000;
-       push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors);
+       push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type_features);
        push_amt -= get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000;
        create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, push_amt);
 
        let dust_amt = crate::ln::channel::MIN_CHAN_DUST_LIMIT_SATOSHIS * 1000
-               + feerate_per_kw as u64 * htlc_success_tx_weight(opt_anchors) / 1000 * 1000 - 1;
+               + feerate_per_kw as u64 * htlc_success_tx_weight(&channel_type_features) / 1000 * 1000 - 1;
        // In the previous code, routing this dust payment would cause nodes[0] to perceive a channel
        // reserve violation even though it's a dust HTLC and therefore shouldn't count towards the
        // commitment transaction fee.
@@ -1646,12 +1650,12 @@ fn test_chan_init_feerate_unaffordability() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
        let default_config = UserConfig::default();
-       let opt_anchors = false;
+       let channel_type_features = ChannelTypeFeatures::only_static_remote_key();
 
        // Set the push_msat amount such that nodes[0] will not be able to afford to add even a single
        // HTLC.
        let mut push_amt = 100_000_000;
-       push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors);
+       push_amt -= 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(),
                APIError::APIMisuseError { err: "Funding amount (356) can't even pay fee for initial commitment transaction fee of 357.".to_string() });
 
@@ -1716,10 +1720,10 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
        let total_routing_fee_msat = (nodes.len() - 2) as u64 * feemsat;
        let chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2);
        let feerate = get_feerate!(nodes[0], nodes[1], chan.2);
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan.2);
 
        // Add a 2* and +1 for the fee spike reserve.
-       let commit_tx_fee_2_htlc = 2*commit_tx_fee_msat(feerate, 2 + 1, opt_anchors);
+       let commit_tx_fee_2_htlc = 2*commit_tx_fee_msat(feerate, 2 + 1, &channel_type_features);
        let recv_value_1 = (chan_stat.value_to_self_msat - chan_stat.channel_reserve_msat - total_routing_fee_msat - commit_tx_fee_2_htlc)/2;
        let amt_msat_1 = recv_value_1 + total_routing_fee_msat;
 
@@ -1737,7 +1741,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
        nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event_1.msgs[0]);
 
        // Attempt to trigger a channel reserve violation --> payment failure.
-       let commit_tx_fee_2_htlcs = commit_tx_fee_msat(feerate, 2, opt_anchors);
+       let commit_tx_fee_2_htlcs = commit_tx_fee_msat(feerate, 2, &channel_type_features);
        let recv_value_2 = chan_stat.value_to_self_msat - amt_msat_1 - chan_stat.channel_reserve_msat - total_routing_fee_msat - commit_tx_fee_2_htlcs + 1;
        let amt_msat_2 = recv_value_2 + total_routing_fee_msat;
        let mut route_2 = route_1.clone();
@@ -1758,6 +1762,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
                payment_hash: our_payment_hash_1,
                cltv_expiry: htlc_cltv,
                onion_routing_packet: onion_packet,
+               skimmed_fee_msat: None,
        };
 
        nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &msg);
@@ -1791,8 +1796,8 @@ fn test_inbound_outbound_capacity_is_not_zero() {
        assert_eq!(channels1[0].inbound_capacity_msat, 100000 * 1000 - 95000000 - reserve*1000);
 }
 
-fn commit_tx_fee_msat(feerate: u32, num_htlcs: u64, opt_anchors: bool) -> u64 {
-       (commitment_tx_base_weight(opt_anchors) + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate as u64 / 1000 * 1000
+fn commit_tx_fee_msat(feerate: u32, num_htlcs: u64, channel_type_features: &ChannelTypeFeatures) -> u64 {
+       (commitment_tx_base_weight(channel_type_features) + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate as u64 / 1000 * 1000
 }
 
 #[test]
@@ -1827,7 +1832,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
        let feemsat = 239; // set above
        let total_fee_msat = (nodes.len() - 2) as u64 * feemsat;
        let feerate = get_feerate!(nodes[0], nodes[1], chan_1.2);
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_1.2);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_1.2);
 
        let recv_value_0 = stat01.counterparty_max_htlc_value_in_flight_msat - total_fee_msat;
 
@@ -1852,7 +1857,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
                // 3 for the 3 HTLCs that will be sent, 2* and +1 for the fee spike reserve.
                // Also, ensure that each payment has enough to be over the dust limit to
                // ensure it'll be included in each commit tx fee calculation.
-               let commit_tx_fee_all_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, opt_anchors);
+               let commit_tx_fee_all_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, &channel_type_features);
                let ensure_htlc_amounts_above_dust_buffer = 3 * (stat01.counterparty_dust_limit_msat + 1000);
                if stat01.value_to_self_msat < stat01.channel_reserve_msat + commit_tx_fee_all_htlcs + ensure_htlc_amounts_above_dust_buffer + amt_msat {
                        break;
@@ -1889,7 +1894,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
        // the amount of the first of these aforementioned 3 payments. The reason we split into 3 payments
        // is to test the behavior of the holding cell with respect to channel reserve and commit tx fee
        // policy.
-       let commit_tx_fee_2_htlcs = 2*commit_tx_fee_msat(feerate, 2 + 1, opt_anchors);
+       let commit_tx_fee_2_htlcs = 2*commit_tx_fee_msat(feerate, 2 + 1, &channel_type_features);
        let recv_value_1 = (stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - commit_tx_fee_2_htlcs)/2;
        let amt_msat_1 = recv_value_1 + total_fee_msat;
 
@@ -1918,7 +1923,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
        }
 
        // split the rest to test holding cell
-       let commit_tx_fee_3_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, opt_anchors);
+       let commit_tx_fee_3_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, &channel_type_features);
        let additional_htlc_cost_msat = commit_tx_fee_3_htlcs - commit_tx_fee_2_htlcs;
        let recv_value_21 = recv_value_2/2 - additional_htlc_cost_msat/2;
        let recv_value_22 = recv_value_2 - recv_value_21 - total_fee_msat - additional_htlc_cost_msat;
@@ -2037,11 +2042,11 @@ fn test_channel_reserve_holding_cell_htlcs() {
        claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_21);
        claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_22);
 
-       let commit_tx_fee_0_htlcs = 2*commit_tx_fee_msat(feerate, 1, opt_anchors);
+       let commit_tx_fee_0_htlcs = 2*commit_tx_fee_msat(feerate, 1, &channel_type_features);
        let recv_value_3 = commit_tx_fee_2_htlcs - commit_tx_fee_0_htlcs - total_fee_msat;
        send_payment(&nodes[0], &vec![&nodes[1], &nodes[2]][..], recv_value_3);
 
-       let commit_tx_fee_1_htlc = 2*commit_tx_fee_msat(feerate, 1 + 1, opt_anchors);
+       let commit_tx_fee_1_htlc = 2*commit_tx_fee_msat(feerate, 1 + 1, &channel_type_features);
        let expected_value_to_self = stat01.value_to_self_msat - (recv_value_1 + total_fee_msat) - (recv_value_21 + total_fee_msat) - (recv_value_22 + total_fee_msat) - (recv_value_3 + total_fee_msat);
        let stat0 = get_channel_value_stat!(nodes[0], nodes[1], chan_1.2);
        assert_eq!(stat0.value_to_self_msat, expected_value_to_self);
@@ -3410,6 +3415,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() {
                        payment_hash,
                        cltv_expiry,
                        onion_routing_packet,
+                       skimmed_fee_msat: None,
                };
                nodes[0].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &update_add_htlc);
        }
@@ -5706,10 +5712,10 @@ fn test_fail_holding_cell_htlc_upon_free() {
        let mut chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2);
        let channel_reserve = chan_stat.channel_reserve_msat;
        let feerate = get_feerate!(nodes[0], nodes[1], chan.2);
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan.2);
 
        // 2* and +1 HTLCs on the commit tx fee calculation for the fee spike reserve.
-       let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, opt_anchors);
+       let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, &channel_type_features);
        let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], max_can_send);
 
        // Send a payment which passes reserve checks but gets stuck in the holding cell.
@@ -5786,11 +5792,11 @@ fn test_free_and_fail_holding_cell_htlcs() {
        let mut chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2);
        let channel_reserve = chan_stat.channel_reserve_msat;
        let feerate = get_feerate!(nodes[0], nodes[1], chan.2);
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan.2);
 
        // 2* and +1 HTLCs on the commit tx fee calculation for the fee spike reserve.
        let amt_1 = 20000;
-       let amt_2 = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 2 + 1, opt_anchors) - amt_1;
+       let amt_2 = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 2 + 1, &channel_type_features) - amt_1;
        let (route_1, payment_hash_1, payment_preimage_1, payment_secret_1) = get_route_and_payment_hash!(nodes[0], nodes[1], amt_1);
        let (route_2, payment_hash_2, _, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[1], amt_2);
 
@@ -5916,10 +5922,10 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
        let mut chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan_0_1.2);
        let channel_reserve = chan_stat.channel_reserve_msat;
        let feerate = get_feerate!(nodes[0], nodes[1], chan_0_1.2);
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_0_1.2);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_0_1.2);
 
        // Send a payment which passes reserve checks but gets stuck in the holding cell.
-       let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, opt_anchors);
+       let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, &channel_type_features);
        let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], max_can_send);
        let payment_event = {
                nodes[0].node.send_payment_with_route(&route, our_payment_hash,
@@ -6207,9 +6213,9 @@ fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() {
        let chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2);
        let channel_reserve = chan_stat.channel_reserve_msat;
        let feerate = get_feerate!(nodes[0], nodes[1], chan.2);
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan.2);
        // The 2* and +1 are for the fee spike reserve.
-       let commit_tx_fee_outbound = 2 * commit_tx_fee_msat(feerate, 1 + 1, opt_anchors);
+       let commit_tx_fee_outbound = 2 * commit_tx_fee_msat(feerate, 1 + 1, &channel_type_features);
 
        let max_can_send = 5000000 - channel_reserve - commit_tx_fee_outbound;
        let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], max_can_send);
@@ -6259,6 +6265,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
                payment_hash: our_payment_hash,
                cltv_expiry: htlc_cltv,
                onion_routing_packet: onion_packet.clone(),
+               skimmed_fee_msat: None,
        };
 
        for i in 0..50 {
@@ -8202,67 +8209,6 @@ fn test_preimage_storage() {
        }
 }
 
-#[test]
-#[allow(deprecated)]
-fn test_secret_timeout() {
-       // Simple test of payment secret storage time outs. After
-       // `create_inbound_payment(_for_hash)_legacy` is removed, this test will be removed as well.
-       let chanmon_cfgs = create_chanmon_cfgs(2);
-       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
-       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
-       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
-
-       create_announced_chan_between_nodes(&nodes, 0, 1).0.contents.short_channel_id;
-
-       let (payment_hash, payment_secret_1) = nodes[1].node.create_inbound_payment_legacy(Some(100_000), 2).unwrap();
-
-       // We should fail to register the same payment hash twice, at least until we've connected a
-       // block with time 7200 + CHAN_CONFIRM_DEPTH + 1.
-       if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2) {
-               assert_eq!(err, "Duplicate payment hash");
-       } else { panic!(); }
-       let mut block = {
-               let node_1_blocks = nodes[1].blocks.lock().unwrap();
-               create_dummy_block(node_1_blocks.last().unwrap().0.block_hash(), node_1_blocks.len() as u32 + 7200, Vec::new())
-       };
-       connect_block(&nodes[1], &block);
-       if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2) {
-               assert_eq!(err, "Duplicate payment hash");
-       } else { panic!(); }
-
-       // If we then connect the second block, we should be able to register the same payment hash
-       // again (this time getting a new payment secret).
-       block.header.prev_blockhash = block.header.block_hash();
-       block.header.time += 1;
-       connect_block(&nodes[1], &block);
-       let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2).unwrap();
-       assert_ne!(payment_secret_1, our_payment_secret);
-
-       {
-               let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
-               nodes[0].node.send_payment_with_route(&route, payment_hash,
-                       RecipientOnionFields::secret_only(our_payment_secret), PaymentId(payment_hash.0)).unwrap();
-               check_added_monitors!(nodes[0], 1);
-               let mut events = nodes[0].node.get_and_clear_pending_msg_events();
-               let mut payment_event = SendEvent::from_event(events.pop().unwrap());
-               nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
-               commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
-       }
-       // Note that after leaving the above scope we have no knowledge of any arguments or return
-       // values from previous calls.
-       expect_pending_htlcs_forwardable!(nodes[1]);
-       let events = nodes[1].node.get_and_clear_pending_events();
-       assert_eq!(events.len(), 1);
-       match events[0] {
-               Event::PaymentClaimable { purpose: PaymentPurpose::InvoicePayment { payment_preimage, payment_secret }, .. } => {
-                       assert!(payment_preimage.is_none());
-                       assert_eq!(payment_secret, our_payment_secret);
-                       // We don't actually have the payment preimage with which to claim this payment!
-               },
-               _ => panic!("Unexpected event"),
-       }
-}
-
 #[test]
 fn test_bad_secret_hash() {
        // Simple test of unregistered payment hash/invalid payment secret handling
@@ -8937,13 +8883,13 @@ fn test_duplicate_chan_id() {
        let (_, funding_created) = {
                let per_peer_state = nodes[0].node.per_peer_state.read().unwrap();
                let mut a_peer_state = per_peer_state.get(&nodes[1].node.get_our_node_id()).unwrap().lock().unwrap();
-               // Once we call `get_outbound_funding_created` the channel has a duplicate channel_id as
+               // Once we call `get_funding_created` the channel has a duplicate channel_id as
                // another channel in the ChannelManager - an invalid state. Thus, we'd panic later when we
                // try to create another channel. Instead, we drop the channel entirely here (leaving the
                // channelmanager in a possibly nonsense state instead).
                let mut as_chan = a_peer_state.outbound_v1_channel_by_id.remove(&open_chan_2_msg.temporary_channel_id).unwrap();
                let logger = test_utils::TestLogger::new();
-               as_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap()
+               as_chan.get_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap()
        };
        check_added_monitors!(nodes[0], 0);
        nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created);
@@ -9571,7 +9517,7 @@ enum ExposureEvent {
        AtUpdateFeeOutbound,
 }
 
-fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_event: ExposureEvent, on_holder_tx: bool) {
+fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_event: ExposureEvent, on_holder_tx: bool, multiplier_dust_limit: bool) {
        // Test that we properly reject dust HTLC violating our `max_dust_htlc_exposure_msat`
        // policy.
        //
@@ -9586,7 +9532,12 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let mut config = test_default_channel_config();
-       config.channel_config.max_dust_htlc_exposure_msat = 5_000_000; // default setting value
+       config.channel_config.max_dust_htlc_exposure = if multiplier_dust_limit {
+               // Default test fee estimator rate is 253 sat/kw, so we set the multiplier to 5_000_000 / 253
+               // to get roughly the same initial value as the default setting when this test was
+               // originally written.
+               MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253)
+       } else { MaxDustHTLCExposure::FixedLimitMsat(5_000_000) }; // initial default setting value
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
@@ -9602,7 +9553,7 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
        let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
        nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel);
 
-       let opt_anchors = false;
+       let channel_type_features = ChannelTypeFeatures::only_static_remote_key();
 
        let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42);
 
@@ -9630,20 +9581,21 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
        let (mut route, payment_hash, _, payment_secret) =
                get_route_and_payment_hash!(nodes[0], nodes[1], 1000);
 
-       let dust_buffer_feerate = {
+       let (dust_buffer_feerate, max_dust_htlc_exposure_msat) = {
                let per_peer_state = nodes[0].node.per_peer_state.read().unwrap();
                let chan_lock = per_peer_state.get(&nodes[1].node.get_our_node_id()).unwrap().lock().unwrap();
                let chan = chan_lock.channel_by_id.get(&channel_id).unwrap();
-               chan.context.get_dust_buffer_feerate(None) as u64
+               (chan.context.get_dust_buffer_feerate(None) as u64,
+               chan.context.get_max_dust_htlc_exposure_msat(&LowerBoundedFeeEstimator(nodes[0].fee_estimator)))
        };
-       let dust_outbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_timeout_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
-       let dust_outbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_outbound_htlc_on_holder_tx_msat;
+       let dust_outbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_timeout_tx_weight(&channel_type_features) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
+       let dust_outbound_htlc_on_holder_tx: u64 = max_dust_htlc_exposure_msat / dust_outbound_htlc_on_holder_tx_msat;
 
-       let dust_inbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_success_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
-       let dust_inbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_inbound_htlc_on_holder_tx_msat;
+       let dust_inbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_success_tx_weight(&channel_type_features) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
+       let dust_inbound_htlc_on_holder_tx: u64 = max_dust_htlc_exposure_msat / dust_inbound_htlc_on_holder_tx_msat;
 
        let dust_htlc_on_counterparty_tx: u64 = 4;
-       let dust_htlc_on_counterparty_tx_msat: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_htlc_on_counterparty_tx;
+       let dust_htlc_on_counterparty_tx_msat: u64 = max_dust_htlc_exposure_msat / dust_htlc_on_counterparty_tx;
 
        if on_holder_tx {
                if dust_outbound_balance {
@@ -9695,7 +9647,7 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
                                ), true, APIError::ChannelUnavailable { .. }, {});
                }
        } else if exposure_breach_event == ExposureEvent::AtHTLCReception {
-               let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], if on_holder_tx { dust_inbound_htlc_on_holder_tx_msat } else { dust_htlc_on_counterparty_tx_msat + 1 });
+               let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], if on_holder_tx { dust_inbound_htlc_on_holder_tx_msat } else { dust_htlc_on_counterparty_tx_msat + 4 });
                nodes[1].node.send_payment_with_route(&route, payment_hash,
                        RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
                check_added_monitors!(nodes[1], 1);
@@ -9708,18 +9660,24 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
                        // Outbound dust balance: 6399 sats
                        let dust_inbound_overflow = dust_inbound_htlc_on_holder_tx_msat * (dust_inbound_htlc_on_holder_tx + 1);
                        let dust_outbound_overflow = dust_outbound_htlc_on_holder_tx_msat * dust_outbound_htlc_on_holder_tx + dust_inbound_htlc_on_holder_tx_msat;
-                       nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_config.max_dust_htlc_exposure_msat), 1);
+                       nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, max_dust_htlc_exposure_msat), 1);
                } else {
                        // Outbound dust balance: 5200 sats
                        nodes[0].logger.assert_log("lightning::ln::channel".to_string(),
                                format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx",
-                                       dust_htlc_on_counterparty_tx_msat * (dust_htlc_on_counterparty_tx - 1) + dust_htlc_on_counterparty_tx_msat + 1,
-                                       config.channel_config.max_dust_htlc_exposure_msat), 1);
+                                       dust_htlc_on_counterparty_tx_msat * (dust_htlc_on_counterparty_tx - 1) + dust_htlc_on_counterparty_tx_msat + 4,
+                                       max_dust_htlc_exposure_msat), 1);
                }
        } else if exposure_breach_event == ExposureEvent::AtUpdateFeeOutbound {
                route.paths[0].hops.last_mut().unwrap().fee_msat = 2_500_000;
-               nodes[0].node.send_payment_with_route(&route, payment_hash,
-                       RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
+               // For the multiplier dust exposure limit, since it scales with feerate,
+               // we need to add a lot of HTLCs that will become dust at the new feerate
+               // to cross the threshold.
+               for _ in 0..20 {
+                       let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(1_000), None);
+                       nodes[0].node.send_payment_with_route(&route, payment_hash,
+                               RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
+               }
                {
                        let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap();
                        *feerate_lock = *feerate_lock * 10;
@@ -9734,20 +9692,25 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
        added_monitors.clear();
 }
 
+fn do_test_max_dust_htlc_exposure_by_threshold_type(multiplier_dust_limit: bool) {
+       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCForward, true, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCForward, true, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCReception, true, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCReception, false, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCForward, false, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCReception, false, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCReception, true, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCForward, false, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtUpdateFeeOutbound, true, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtUpdateFeeOutbound, false, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtUpdateFeeOutbound, false, multiplier_dust_limit);
+       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtUpdateFeeOutbound, true, multiplier_dust_limit);
+}
+
 #[test]
 fn test_max_dust_htlc_exposure() {
-       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCForward, true);
-       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCForward, true);
-       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCReception, true);
-       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCReception, false);
-       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCForward, false);
-       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCReception, false);
-       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtHTLCReception, true);
-       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtHTLCForward, false);
-       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtUpdateFeeOutbound, true);
-       do_test_max_dust_htlc_exposure(true, ExposureEvent::AtUpdateFeeOutbound, false);
-       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtUpdateFeeOutbound, false);
-       do_test_max_dust_htlc_exposure(false, ExposureEvent::AtUpdateFeeOutbound, true);
+       do_test_max_dust_htlc_exposure_by_threshold_type(false);
+       do_test_max_dust_htlc_exposure_by_threshold_type(true);
 }
 
 #[test]
@@ -10056,3 +10019,89 @@ fn test_disconnects_peer_awaiting_response_ticks() {
                }
        }
 }
+
+#[test]
+fn test_remove_expired_outbound_unfunded_channels() {
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+       let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_message);
+       let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel_message);
+
+       let events = nodes[0].node.get_and_clear_pending_events();
+       assert_eq!(events.len(), 1);
+       match events[0] {
+               Event::FundingGenerationReady { .. } => (),
+               _ => panic!("Unexpected event"),
+       };
+
+       // Asserts the outbound channel has been removed from a nodes[0]'s peer state map.
+       let check_outbound_channel_existence = |should_exist: bool| {
+               let per_peer_state = nodes[0].node.per_peer_state.read().unwrap();
+               let chan_lock = per_peer_state.get(&nodes[1].node.get_our_node_id()).unwrap().lock().unwrap();
+               assert_eq!(chan_lock.outbound_v1_channel_by_id.contains_key(&temp_channel_id), should_exist);
+       };
+
+       // Channel should exist without any timer ticks.
+       check_outbound_channel_existence(true);
+
+       // Channel should exist with 1 timer tick less than required.
+       for _ in 0..UNFUNDED_CHANNEL_AGE_LIMIT_TICKS - 1 {
+               nodes[0].node.timer_tick_occurred();
+               check_outbound_channel_existence(true)
+       }
+
+       // Remove channel after reaching the required ticks.
+       nodes[0].node.timer_tick_occurred();
+       check_outbound_channel_existence(false);
+
+       check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed);
+}
+
+#[test]
+fn test_remove_expired_inbound_unfunded_channels() {
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+       let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_message);
+       let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel_message);
+
+       let events = nodes[0].node.get_and_clear_pending_events();
+       assert_eq!(events.len(), 1);
+       match events[0] {
+               Event::FundingGenerationReady { .. } => (),
+               _ => panic!("Unexpected event"),
+       };
+
+       // Asserts the inbound channel has been removed from a nodes[1]'s peer state map.
+       let check_inbound_channel_existence = |should_exist: bool| {
+               let per_peer_state = nodes[1].node.per_peer_state.read().unwrap();
+               let chan_lock = per_peer_state.get(&nodes[0].node.get_our_node_id()).unwrap().lock().unwrap();
+               assert_eq!(chan_lock.inbound_v1_channel_by_id.contains_key(&temp_channel_id), should_exist);
+       };
+
+       // Channel should exist without any timer ticks.
+       check_inbound_channel_existence(true);
+
+       // Channel should exist with 1 timer tick less than required.
+       for _ in 0..UNFUNDED_CHANNEL_AGE_LIMIT_TICKS - 1 {
+               nodes[1].node.timer_tick_occurred();
+               check_inbound_channel_existence(true)
+       }
+
+       // Remove channel after reaching the required ticks.
+       nodes[1].node.timer_tick_occurred();
+       check_inbound_channel_existence(false);
+
+       check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
+}
index 5fa39137cf4577f41f85a57b95aedf067ea43e5b..a916dbfc9e26d13cdd12e7d29ec667772d8e7dd7 100644 (file)
@@ -9,41 +9,25 @@
 
 //! Further functional tests which test blockchain reorganizations.
 
-#[cfg(anchors)]
-use crate::sign::{ChannelSigner, EcdsaChannelSigner};
-#[cfg(anchors)]
-use crate::chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS;
-use crate::chain::channelmonitor::{ANTI_REORG_DELAY, Balance};
+use crate::sign::EcdsaChannelSigner;
+use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS, Balance};
 use crate::chain::transaction::OutPoint;
-use crate::chain::chaininterface::LowerBoundedFeeEstimator;
-#[cfg(anchors)]
-use crate::events::bump_transaction::BumpTransactionEvent;
+use crate::chain::chaininterface::{LowerBoundedFeeEstimator, compute_feerate_sat_per_1000_weight};
+use crate::events::bump_transaction::{BumpTransactionEvent, WalletSource};
 use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination};
 use crate::ln::channel;
-#[cfg(anchors)]
-use crate::ln::chan_utils;
-#[cfg(anchors)]
-use crate::ln::channelmanager::ChannelManager;
-use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, PaymentId, RecipientOnionFields};
+use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, PaymentId, RecipientOnionFields};
 use crate::ln::msgs::ChannelMessageHandler;
-#[cfg(anchors)]
 use crate::util::config::UserConfig;
-#[cfg(anchors)]
 use crate::util::crypto::sign;
 use crate::util::ser::Writeable;
 use crate::util::test_utils;
 
-#[cfg(anchors)]
 use bitcoin::blockdata::transaction::EcdsaSighashType;
 use bitcoin::blockdata::script::Builder;
 use bitcoin::blockdata::opcodes;
-use bitcoin::secp256k1::Secp256k1;
-#[cfg(anchors)]
-use bitcoin::secp256k1::SecretKey;
-#[cfg(anchors)]
-use bitcoin::{Amount, PublicKey, Script, TxIn, TxOut, PackedLockTime, Witness};
-use bitcoin::Transaction;
-#[cfg(anchors)]
+use bitcoin::secp256k1::{Secp256k1, SecretKey};
+use bitcoin::{Amount, PublicKey, Script, Transaction, TxIn, TxOut, PackedLockTime, Witness};
 use bitcoin::util::sighash::SighashCache;
 
 use crate::prelude::*;
@@ -184,10 +168,10 @@ fn chanmon_claim_value_coop_close() {
        assert_eq!(funding_outpoint.to_channel_id(), chan_id);
 
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
 
        assert_eq!(vec![Balance::ClaimableOnChannelClose {
-                       claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(opt_anchors) / 1000
+                       claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(&channel_type_features) / 1000
                }],
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
        assert_eq!(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000, }],
@@ -222,7 +206,7 @@ fn chanmon_claim_value_coop_close() {
        assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
 
        assert_eq!(vec![Balance::ClaimableAwaitingConfirmations {
-                       claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(opt_anchors) / 1000,
+                       claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(&channel_type_features) / 1000,
                        confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1,
                }],
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
@@ -295,7 +279,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) {
        let htlc_cltv_timeout = nodes[0].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety
 
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
 
        let remote_txn = get_local_commitment_txn!(nodes[1], chan_id);
        let sent_htlc_balance = Balance::MaybeTimeoutClaimableHTLC {
@@ -335,7 +319,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) {
        // as claimable. A lists both its to-self balance and the (possibly-claimable) HTLCs.
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        claimable_amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
@@ -382,7 +366,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) {
                                1_000 - // The push_msat value in satoshis
                                3 - // The dust HTLC value in satoshis
                                // The commitment transaction fee with two HTLC outputs:
-                               chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) +
+                               chan_feerate * (channel::commitment_tx_base_weight(&channel_type_features) +
                                                                if prev_commitment_tx { 1 } else { 2 } *
                                                                channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, sent_htlc_timeout_balance.clone()];
@@ -432,7 +416,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) {
 
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1,
                }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
@@ -622,7 +606,7 @@ fn test_balances_on_local_commitment_htlcs() {
        expect_payment_claimed!(nodes[1], payment_hash_2, 20_000_000);
 
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
 
        // Get nodes[0]'s commitment transaction and HTLC-Timeout transactions
        let as_txn = get_local_commitment_txn!(nodes[0], chan_id);
@@ -652,7 +636,7 @@ fn test_balances_on_local_commitment_htlcs() {
 
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
@@ -671,7 +655,7 @@ fn test_balances_on_local_commitment_htlcs() {
        connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
@@ -686,7 +670,7 @@ fn test_balances_on_local_commitment_htlcs() {
        // call, as described, two hunks down.
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 10_000,
@@ -700,7 +684,7 @@ fn test_balances_on_local_commitment_htlcs() {
        expect_payment_sent!(nodes[0], payment_preimage_2);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 10_000,
@@ -716,7 +700,7 @@ fn test_balances_on_local_commitment_htlcs() {
 
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 10_000,
@@ -767,7 +751,7 @@ fn test_no_preimage_inbound_htlc_balances() {
        let htlc_cltv_timeout = nodes[0].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety
 
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
 
        let a_sent_htlc_balance = Balance::MaybeTimeoutClaimableHTLC {
                claimable_amount_satoshis: 10_000,
@@ -796,7 +780,7 @@ fn test_no_preimage_inbound_htlc_balances() {
 
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
@@ -816,7 +800,7 @@ fn test_no_preimage_inbound_htlc_balances() {
        let node_a_commitment_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32;
        let as_pre_spend_claims = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]);
 
@@ -888,7 +872,7 @@ fn test_no_preimage_inbound_htlc_balances() {
        let as_timeout_claimable_height = nodes[0].best_block_info().1 + (BREAKDOWN_TIMEOUT as u32) - 1;
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 10_000,
@@ -899,7 +883,7 @@ fn test_no_preimage_inbound_htlc_balances() {
        mine_transaction(&nodes[0], &bs_htlc_timeout_claim[0]);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 10_000,
@@ -915,7 +899,7 @@ fn test_no_preimage_inbound_htlc_balances() {
        connect_blocks(&nodes[0], 1);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: node_a_commitment_claimable,
                }, Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 10_000,
@@ -1024,7 +1008,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
 
        // Get the latest commitment transaction from A and then update the fee to revoke it
        let as_revoked_txn = get_local_commitment_txn!(nodes[0], chan_id);
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
 
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
 
@@ -1123,7 +1107,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
 
        let to_self_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable {
                claimable_amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate *
-                       (channel::commitment_tx_base_weight(opt_anchors) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
        };
        let to_self_claimed_avail_height;
        let largest_htlc_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable {
@@ -1153,7 +1137,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
        };
        let to_self_claimed_balance = Balance::ClaimableAwaitingConfirmations {
                claimable_amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate *
-                       (channel::commitment_tx_base_weight(opt_anchors) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
+                       (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
                        - chan_feerate * claim_txn[3].weight() as u64 / 1000,
                confirmation_height: to_self_claimed_avail_height,
        };
@@ -1185,7 +1169,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
                        confirmation_height: nodes[1].best_block_info().1 + 1,
                }, Balance::ClaimableAwaitingConfirmations {
                        claimable_amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
                                - chan_feerate * claim_txn[3].weight() as u64 / 1000,
                        confirmation_height: to_self_claimed_avail_height,
                }, Balance::ClaimableAwaitingConfirmations {
@@ -1263,7 +1247,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
 
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
 
        // B will generate an HTLC-Success from its revoked commitment tx
        mine_transaction(&nodes[1], &revoked_local_txn[0]);
@@ -1311,7 +1295,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        let as_balances = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        // to_remote output in B's revoked commitment
                        claimable_amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: to_remote_conf_height,
                }, Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in B's revoked commitment
@@ -1342,7 +1326,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        // to_remote output in B's revoked commitment
                        claimable_amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                        confirmation_height: to_remote_conf_height,
                }, Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in B's revoked commitment
@@ -1491,7 +1475,7 @@ fn test_revoked_counterparty_aggregated_claims() {
        check_spends!(as_revoked_txn[0], funding_tx);
        check_spends!(as_revoked_txn[1], as_revoked_txn[0]); // The HTLC-Claim transaction
 
-       let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id);
+       let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
 
        {
@@ -1543,7 +1527,7 @@ fn test_revoked_counterparty_aggregated_claims() {
                }, Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in A's revoked commitment
                        claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
                        claimable_amount_satoshis: 4_000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2
@@ -1572,7 +1556,7 @@ fn test_revoked_counterparty_aggregated_claims() {
                }, Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in A's revoked commitment
                        claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
                        claimable_amount_satoshis: 4_000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2
@@ -1589,7 +1573,7 @@ fn test_revoked_counterparty_aggregated_claims() {
        assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in A's revoked commitment
                        claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
                        claimable_amount_satoshis: 4_000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2
@@ -1606,7 +1590,7 @@ fn test_revoked_counterparty_aggregated_claims() {
        assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in A's revoked commitment
                        claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
                        claimable_amount_satoshis: 4_000,
                }, Balance::ClaimableAwaitingConfirmations { // HTLC 2
@@ -1621,7 +1605,7 @@ fn test_revoked_counterparty_aggregated_claims() {
        assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in A's revoked commitment
                        claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
                }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
                        claimable_amount_satoshis: 4_000,
                }]),
@@ -1731,16 +1715,12 @@ fn test_restored_packages_retry() {
 fn do_test_monitor_rebroadcast_pending_claims(anchors: bool) {
        // Test that we will retry broadcasting pending claims for a force-closed channel on every
        // `ChainMonitor::rebroadcast_pending_claims` call.
-       if anchors {
-               assert!(cfg!(anchors));
-       }
        let mut chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let mut config = test_default_channel_config();
        if anchors {
-               #[cfg(anchors)] {
-                       config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
-               }
+               config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+               config.manually_accept_inbound_channels = true;
        }
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), Some(config)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
@@ -1762,6 +1742,17 @@ fn do_test_monitor_rebroadcast_pending_claims(anchors: bool) {
        check_closed_event(&nodes[0], 1, ClosureReason::CommitmentTxConfirmed, false);
        check_added_monitors(&nodes[0], 1);
 
+       let coinbase_tx = Transaction {
+               version: 2,
+               lock_time: PackedLockTime::ZERO,
+               input: vec![TxIn { ..Default::default() }],
+               output: vec![TxOut { // UTXO to attach fees to `htlc_tx` on anchors
+                       value: Amount::ONE_BTC.to_sat(),
+                       script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
+               }],
+       };
+       nodes[0].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value);
+
        // Set up a helper closure we'll use throughout our test. We should only expect retries without
        // bumps if fees have not increased after a block has been connected (assuming the height timer
        // re-evaluates at every block) or after `ChainMonitor::rebroadcast_pending_claims` is called.
@@ -1769,49 +1760,25 @@ fn do_test_monitor_rebroadcast_pending_claims(anchors: bool) {
        let mut check_htlc_retry = |should_retry: bool, should_bump: bool| -> Option<Transaction> {
                let (htlc_tx, htlc_tx_feerate) = if anchors {
                        assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
-                       let mut events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
+                       let events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
                        assert_eq!(events.len(), if should_retry { 1 } else { 0 });
                        if !should_retry {
                                return None;
                        }
-                       #[allow(unused_assignments)]
-                       let mut tx = Transaction {
-                               version: 2,
-                               lock_time: bitcoin::PackedLockTime::ZERO,
-                               input: vec![],
-                               output: vec![],
-                       };
-                       #[allow(unused_assignments)]
-                       let mut feerate = 0;
-                       #[cfg(anchors)] {
-                               feerate = if let Event::BumpTransaction(BumpTransactionEvent::HTLCResolution {
-                                       target_feerate_sat_per_1000_weight, mut htlc_descriptors, tx_lock_time,
-                               }) = events.pop().unwrap() {
-                                       let secp = Secp256k1::new();
-                                       assert_eq!(htlc_descriptors.len(), 1);
-                                       let descriptor = htlc_descriptors.pop().unwrap();
-                                       assert_eq!(descriptor.commitment_txid, commitment_txn[0].txid());
-                                       let htlc_output_idx = descriptor.htlc.transaction_output_index.unwrap() as usize;
-                                       assert!(htlc_output_idx < commitment_txn[0].output.len());
-                                       tx.lock_time = tx_lock_time;
-                                       // Note that we don't care about actually making the HTLC transaction meet the
-                                       // feerate for the test, we just want to make sure the feerates we receive from
-                                       // the events never decrease.
-                                       tx.input.push(descriptor.unsigned_tx_input());
-                                       let signer = nodes[0].keys_manager.derive_channel_keys(
-                                               descriptor.channel_value_satoshis, &descriptor.channel_keys_id,
-                                       );
-                                       let per_commitment_point = signer.get_per_commitment_point(
-                                               descriptor.per_commitment_number, &secp
-                                       );
-                                       tx.output.push(descriptor.tx_output(&per_commitment_point, &secp));
-                                       let our_sig = signer.sign_holder_htlc_transaction(&mut tx, 0, &descriptor, &secp).unwrap();
-                                       let witness_script = descriptor.witness_script(&per_commitment_point, &secp);
-                                       tx.input[0].witness = descriptor.tx_input_witness(&our_sig, &witness_script);
-                                       target_feerate_sat_per_1000_weight as u64
-                               } else { panic!("unexpected event"); };
+                       match &events[0] {
+                               Event::BumpTransaction(event) => {
+                                       nodes[0].bump_tx_handler.handle_event(&event);
+                                       let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
+                                       assert_eq!(txn.len(), 1);
+                                       let htlc_tx = txn.pop().unwrap();
+                                       check_spends!(&htlc_tx, &commitment_txn[0], &coinbase_tx);
+                                       let htlc_tx_fee = HTLC_AMT_SAT + coinbase_tx.output[0].value -
+                                               htlc_tx.output.iter().map(|output| output.value).sum::<u64>();
+                                       let htlc_tx_weight = htlc_tx.weight() as u64;
+                                       (htlc_tx, compute_feerate_sat_per_1000_weight(htlc_tx_fee, htlc_tx_weight))
+                               }
+                               _ => panic!("Unexpected event"),
                        }
-                       (tx, feerate)
                } else {
                        assert!(nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
                        let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
@@ -1822,8 +1789,8 @@ fn do_test_monitor_rebroadcast_pending_claims(anchors: bool) {
                        let htlc_tx = txn.pop().unwrap();
                        check_spends!(htlc_tx, commitment_txn[0]);
                        let htlc_tx_fee = HTLC_AMT_SAT - htlc_tx.output[0].value;
-                       let htlc_tx_feerate = htlc_tx_fee * 1000 / htlc_tx.weight() as u64;
-                       (htlc_tx, htlc_tx_feerate)
+                       let htlc_tx_weight = htlc_tx.weight() as u64;
+                       (htlc_tx, compute_feerate_sat_per_1000_weight(htlc_tx_fee, htlc_tx_weight))
                };
                if should_bump {
                        assert!(htlc_tx_feerate > prev_htlc_tx_feerate.take().unwrap());
@@ -1863,9 +1830,11 @@ fn do_test_monitor_rebroadcast_pending_claims(anchors: bool) {
 
        // Mine the HTLC transaction to ensure we don't retry claims while they're confirmed.
        mine_transaction(&nodes[0], &htlc_tx);
-       // If we have a `ConnectStyle` that advertises the new block first without the transasctions,
+       // If we have a `ConnectStyle` that advertises the new block first without the transactions,
        // we'll receive an extra bumped claim.
        if nodes[0].connect_style.borrow().updates_best_block_first() {
+               nodes[0].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value);
+               nodes[0].wallet_source.remove_utxo(bitcoin::OutPoint { txid: htlc_tx.txid(), vout: 1 });
                check_htlc_retry(true, anchors);
        }
        nodes[0].chain_monitor.chain_monitor.rebroadcast_pending_claims();
@@ -1875,11 +1844,9 @@ fn do_test_monitor_rebroadcast_pending_claims(anchors: bool) {
 #[test]
 fn test_monitor_timer_based_claim() {
        do_test_monitor_rebroadcast_pending_claims(false);
-       #[cfg(anchors)]
        do_test_monitor_rebroadcast_pending_claims(true);
 }
 
-#[cfg(anchors)]
 #[test]
 fn test_yield_anchors_events() {
        // Tests that two parties supporting anchor outputs can open a channel, route payments over
@@ -1888,12 +1855,12 @@ fn test_yield_anchors_events() {
        // allowing the consumer to provide additional fees to the commitment transaction to be
        // broadcast. Once the commitment transaction confirms, events for the HTLC resolution should be
        // emitted by LDK, such that the consumer can attach fees to the zero fee HTLC transactions.
-       let secp = Secp256k1::new();
        let mut chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let mut anchors_config = UserConfig::default();
        anchors_config.channel_handshake_config.announced_channel = true;
        anchors_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+       anchors_config.manually_accept_inbound_channels = true;
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config), Some(anchors_config)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
@@ -1905,6 +1872,7 @@ fn test_yield_anchors_events() {
 
        assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
 
+       *nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
        connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
        check_closed_broadcast!(&nodes[0], true);
        assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
@@ -1917,28 +1885,23 @@ fn test_yield_anchors_events() {
        let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
        assert_eq!(holder_events.len(), 1);
        let (commitment_tx, anchor_tx) = match holder_events.pop().unwrap() {
-               Event::BumpTransaction(BumpTransactionEvent::ChannelClose { commitment_tx, anchor_descriptor, .. })  => {
-                       assert_eq!(commitment_tx.input.len(), 1);
-                       assert_eq!(commitment_tx.output.len(), 6);
-                       let mut anchor_tx = Transaction {
+               Event::BumpTransaction(event) => {
+                       let coinbase_tx = Transaction {
                                version: 2,
                                lock_time: PackedLockTime::ZERO,
-                               input: vec![
-                                       TxIn { previous_output: anchor_descriptor.outpoint, ..Default::default() },
-                                       TxIn { ..Default::default() },
-                               ],
-                               output: vec![TxOut {
+                               input: vec![TxIn { ..Default::default() }],
+                               output: vec![TxOut { // UTXO to attach fees to `anchor_tx`
                                        value: Amount::ONE_BTC.to_sat(),
-                                       script_pubkey: Script::new_op_return(&[]),
+                                       script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
                                }],
                        };
-                       let signer = nodes[0].keys_manager.derive_channel_keys(
-                               anchor_descriptor.channel_value_satoshis, &anchor_descriptor.channel_keys_id,
-                       );
-                       let funding_sig = signer.sign_holder_anchor_input(&mut anchor_tx, 0, &secp).unwrap();
-                       anchor_tx.input[0].witness = chan_utils::build_anchor_input_witness(
-                               &signer.pubkeys().funding_pubkey, &funding_sig
-                       );
+                       nodes[0].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value);
+                       nodes[0].bump_tx_handler.handle_event(&event);
+                       let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
+                       assert_eq!(txn.len(), 2);
+                       let anchor_tx = txn.pop().unwrap();
+                       let commitment_tx = txn.pop().unwrap();
+                       check_spends!(anchor_tx, coinbase_tx, commitment_tx);
                        (commitment_tx, anchor_tx)
                },
                _ => panic!("Unexpected event"),
@@ -1962,31 +1925,12 @@ fn test_yield_anchors_events() {
        let mut htlc_txs = Vec::with_capacity(2);
        for event in holder_events {
                match event {
-                       Event::BumpTransaction(BumpTransactionEvent::HTLCResolution { htlc_descriptors, tx_lock_time, .. }) => {
-                               assert_eq!(htlc_descriptors.len(), 1);
-                               let htlc_descriptor = &htlc_descriptors[0];
-                               let signer = nodes[0].keys_manager.derive_channel_keys(
-                                       htlc_descriptor.channel_value_satoshis, &htlc_descriptor.channel_keys_id
-                               );
-                               let per_commitment_point = signer.get_per_commitment_point(htlc_descriptor.per_commitment_number, &secp);
-                               let mut htlc_tx = Transaction {
-                                       version: 2,
-                                       lock_time: tx_lock_time,
-                                       input: vec![
-                                               htlc_descriptor.unsigned_tx_input(), // HTLC input
-                                               TxIn { ..Default::default() } // Fee input
-                                       ],
-                                       output: vec![
-                                               htlc_descriptor.tx_output(&per_commitment_point, &secp), // HTLC output
-                                               TxOut { // Fee input change
-                                                       value: Amount::ONE_BTC.to_sat(),
-                                                       script_pubkey: Script::new_op_return(&[]),
-                                               }
-                                       ]
-                               };
-                               let our_sig = signer.sign_holder_htlc_transaction(&mut htlc_tx, 0, htlc_descriptor, &secp).unwrap();
-                               let witness_script = htlc_descriptor.witness_script(&per_commitment_point, &secp);
-                               htlc_tx.input[0].witness = htlc_descriptor.tx_input_witness(&our_sig, &witness_script);
+                       Event::BumpTransaction(event) => {
+                               nodes[0].bump_tx_handler.handle_event(&event);
+                               let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
+                               assert_eq!(txn.len(), 1);
+                               let htlc_tx = txn.pop().unwrap();
+                               check_spends!(htlc_tx, commitment_tx, anchor_tx);
                                htlc_txs.push(htlc_tx);
                        },
                        _ => panic!("Unexpected event"),
@@ -2013,7 +1957,6 @@ fn test_yield_anchors_events() {
        nodes[0].node.get_and_clear_pending_events();
 }
 
-#[cfg(anchors)]
 #[test]
 fn test_anchors_aggregated_revoked_htlc_tx() {
        // Test that `ChannelMonitor`s can properly detect and claim funds from a counterparty claiming
@@ -2027,6 +1970,7 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
        let mut anchors_config = UserConfig::default();
        anchors_config.channel_handshake_config.announced_channel = true;
        anchors_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+       anchors_config.manually_accept_inbound_channels = true;
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config), Some(anchors_config)]);
 
        let bob_persister: test_utils::TestPersister;
@@ -2086,11 +2030,12 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
        // Bob force closes by restarting with the outdated state, prompting the ChannelMonitors to
        // broadcast the latest commitment transaction known to them, which in our case is the one with
        // the HTLCs still pending.
+       *nodes[1].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
        nodes[1].node.timer_tick_occurred();
        check_added_monitors(&nodes[1], 2);
        check_closed_event!(&nodes[1], 2, ClosureReason::OutdatedChannelManager);
        let (revoked_commitment_a, revoked_commitment_b) = {
-               let txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+               let txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
                assert_eq!(txn.len(), 2);
                assert_eq!(txn[0].output.len(), 6); // 2 HTLC outputs + 1 to_self output + 1 to_remote output + 2 anchor outputs
                assert_eq!(txn[1].output.len(), 6); // 2 HTLC outputs + 1 to_self output + 1 to_remote output + 2 anchor outputs
@@ -2109,73 +2054,32 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
        assert!(nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
        let events = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events();
        assert_eq!(events.len(), 2);
-       let anchor_tx = {
-               let secret_key = SecretKey::from_slice(&[1; 32]).unwrap();
-               let public_key = PublicKey::new(secret_key.public_key(&secp));
-               let fee_utxo_script = Script::new_v0_p2wpkh(&public_key.wpubkey_hash().unwrap());
+       let mut anchor_txs = Vec::with_capacity(events.len());
+       for (idx, event) in events.into_iter().enumerate() {
+               let utxo_value = Amount::ONE_BTC.to_sat() * (idx + 1) as u64;
                let coinbase_tx = Transaction {
                        version: 2,
                        lock_time: PackedLockTime::ZERO,
                        input: vec![TxIn { ..Default::default() }],
                        output: vec![TxOut { // UTXO to attach fees to `anchor_tx`
-                               value: Amount::ONE_BTC.to_sat(),
-                               script_pubkey: fee_utxo_script.clone(),
-                       }],
-               };
-               let mut anchor_tx = Transaction {
-                       version: 2,
-                       lock_time: PackedLockTime::ZERO,
-                       input: vec![
-                               TxIn { // Fee input
-                                       previous_output: bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 },
-                                       ..Default::default()
-                               },
-                       ],
-                       output: vec![TxOut { // Fee input change
-                               value: coinbase_tx.output[0].value / 2 ,
-                               script_pubkey: Script::new_op_return(&[]),
+                               value: utxo_value,
+                               script_pubkey: nodes[1].wallet_source.get_change_script().unwrap(),
                        }],
                };
-               let mut signers = Vec::with_capacity(2);
-               for event in events {
-                       match event {
-                               Event::BumpTransaction(BumpTransactionEvent::ChannelClose { anchor_descriptor, .. })  => {
-                                       anchor_tx.input.push(TxIn {
-                                               previous_output: anchor_descriptor.outpoint,
-                                               ..Default::default()
-                                       });
-                                       let signer = nodes[1].keys_manager.derive_channel_keys(
-                                               anchor_descriptor.channel_value_satoshis, &anchor_descriptor.channel_keys_id,
-                                       );
-                                       signers.push(signer);
-                               },
-                               _ => panic!("Unexpected event"),
-                       }
-               }
-               for (i, signer) in signers.into_iter().enumerate() {
-                       let anchor_idx = i + 1;
-                       let funding_sig = signer.sign_holder_anchor_input(&mut anchor_tx, anchor_idx, &secp).unwrap();
-                       anchor_tx.input[anchor_idx].witness = chan_utils::build_anchor_input_witness(
-                               &signer.pubkeys().funding_pubkey, &funding_sig
-                       );
-               }
-               let fee_utxo_sig = {
-                       let witness_script = Script::new_p2pkh(&public_key.pubkey_hash());
-                       let sighash = hash_to_message!(&SighashCache::new(&anchor_tx).segwit_signature_hash(
-                               0, &witness_script, coinbase_tx.output[0].value, EcdsaSighashType::All
-                       ).unwrap()[..]);
-                       let sig = sign(&secp, &sighash, &secret_key);
-                       let mut sig = sig.serialize_der().to_vec();
-                       sig.push(EcdsaSighashType::All as u8);
-                       sig
+               nodes[1].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, utxo_value);
+               match event {
+                       Event::BumpTransaction(event) => nodes[1].bump_tx_handler.handle_event(&event),
+                       _ => panic!("Unexpected event"),
                };
-               anchor_tx.input[0].witness = Witness::from_vec(vec![fee_utxo_sig, public_key.to_bytes()]);
-               check_spends!(anchor_tx, coinbase_tx, revoked_commitment_a, revoked_commitment_b);
-               anchor_tx
+               let txn = nodes[1].tx_broadcaster.txn_broadcast();
+               assert_eq!(txn.len(), 2);
+               let (commitment_tx, anchor_tx) = (&txn[0], &txn[1]);
+               check_spends!(anchor_tx, coinbase_tx, commitment_tx);
+               anchor_txs.push(anchor_tx.clone());
        };
 
        for node in &nodes {
-               mine_transactions(node, &[&revoked_commitment_a, &revoked_commitment_b, &anchor_tx]);
+               mine_transactions(node, &[&revoked_commitment_a, &anchor_txs[0], &revoked_commitment_b, &anchor_txs[1]]);
        }
        check_added_monitors!(&nodes[0], 2);
        check_closed_broadcast(&nodes[0], 2, true);
@@ -2245,16 +2149,14 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
                };
                let mut descriptors = Vec::with_capacity(4);
                for event in events {
+                       // We don't use the `BumpTransactionEventHandler` here because it does not support
+                       // creating one transaction from multiple `HTLCResolution` events.
                        if let Event::BumpTransaction(BumpTransactionEvent::HTLCResolution { mut htlc_descriptors, tx_lock_time, .. }) = event {
                                assert_eq!(htlc_descriptors.len(), 2);
                                for htlc_descriptor in &htlc_descriptors {
                                        assert!(!htlc_descriptor.htlc.offered);
-                                       let signer = nodes[1].keys_manager.derive_channel_keys(
-                                               htlc_descriptor.channel_value_satoshis, &htlc_descriptor.channel_keys_id
-                                       );
-                                       let per_commitment_point = signer.get_per_commitment_point(htlc_descriptor.per_commitment_number, &secp);
                                        htlc_tx.input.push(htlc_descriptor.unsigned_tx_input());
-                                       htlc_tx.output.push(htlc_descriptor.tx_output(&per_commitment_point, &secp));
+                                       htlc_tx.output.push(htlc_descriptor.tx_output(&secp));
                                }
                                descriptors.append(&mut htlc_descriptors);
                                htlc_tx.lock_time = tx_lock_time;
@@ -2264,12 +2166,9 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
                }
                for (idx, htlc_descriptor) in descriptors.into_iter().enumerate() {
                        let htlc_input_idx = idx + 1;
-                       let signer = nodes[1].keys_manager.derive_channel_keys(
-                               htlc_descriptor.channel_value_satoshis, &htlc_descriptor.channel_keys_id
-                       );
+                       let signer = htlc_descriptor.derive_channel_signer(&nodes[1].keys_manager);
                        let our_sig = signer.sign_holder_htlc_transaction(&htlc_tx, htlc_input_idx, &htlc_descriptor, &secp).unwrap();
-                       let per_commitment_point = signer.get_per_commitment_point(htlc_descriptor.per_commitment_number, &secp);
-                       let witness_script = htlc_descriptor.witness_script(&per_commitment_point, &secp);
+                       let witness_script = htlc_descriptor.witness_script(&secp);
                        htlc_tx.input[htlc_input_idx].witness = htlc_descriptor.tx_input_witness(&our_sig, &witness_script);
                }
                let fee_utxo_sig = {
index 3dd4a6da70ccda8bde8a2e22f50db9c12e12d9cd..a514f4923268ce8639bafbb5065c43e6e1a7ea3d 100644 (file)
@@ -610,6 +610,11 @@ pub struct UpdateAddHTLC {
        pub payment_hash: PaymentHash,
        /// The expiry height of the HTLC
        pub cltv_expiry: u32,
+       /// The extra fee skimmed by the sender of this message. See
+       /// [`ChannelConfig::accept_underpaying_htlcs`].
+       ///
+       /// [`ChannelConfig::accept_underpaying_htlcs`]: crate::util::config::ChannelConfig::accept_underpaying_htlcs
+       pub skimmed_fee_msat: Option<u64>,
        pub(crate) onion_routing_packet: OnionPacket,
 }
 
@@ -1903,8 +1908,10 @@ impl_writeable_msg!(UpdateAddHTLC, {
        amount_msat,
        payment_hash,
        cltv_expiry,
-       onion_routing_packet
-}, {});
+       onion_routing_packet,
+}, {
+       (65537, skimmed_fee_msat, option)
+});
 
 impl Readable for OnionMessage {
        fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
@@ -3330,7 +3337,8 @@ mod tests {
                        amount_msat: 3608586615801332854,
                        payment_hash: PaymentHash([1; 32]),
                        cltv_expiry: 821716,
-                       onion_routing_packet
+                       onion_routing_packet,
+                       skimmed_fee_msat: None,
                };
                let encoded_value = update_add_htlc.encode();
                let target_value = hex::decode("020202020202020202020202020202020202020202020202020202020202020200083a840000034d32144668701144760101010101010101010101010101010101010101010101010101010101010101000c89d4ff031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202").unwrap();
@@ -3752,7 +3760,7 @@ mod tests {
                let test_bytes = vec![42u8; 1000];
                if let OnionHopDataFormat::NonFinalNode { short_channel_id } = payload.format {
                        _encode_varint_length_prefixed_tlv!(&mut encoded_payload, {
-                               (1, test_bytes, vec_type),
+                               (1, test_bytes, required_vec),
                                (2, HighZeroBytesDroppedBigSize(payload.amt_to_forward), required),
                                (4, HighZeroBytesDroppedBigSize(payload.outgoing_cltv_value), required),
                                (6, short_channel_id, required)
index 1aa3420caf503f3704e502abe248fa869c7feded..1230d48ba1ed6d37df3a7f73f1737dc5b873c733 100644 (file)
@@ -20,13 +20,13 @@ use crate::ln::channelmanager::{HTLCForwardInfo, FailureCode, CLTV_FAR_FAR_AWAY,
 use crate::ln::onion_utils;
 use crate::routing::gossip::{NetworkUpdate, RoutingFees};
 use crate::routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop};
-use crate::ln::features::{InitFeatures, InvoiceFeatures};
+use crate::ln::features::{InitFeatures, Bolt11InvoiceFeatures};
 use crate::ln::msgs;
 use crate::ln::msgs::{ChannelMessageHandler, ChannelUpdate};
 use crate::ln::wire::Encode;
 use crate::util::ser::{Writeable, Writer};
 use crate::util::test_utils;
-use crate::util::config::{UserConfig, ChannelConfig};
+use crate::util::config::{UserConfig, ChannelConfig, MaxDustHTLCExposure};
 use crate::util::errors::APIError;
 
 use bitcoin::hash_types::BlockHash;
@@ -671,6 +671,7 @@ fn do_test_onion_failure_stale_channel_update(announced_channel: bool) {
        config.channel_handshake_config.announced_channel = announced_channel;
        config.channel_handshake_limits.force_announced_channel_preference = false;
        config.accept_forwards_to_priv_channels = !announced_channel;
+       config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253);
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let persister;
        let chain_monitor;
@@ -861,7 +862,7 @@ fn test_always_create_tlv_format_onion_payloads() {
        create_announced_chan_between_nodes(&nodes, 1, 2);
 
        let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
-               .with_bolt11_features(InvoiceFeatures::empty()).unwrap();
+               .with_bolt11_features(Bolt11InvoiceFeatures::empty()).unwrap();
        let (route, _payment_hash, _payment_preimage, _payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 40000);
 
        let hops = &route.paths[0].hops;
@@ -1371,10 +1372,19 @@ fn test_phantom_failure_too_low_recv_amt() {
 
 #[test]
 fn test_phantom_dust_exposure_failure() {
+       do_test_phantom_dust_exposure_failure(false);
+       do_test_phantom_dust_exposure_failure(true);
+}
+
+fn do_test_phantom_dust_exposure_failure(multiplier_dust_limit: bool) {
        // Set the max dust exposure to the dust limit.
        let max_dust_exposure = 546;
        let mut receiver_config = UserConfig::default();
-       receiver_config.channel_config.max_dust_htlc_exposure_msat = max_dust_exposure;
+       // Default test fee estimator rate is 253, so to set the max dust exposure to the dust limit,
+       // we need to set the multiplier to 2.
+       receiver_config.channel_config.max_dust_htlc_exposure =
+               if multiplier_dust_limit { MaxDustHTLCExposure::FeeRateMultiplier(2) }
+               else { MaxDustHTLCExposure::FixedLimitMsat(max_dust_exposure) };
        receiver_config.channel_handshake_config.announced_channel = true;
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
index 3b62c856334596b85bf58b8ee96b1a0eed8f36f6..52eb7bcb54298a7cc8e8fc418f77d4de66babd69 100644 (file)
@@ -645,7 +645,7 @@ impl_writeable_tlv_based_enum!(HTLCFailReasonRepr,
        },
        (1, Reason) => {
                (0, failure_code, required),
-               (2, data, vec_type),
+               (2, data, required_vec),
        },
 ;);
 
index 2ac24baa58b3466315c2628c711f17e4f3d17d73..30e718dccd65321cd5fee3f3d2fd632a0fce6d61 100644 (file)
@@ -239,7 +239,7 @@ impl Retry {
                        },
                        #[cfg(all(not(feature = "no-std"), not(test)))]
                        (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) =>
-                               *max_duration >= std::time::Instant::now().duration_since(*first_attempted_at),
+                               *max_duration >= crate::util::time::MonotonicTime::now().duration_since(*first_attempted_at),
                        #[cfg(all(not(feature = "no-std"), test))]
                        (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) =>
                                *max_duration >= SinceEpoch::now().duration_since(*first_attempted_at),
@@ -274,7 +274,7 @@ pub(crate) struct PaymentAttemptsUsingTime<T: Time> {
 }
 
 #[cfg(not(any(feature = "no-std", test)))]
-type ConfiguredTime = std::time::Instant;
+type ConfiguredTime = crate::util::time::MonotonicTime;
 #[cfg(feature = "no-std")]
 type ConfiguredTime = crate::util::time::Eternity;
 #[cfg(all(not(feature = "no-std"), test))]
@@ -669,7 +669,7 @@ impl OutboundPayments {
 
                let route = router.find_route_with_id(
                        &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
-                       Some(&first_hops.iter().collect::<Vec<_>>()), &inflight_htlcs(),
+                       Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs(),
                        payment_hash, payment_id,
                ).map_err(|_| RetryableSendFailure::RouteNotFound)?;
 
@@ -712,7 +712,7 @@ impl OutboundPayments {
 
                let route = match router.find_route_with_id(
                        &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
-                       Some(&first_hops.iter().collect::<Vec<_>>()), &inflight_htlcs(),
+                       Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs(),
                        payment_hash, payment_id,
                ) {
                        Ok(route) => route,
index 90c7ad7625ceb85dd4cbc318a755e5925ef55390..2ae606106c92a7591be57770bf6627a3bac9dc95 100644 (file)
@@ -18,7 +18,7 @@ use crate::chain::transaction::OutPoint;
 use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason};
 use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS;
 use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS, RecentPaymentDetails, RecipientOnionFields, HTLCForwardInfo, PendingHTLCRouting, PendingAddHTLCInfo};
-use crate::ln::features::InvoiceFeatures;
+use crate::ln::features::Bolt11InvoiceFeatures;
 use crate::ln::{msgs, PaymentSecret, PaymentPreimage};
 use crate::ln::msgs::ChannelMessageHandler;
 use crate::ln::outbound_payment::Retry;
@@ -1736,6 +1736,133 @@ fn do_test_intercepted_payment(test: InterceptTest) {
        }
 }
 
+#[test]
+fn accept_underpaying_htlcs_config() {
+       do_accept_underpaying_htlcs_config(1);
+       do_accept_underpaying_htlcs_config(2);
+       do_accept_underpaying_htlcs_config(3);
+}
+
+fn do_accept_underpaying_htlcs_config(num_mpp_parts: usize) {
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let mut intercept_forwards_config = test_default_channel_config();
+       intercept_forwards_config.accept_intercept_htlcs = true;
+       let mut underpay_config = test_default_channel_config();
+       underpay_config.channel_config.accept_underpaying_htlcs = true;
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(intercept_forwards_config), Some(underpay_config)]);
+       let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       let mut chan_ids = Vec::new();
+       for _ in 0..num_mpp_parts {
+               let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000, 0);
+               let channel_id = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 2_000_000, 0).0.channel_id;
+               chan_ids.push(channel_id);
+       }
+
+       // Send the initial payment.
+       let amt_msat = 900_000;
+       let skimmed_fee_msat = 20;
+       let mut route_hints = Vec::new();
+       for _ in 0..num_mpp_parts {
+               route_hints.push(RouteHint(vec![RouteHintHop {
+                       src_node_id: nodes[1].node.get_our_node_id(),
+                       short_channel_id: nodes[1].node.get_intercept_scid(),
+                       fees: RoutingFees {
+                               base_msat: 1000,
+                               proportional_millionths: 0,
+                       },
+                       cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
+                       htlc_minimum_msat: None,
+                       htlc_maximum_msat: Some(amt_msat / num_mpp_parts as u64 + 5),
+               }]));
+       }
+       let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
+               .with_route_hints(route_hints).unwrap()
+               .with_bolt11_features(nodes[2].node.invoice_features()).unwrap();
+       let route_params = RouteParameters {
+               payment_params,
+               final_value_msat: amt_msat,
+       };
+       let (payment_hash, payment_secret) = nodes[2].node.create_inbound_payment(Some(amt_msat), 60 * 60, None).unwrap();
+       nodes[0].node.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret),
+               PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
+       check_added_monitors!(nodes[0], num_mpp_parts); // one monitor per path
+       let mut events: Vec<SendEvent> = nodes[0].node.get_and_clear_pending_msg_events().into_iter().map(|e| SendEvent::from_event(e)).collect();
+       assert_eq!(events.len(), num_mpp_parts);
+
+       // Forward the intercepted payments.
+       for (idx, ev) in events.into_iter().enumerate() {
+               nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &ev.msgs[0]);
+               do_commitment_signed_dance(&nodes[1], &nodes[0], &ev.commitment_msg, false, true);
+
+               let events = nodes[1].node.get_and_clear_pending_events();
+               assert_eq!(events.len(), 1);
+               let (intercept_id, expected_outbound_amt_msat) = match events[0] {
+                       crate::events::Event::HTLCIntercepted {
+                               intercept_id, expected_outbound_amount_msat, payment_hash: pmt_hash, ..
+                       } => {
+                               assert_eq!(pmt_hash, payment_hash);
+                               (intercept_id, expected_outbound_amount_msat)
+                       },
+                       _ => panic!()
+               };
+               nodes[1].node.forward_intercepted_htlc(intercept_id, &chan_ids[idx],
+                       nodes[2].node.get_our_node_id(), expected_outbound_amt_msat - skimmed_fee_msat).unwrap();
+               expect_pending_htlcs_forwardable!(nodes[1]);
+               let payment_event = {
+                       {
+                               let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
+                               assert_eq!(added_monitors.len(), 1);
+                               added_monitors.clear();
+                       }
+                       let mut events = nodes[1].node.get_and_clear_pending_msg_events();
+                       assert_eq!(events.len(), 1);
+                       SendEvent::from_event(events.remove(0))
+               };
+               nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
+               do_commitment_signed_dance(&nodes[2], &nodes[1], &payment_event.commitment_msg, false, true);
+               if idx == num_mpp_parts - 1 {
+                       expect_pending_htlcs_forwardable!(nodes[2]);
+               }
+       }
+
+       // Claim the payment and check that the skimmed fee is as expected.
+       let payment_preimage = nodes[2].node.get_payment_preimage(payment_hash, payment_secret).unwrap();
+       let events = nodes[2].node.get_and_clear_pending_events();
+       assert_eq!(events.len(), 1);
+       match events[0] {
+               crate::events::Event::PaymentClaimable {
+                       ref payment_hash, ref purpose, amount_msat, counterparty_skimmed_fee_msat, receiver_node_id, ..
+               } => {
+                       assert_eq!(payment_hash, payment_hash);
+                       assert_eq!(amt_msat - skimmed_fee_msat * num_mpp_parts as u64, amount_msat);
+                       assert_eq!(skimmed_fee_msat * num_mpp_parts as u64, counterparty_skimmed_fee_msat);
+                       assert_eq!(nodes[2].node.get_our_node_id(), receiver_node_id.unwrap());
+                       match purpose {
+                               crate::events::PaymentPurpose::InvoicePayment { payment_preimage: ev_payment_preimage,
+                                       payment_secret: ev_payment_secret, .. } =>
+                               {
+                                       assert_eq!(payment_preimage, ev_payment_preimage.unwrap());
+                                       assert_eq!(payment_secret, *ev_payment_secret);
+                               },
+                               _ => panic!(),
+                       }
+               },
+               _ => panic!("Unexpected event"),
+       }
+       let mut expected_paths_vecs = Vec::new();
+       let mut expected_paths = Vec::new();
+       for _ in 0..num_mpp_parts { expected_paths_vecs.push(vec!(&nodes[1], &nodes[2])); }
+       for i in 0..num_mpp_parts { expected_paths.push(&expected_paths_vecs[i][..]); }
+       let total_fee_msat = do_claim_payment_along_route_with_extra_penultimate_hop_fees(
+               &nodes[0], &expected_paths[..], &vec![skimmed_fee_msat as u32; num_mpp_parts][..], false,
+               payment_preimage);
+       // The sender doesn't know that the penultimate hop took an extra fee.
+       expect_payment_sent(&nodes[0], payment_preimage,
+               Some(Some(total_fee_msat - skimmed_fee_msat * num_mpp_parts as u64)), true);
+}
+
 #[derive(PartialEq)]
 enum AutoRetry {
        Success,
@@ -1776,7 +1903,7 @@ fn do_automatic_retries(test: AutoRetry) {
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
        let amt_msat = 1000;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -1995,7 +2122,7 @@ fn auto_retry_partial_failure() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -2207,7 +2334,7 @@ fn auto_retry_zero_attempts_send_error() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -2247,7 +2374,7 @@ fn fails_paying_after_rejected_by_payee() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -2294,7 +2421,7 @@ fn retry_multi_path_single_failed_payment() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -2387,7 +2514,7 @@ fn immediate_retry_on_failure() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -2475,7 +2602,7 @@ fn no_extra_retries_on_back_to_back_fail() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -2677,7 +2804,7 @@ fn test_simple_partial_retry() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -2843,7 +2970,7 @@ fn test_threaded_payment_retries() {
        let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
        #[cfg(not(feature = "std"))]
        let payment_expiry_secs = 60 * 60;
-       let mut invoice_features = InvoiceFeatures::empty();
+       let mut invoice_features = Bolt11InvoiceFeatures::empty();
        invoice_features.set_variable_length_onion_required();
        invoice_features.set_payment_secret_required();
        invoice_features.set_basic_mpp_optional();
@@ -3091,7 +3218,7 @@ fn do_claim_from_closed_chan(fail_payment: bool) {
                final_value_msat: 10_000_000,
        };
        let mut route = nodes[0].router.find_route(&nodes[0].node.get_our_node_id(), &route_params,
-               None, &nodes[0].node.compute_inflight_htlcs()).unwrap();
+               None, nodes[0].node.compute_inflight_htlcs()).unwrap();
        // Make sure the route is ordered as the B->D path before C->D
        route.paths.sort_by(|a, _| if a.hops[0].pubkey == nodes[1].node.get_our_node_id() {
                std::cmp::Ordering::Less } else { std::cmp::Ordering::Greater });
index 931e8c4e4245d8485962015f9937b42f25e17de6..1a39bbb3ae408e7047159e6d9f3f63267188b61f 100644 (file)
@@ -607,11 +607,11 @@ impl Peer {
 /// issues such as overly long function definitions.
 ///
 /// This is not exported to bindings users as `Arc`s don't make sense in bindings.
-pub type SimpleArcPeerManager<SD, M, T, F, C, L, R> = PeerManager<
+pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<
        SD,
        Arc<SimpleArcChannelManager<M, T, F, L>>,
        Arc<P2PGossipSync<Arc<NetworkGraph<Arc<L>>>, Arc<C>, Arc<L>>>,
-       Arc<SimpleArcOnionMessenger<L, R>>,
+       Arc<SimpleArcOnionMessenger<L>>,
        Arc<L>,
        IgnoringMessageHandler,
        Arc<KeysManager>
@@ -626,12 +626,12 @@ pub type SimpleArcPeerManager<SD, M, T, F, C, L, R> = PeerManager<
 ///
 /// This is not exported to bindings users as general type aliases don't make sense in bindings.
 pub type SimpleRefPeerManager<
-       'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, SD, M, T, F, C, L, R
+       'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, SD, M, T, F, C, L
 > = PeerManager<
        SD,
        &'n SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'm, M, T, F, L>,
        &'f P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>,
-       &'i SimpleRefOnionMessenger<'g, 'm, 'n, L, R>,
+       &'i SimpleRefOnionMessenger<'g, 'm, 'n, L>,
        &'f L,
        IgnoringMessageHandler,
        &'c KeysManager
@@ -641,6 +641,9 @@ pub type SimpleRefPeerManager<
 /// A generic trait which is implemented for all [`PeerManager`]s. This makes bounding functions or
 /// structs on any [`PeerManager`] much simpler as only this trait is needed as a bound, rather
 /// than the full set of bounds on [`PeerManager`] itself.
+///
+/// This is not exported to bindings users as general cover traits aren't useful in other
+/// languages.
 #[allow(missing_docs)]
 pub trait APeerManager {
        type Descriptor: SocketDescriptor;
index 3a6a8b92b37d323c2f431fa55f2ba2376b2fc4b4..40ab57c3e4ccac0590623fc4c34f1cb4f76b1eeb 100644 (file)
@@ -21,7 +21,7 @@ use crate::ln::features::ChannelTypeFeatures;
 use crate::ln::msgs;
 use crate::ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, ChannelUpdate, ErrorAction};
 use crate::ln::wire::Encode;
-use crate::util::config::UserConfig;
+use crate::util::config::{UserConfig, MaxDustHTLCExposure};
 use crate::util::ser::Writeable;
 use crate::util::test_utils;
 
@@ -141,10 +141,12 @@ fn do_test_1_conf_open(connect_style: ConnectStyle) {
        alice_config.channel_handshake_config.minimum_depth = 1;
        alice_config.channel_handshake_config.announced_channel = true;
        alice_config.channel_handshake_limits.force_announced_channel_preference = false;
+       alice_config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253);
        let mut bob_config = UserConfig::default();
        bob_config.channel_handshake_config.minimum_depth = 1;
        bob_config.channel_handshake_config.announced_channel = true;
        bob_config.channel_handshake_limits.force_announced_channel_preference = false;
+       bob_config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253);
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(alice_config), Some(bob_config)]);
index bf2fb1de1e30d4a9ff3bf1fa5498d8f37fbbf5f8..b53c617916a16deb8efc52b0197dacd61f5af780 100644 (file)
@@ -384,7 +384,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
        fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
        persister = test_utils::TestPersister::new();
        let keys_manager = &chanmon_cfgs[0].keys_manager;
-       new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager);
+       new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster, &logger, &fee_estimator, &persister, keys_manager);
        nodes[0].chain_monitor = &new_chain_monitor;
 
 
index a2ec37a8abbaf113afe57e5bbcaa1fdafcbc40a0..3aa48c1b45d2f8f49b17746db0aa7c33d0d2fca1 100644 (file)
@@ -12,7 +12,7 @@
 use crate::sign::{EntropySource, SignerProvider};
 use crate::chain::transaction::OutPoint;
 use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
-use crate::ln::channelmanager::{self, PaymentSendFailure, PaymentId, RecipientOnionFields};
+use crate::ln::channelmanager::{self, PaymentSendFailure, PaymentId, RecipientOnionFields, ChannelShutdownState, ChannelDetails};
 use crate::routing::router::{PaymentParameters, get_route};
 use crate::ln::msgs;
 use crate::ln::msgs::{ChannelMessageHandler, ErrorAction};
@@ -67,6 +67,169 @@ fn pre_funding_lock_shutdown_test() {
        check_closed_event!(nodes[1], 1, ClosureReason::CooperativeClosure);
 }
 
+#[test]
+fn expect_channel_shutdown_state() {
+       // Test sending a shutdown prior to channel_ready after funding generation
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+       let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NotShuttingDown);
+
+       nodes[0].node.close_channel(&chan_1.2, &nodes[1].node.get_our_node_id()).unwrap();
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ShutdownInitiated);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NotShuttingDown);
+
+       let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+
+       // node1 goes into NegotiatingClosingFee since there are no HTLCs in flight, note that it
+       // doesnt mean that node1 has sent/recved its closing signed message
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ShutdownInitiated);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
+
+       let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_shutdown);
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
+
+       let node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_closing_signed);
+       let node_1_closing_signed = get_event_msg!(nodes[1], MessageSendEvent::SendClosingSigned, nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_closing_signed(&nodes[1].node.get_our_node_id(), &node_1_closing_signed);
+       let (_, node_0_2nd_closing_signed) = get_closing_signed_broadcast!(nodes[0].node, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_2nd_closing_signed.unwrap());
+       let (_, node_1_none) = get_closing_signed_broadcast!(nodes[1].node, nodes[0].node.get_our_node_id());
+       assert!(node_1_none.is_none());
+
+       assert!(nodes[0].node.list_channels().is_empty());
+       assert!(nodes[1].node.list_channels().is_empty());
+       check_closed_event!(nodes[0], 1, ClosureReason::CooperativeClosure);
+       check_closed_event!(nodes[1], 1, ClosureReason::CooperativeClosure);
+}
+
+#[test]
+fn expect_channel_shutdown_state_with_htlc() {
+       // Test sending a shutdown with outstanding updates pending.
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+       let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+       let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
+       let _chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
+
+       let (payment_preimage_0, payment_hash_0, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 100_000);
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NotShuttingDown);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NotShuttingDown);
+
+       nodes[0].node.close_channel(&chan_1.2, &nodes[1].node.get_our_node_id()).unwrap();
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ShutdownInitiated);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NotShuttingDown);
+
+       let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ShutdownInitiated);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::ResolvingHTLCs);
+
+       let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_shutdown);
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ResolvingHTLCs);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::ResolvingHTLCs);
+
+       assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+
+       // Claim Funds on Node2
+       nodes[2].node.claim_funds(payment_preimage_0);
+       check_added_monitors!(nodes[2], 1);
+       expect_payment_claimed!(nodes[2], payment_hash_0, 100_000);
+
+       // Fulfil HTLCs on node1 and node0
+       let updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
+       assert!(updates.update_add_htlcs.is_empty());
+       assert!(updates.update_fail_htlcs.is_empty());
+       assert!(updates.update_fail_malformed_htlcs.is_empty());
+       assert!(updates.update_fee.is_none());
+       assert_eq!(updates.update_fulfill_htlcs.len(), 1);
+       nodes[1].node.handle_update_fulfill_htlc(&nodes[2].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]);
+       expect_payment_forwarded!(nodes[1], nodes[0], nodes[2], Some(1000), false, false);
+       check_added_monitors!(nodes[1], 1);
+       let updates_2 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false);
+
+       // Still in "resolvingHTLCs" on chan1 after htlc removed on chan2
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ResolvingHTLCs);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::ResolvingHTLCs);
+
+       assert!(updates_2.update_add_htlcs.is_empty());
+       assert!(updates_2.update_fail_htlcs.is_empty());
+       assert!(updates_2.update_fail_malformed_htlcs.is_empty());
+       assert!(updates_2.update_fee.is_none());
+       assert_eq!(updates_2.update_fulfill_htlcs.len(), 1);
+       nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates_2.update_fulfill_htlcs[0]);
+       commitment_signed_dance!(nodes[0], nodes[1], updates_2.commitment_signed, false, true);
+       expect_payment_sent!(nodes[0], payment_preimage_0);
+
+       // all htlcs removed, chan1 advances to NegotiatingClosingFee
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
+
+       // ClosingSignNegotion process
+       let node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_closing_signed);
+       let node_1_closing_signed = get_event_msg!(nodes[1], MessageSendEvent::SendClosingSigned, nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_closing_signed(&nodes[1].node.get_our_node_id(), &node_1_closing_signed);
+       let (_, node_0_2nd_closing_signed) = get_closing_signed_broadcast!(nodes[0].node, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_2nd_closing_signed.unwrap());
+       let (_, node_1_none) = get_closing_signed_broadcast!(nodes[1].node, nodes[0].node.get_our_node_id());
+       assert!(node_1_none.is_none());
+       check_closed_event!(nodes[0], 1, ClosureReason::CooperativeClosure);
+       check_closed_event!(nodes[1], 1, ClosureReason::CooperativeClosure);
+
+       // Shutdown basically removes the channelDetails, testing of shutdowncomplete state unnecessary
+       assert!(nodes[0].node.list_channels().is_empty());
+}
+
+#[test]
+fn expect_channel_shutdown_state_with_force_closure() {
+       // Test sending a shutdown prior to channel_ready after funding generation
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+       let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NotShuttingDown);
+       expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NotShuttingDown);
+
+       nodes[1].node.force_close_broadcasting_latest_txn(&chan_1.2, &nodes[0].node.get_our_node_id()).unwrap();
+       check_closed_broadcast!(nodes[1], true);
+       check_added_monitors!(nodes[1], 1);
+
+       expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NotShuttingDown);
+       assert!(nodes[1].node.list_channels().is_empty());
+
+       let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+       assert_eq!(node_txn.len(), 1);
+       check_spends!(node_txn[0], chan_1.3);
+       mine_transaction(&nodes[0], &node_txn[0]);
+       check_added_monitors!(nodes[0], 1);
+
+       assert!(nodes[0].node.list_channels().is_empty());
+       assert!(nodes[1].node.list_channels().is_empty());
+       check_closed_broadcast!(nodes[0], true);
+       check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
+       check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
+}
+
 #[test]
 fn updates_shutdown_wait() {
        // Test sending a shutdown with outstanding updates pending
index 4d1398644ce0d24483205b0ac04e428ba3d52482..c3d4500aaebbb0b8f0c2d6abdb4f4179bfad3cf0 100644 (file)
@@ -9,9 +9,9 @@
 
 //! Data structures and encoding for `invoice` messages.
 //!
-//! An [`Invoice`] can be built from a parsed [`InvoiceRequest`] for the "offer to be paid" flow or
-//! from a [`Refund`] as an "offer for money" flow. The expected recipient of the payment then sends
-//! the invoice to the intended payer, who will then pay it.
+//! A [`Bolt12Invoice`] can be built from a parsed [`InvoiceRequest`] for the "offer to be paid"
+//! flow or from a [`Refund`] as an "offer for money" flow. The expected recipient of the payment
+//! then sends the invoice to the intended payer, who will then pay it.
 //!
 //! The payment recipient must include a [`PaymentHash`], so as to reveal the preimage upon payment
 //! receipt, and one or more [`BlindedPath`]s for the payer to use when sending the payment.
 //! # use lightning::offers::invoice::BlindedPayInfo;
 //! # use lightning::blinded_path::BlindedPath;
 //! #
-//! # fn create_payment_paths() -> Vec<(BlindedPath, BlindedPayInfo)> { unimplemented!() }
+//! # fn create_payment_paths() -> Vec<(BlindedPayInfo, BlindedPath)> { unimplemented!() }
 //! # fn create_payment_hash() -> PaymentHash { unimplemented!() }
 //! #
-//! # fn parse_invoice_request(bytes: Vec<u8>) -> Result<(), lightning::offers::parse::ParseError> {
+//! # fn parse_invoice_request(bytes: Vec<u8>) -> Result<(), lightning::offers::parse::Bolt12ParseError> {
 //! let payment_paths = create_payment_paths();
 //! let payment_hash = create_payment_hash();
 //! let secp_ctx = Secp256k1::new();
@@ -62,7 +62,7 @@
 //! # Ok(())
 //! # }
 //!
-//! # fn parse_refund(bytes: Vec<u8>) -> Result<(), lightning::offers::parse::ParseError> {
+//! # fn parse_refund(bytes: Vec<u8>) -> Result<(), lightning::offers::parse::Bolt12ParseError> {
 //! # let payment_paths = create_payment_paths();
 //! # let payment_hash = create_payment_hash();
 //! # let secp_ctx = Secp256k1::new();
@@ -112,7 +112,7 @@ use crate::ln::msgs::DecodeError;
 use crate::offers::invoice_request::{INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
 use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TlvStream, WithoutSignatures, self};
 use crate::offers::offer::{Amount, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef};
-use crate::offers::parse::{ParseError, ParsedMessage, SemanticError};
+use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
 use crate::offers::payer::{PAYER_METADATA_TYPE, PayerTlvStream, PayerTlvStreamRef};
 use crate::offers::refund::{IV_BYTES as REFUND_IV_BYTES, Refund, RefundContents};
 use crate::offers::signer;
@@ -128,7 +128,7 @@ const DEFAULT_RELATIVE_EXPIRY: Duration = Duration::from_secs(7200);
 
 pub(super) const SIGNATURE_TAG: &'static str = concat!("lightning", "invoice", "signature");
 
-/// Builds an [`Invoice`] from either:
+/// Builds a [`Bolt12Invoice`] from either:
 /// - an [`InvoiceRequest`] for the "offer to be paid" flow or
 /// - a [`Refund`] for the "offer for money" flow.
 ///
@@ -146,17 +146,17 @@ pub struct InvoiceBuilder<'a, S: SigningPubkeyStrategy> {
        signing_pubkey_strategy: core::marker::PhantomData<S>,
 }
 
-/// Indicates how [`Invoice::signing_pubkey`] was set.
+/// Indicates how [`Bolt12Invoice::signing_pubkey`] was set.
 ///
 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub trait SigningPubkeyStrategy {}
 
-/// [`Invoice::signing_pubkey`] was explicitly set.
+/// [`Bolt12Invoice::signing_pubkey`] was explicitly set.
 ///
 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub struct ExplicitSigningPubkey {}
 
-/// [`Invoice::signing_pubkey`] was derived.
+/// [`Bolt12Invoice::signing_pubkey`] was derived.
 ///
 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub struct DerivedSigningPubkey {}
@@ -166,9 +166,9 @@ impl SigningPubkeyStrategy for DerivedSigningPubkey {}
 
 impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
        pub(super) fn for_offer(
-               invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>,
+               invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
                created_at: Duration, payment_hash: PaymentHash
-       ) -> Result<Self, SemanticError> {
+       ) -> Result<Self, Bolt12SemanticError> {
                let amount_msats = Self::check_amount_msats(invoice_request)?;
                let signing_pubkey = invoice_request.contents.inner.offer.signing_pubkey();
                let contents = InvoiceContents::ForOffer {
@@ -182,9 +182,9 @@ impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
        }
 
        pub(super) fn for_refund(
-               refund: &'a Refund, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, created_at: Duration,
+               refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration,
                payment_hash: PaymentHash, signing_pubkey: PublicKey
-       ) -> Result<Self, SemanticError> {
+       ) -> Result<Self, Bolt12SemanticError> {
                let amount_msats = refund.amount_msats();
                let contents = InvoiceContents::ForRefund {
                        refund: refund.contents.clone(),
@@ -199,9 +199,9 @@ impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
 
 impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
        pub(super) fn for_offer_using_keys(
-               invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>,
+               invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
                created_at: Duration, payment_hash: PaymentHash, keys: KeyPair
-       ) -> Result<Self, SemanticError> {
+       ) -> Result<Self, Bolt12SemanticError> {
                let amount_msats = Self::check_amount_msats(invoice_request)?;
                let signing_pubkey = invoice_request.contents.inner.offer.signing_pubkey();
                let contents = InvoiceContents::ForOffer {
@@ -215,9 +215,9 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
        }
 
        pub(super) fn for_refund_using_keys(
-               refund: &'a Refund, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, created_at: Duration,
+               refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration,
                payment_hash: PaymentHash, keys: KeyPair,
-       ) -> Result<Self, SemanticError> {
+       ) -> Result<Self, Bolt12SemanticError> {
                let amount_msats = refund.amount_msats();
                let signing_pubkey = keys.public_key();
                let contents = InvoiceContents::ForRefund {
@@ -232,22 +232,22 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
 }
 
 impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
-       fn check_amount_msats(invoice_request: &InvoiceRequest) -> Result<u64, SemanticError> {
+       fn check_amount_msats(invoice_request: &InvoiceRequest) -> Result<u64, Bolt12SemanticError> {
                match invoice_request.amount_msats() {
                        Some(amount_msats) => Ok(amount_msats),
                        None => match invoice_request.contents.inner.offer.amount() {
                                Some(Amount::Bitcoin { amount_msats }) => {
                                        amount_msats.checked_mul(invoice_request.quantity().unwrap_or(1))
-                                               .ok_or(SemanticError::InvalidAmount)
+                                               .ok_or(Bolt12SemanticError::InvalidAmount)
                                },
-                               Some(Amount::Currency { .. }) => Err(SemanticError::UnsupportedCurrency),
-                               None => Err(SemanticError::MissingAmount),
+                               Some(Amount::Currency { .. }) => Err(Bolt12SemanticError::UnsupportedCurrency),
+                               None => Err(Bolt12SemanticError::MissingAmount),
                        },
                }
        }
 
        fn fields(
-               payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, created_at: Duration,
+               payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration,
                payment_hash: PaymentHash, amount_msats: u64, signing_pubkey: PublicKey
        ) -> InvoiceFields {
                InvoiceFields {
@@ -258,9 +258,9 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
 
        fn new(
                invreq_bytes: &'a Vec<u8>, contents: InvoiceContents, keys: Option<KeyPair>
-       ) -> Result<Self, SemanticError> {
+       ) -> Result<Self, Bolt12SemanticError> {
                if contents.fields().payment_paths.is_empty() {
-                       return Err(SemanticError::MissingPaths);
+                       return Err(Bolt12SemanticError::MissingPaths);
                }
 
                Ok(Self {
@@ -271,8 +271,9 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
                })
        }
 
-       /// Sets the [`Invoice::relative_expiry`] as seconds since [`Invoice::created_at`]. Any expiry
-       /// that has already passed is valid and can be checked for using [`Invoice::is_expired`].
+       /// Sets the [`Bolt12Invoice::relative_expiry`] as seconds since [`Bolt12Invoice::created_at`].
+       /// Any expiry that has already passed is valid and can be checked for using
+       /// [`Bolt12Invoice::is_expired`].
        ///
        /// Successive calls to this method will override the previous setting.
        pub fn relative_expiry(mut self, relative_expiry_secs: u32) -> Self {
@@ -281,7 +282,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
                self
        }
 
-       /// Adds a P2WSH address to [`Invoice::fallbacks`].
+       /// Adds a P2WSH address to [`Bolt12Invoice::fallbacks`].
        ///
        /// Successive calls to this method will add another address. Caller is responsible for not
        /// adding duplicate addresses and only calling if capable of receiving to P2WSH addresses.
@@ -294,7 +295,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
                self
        }
 
-       /// Adds a P2WPKH address to [`Invoice::fallbacks`].
+       /// Adds a P2WPKH address to [`Bolt12Invoice::fallbacks`].
        ///
        /// Successive calls to this method will add another address. Caller is responsible for not
        /// adding duplicate addresses and only calling if capable of receiving to P2WPKH addresses.
@@ -307,7 +308,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
                self
        }
 
-       /// Adds a P2TR address to [`Invoice::fallbacks`].
+       /// Adds a P2TR address to [`Bolt12Invoice::fallbacks`].
        ///
        /// Successive calls to this method will add another address. Caller is responsible for not
        /// adding duplicate addresses and only calling if capable of receiving to P2TR addresses.
@@ -320,7 +321,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
                self
        }
 
-       /// Sets [`Invoice::features`] to indicate MPP may be used. Otherwise, MPP is disallowed.
+       /// Sets [`Bolt12Invoice::features`] to indicate MPP may be used. Otherwise, MPP is disallowed.
        pub fn allow_mpp(mut self) -> Self {
                self.invoice.fields_mut().features.set_basic_mpp_optional();
                self
@@ -328,33 +329,33 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
 }
 
 impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
-       /// Builds an unsigned [`Invoice`] after checking for valid semantics. It can be signed by
-       /// [`UnsignedInvoice::sign`].
-       pub fn build(self) -> Result<UnsignedInvoice<'a>, SemanticError> {
+       /// Builds an unsigned [`Bolt12Invoice`] after checking for valid semantics. It can be signed by
+       /// [`UnsignedBolt12Invoice::sign`].
+       pub fn build(self) -> Result<UnsignedBolt12Invoice<'a>, Bolt12SemanticError> {
                #[cfg(feature = "std")] {
                        if self.invoice.is_offer_or_refund_expired() {
-                               return Err(SemanticError::AlreadyExpired);
+                               return Err(Bolt12SemanticError::AlreadyExpired);
                        }
                }
 
                let InvoiceBuilder { invreq_bytes, invoice, .. } = self;
-               Ok(UnsignedInvoice { invreq_bytes, invoice })
+               Ok(UnsignedBolt12Invoice { invreq_bytes, invoice })
        }
 }
 
 impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
-       /// Builds a signed [`Invoice`] after checking for valid semantics.
+       /// Builds a signed [`Bolt12Invoice`] after checking for valid semantics.
        pub fn build_and_sign<T: secp256k1::Signing>(
                self, secp_ctx: &Secp256k1<T>
-       ) -> Result<Invoice, SemanticError> {
+       ) -> Result<Bolt12Invoice, Bolt12SemanticError> {
                #[cfg(feature = "std")] {
                        if self.invoice.is_offer_or_refund_expired() {
-                               return Err(SemanticError::AlreadyExpired);
+                               return Err(Bolt12SemanticError::AlreadyExpired);
                        }
                }
 
                let InvoiceBuilder { invreq_bytes, invoice, keys, .. } = self;
-               let unsigned_invoice = UnsignedInvoice { invreq_bytes, invoice };
+               let unsigned_invoice = UnsignedBolt12Invoice { invreq_bytes, invoice };
 
                let keys = keys.unwrap();
                let invoice = unsigned_invoice
@@ -364,13 +365,13 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
        }
 }
 
-/// A semantically valid [`Invoice`] that hasn't been signed.
-pub struct UnsignedInvoice<'a> {
+/// A semantically valid [`Bolt12Invoice`] that hasn't been signed.
+pub struct UnsignedBolt12Invoice<'a> {
        invreq_bytes: &'a Vec<u8>,
        invoice: InvoiceContents,
 }
 
-impl<'a> UnsignedInvoice<'a> {
+impl<'a> UnsignedBolt12Invoice<'a> {
        /// The public key corresponding to the key needed to sign the invoice.
        pub fn signing_pubkey(&self) -> PublicKey {
                self.invoice.fields().signing_pubkey
@@ -379,7 +380,7 @@ impl<'a> UnsignedInvoice<'a> {
        /// Signs the invoice using the given function.
        ///
        /// This is not exported to bindings users as functions aren't currently mapped.
-       pub fn sign<F, E>(self, sign: F) -> Result<Invoice, SignError<E>>
+       pub fn sign<F, E>(self, sign: F) -> Result<Bolt12Invoice, SignError<E>>
        where
                F: FnOnce(&Message) -> Result<Signature, E>
        {
@@ -402,7 +403,7 @@ impl<'a> UnsignedInvoice<'a> {
                };
                signature_tlv_stream.write(&mut bytes).unwrap();
 
-               Ok(Invoice {
+               Ok(Bolt12Invoice {
                        bytes,
                        contents: self.invoice,
                        signature,
@@ -410,39 +411,37 @@ impl<'a> UnsignedInvoice<'a> {
        }
 }
 
-/// An `Invoice` is a payment request, typically corresponding to an [`Offer`] or a [`Refund`].
+/// A `Bolt12Invoice` is a payment request, typically corresponding to an [`Offer`] or a [`Refund`].
 ///
 /// An invoice may be sent in response to an [`InvoiceRequest`] in the case of an offer or sent
 /// directly after scanning a refund. It includes all the information needed to pay a recipient.
 ///
-/// This is not exported to bindings users as its name conflicts with the BOLT 11 Invoice type.
-///
 /// [`Offer`]: crate::offers::offer::Offer
 /// [`Refund`]: crate::offers::refund::Refund
 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
-pub struct Invoice {
+pub struct Bolt12Invoice {
        bytes: Vec<u8>,
        contents: InvoiceContents,
        signature: Signature,
 }
 
-/// The contents of an [`Invoice`] for responding to either an [`Offer`] or a [`Refund`].
+/// The contents of an [`Bolt12Invoice`] for responding to either an [`Offer`] or a [`Refund`].
 ///
 /// [`Offer`]: crate::offers::offer::Offer
 /// [`Refund`]: crate::offers::refund::Refund
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 enum InvoiceContents {
-       /// Contents for an [`Invoice`] corresponding to an [`Offer`].
+       /// Contents for an [`Bolt12Invoice`] corresponding to an [`Offer`].
        ///
        /// [`Offer`]: crate::offers::offer::Offer
        ForOffer {
                invoice_request: InvoiceRequestContents,
                fields: InvoiceFields,
        },
-       /// Contents for an [`Invoice`] corresponding to a [`Refund`].
+       /// Contents for an [`Bolt12Invoice`] corresponding to a [`Refund`].
        ///
        /// [`Refund`]: crate::offers::refund::Refund
        ForRefund {
@@ -454,7 +453,7 @@ enum InvoiceContents {
 /// Invoice-specific fields for an `invoice` message.
 #[derive(Clone, Debug, PartialEq)]
 struct InvoiceFields {
-       payment_paths: Vec<(BlindedPath, BlindedPayInfo)>,
+       payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
        created_at: Duration,
        relative_expiry: Option<Duration>,
        payment_hash: PaymentHash,
@@ -464,7 +463,7 @@ struct InvoiceFields {
        signing_pubkey: PublicKey,
 }
 
-impl Invoice {
+impl Bolt12Invoice {
        /// A complete description of the purpose of the originating offer or refund. Intended to be
        /// displayed to the user but with the caveat that it has not been verified in any way.
        pub fn description(&self) -> PrintableString {
@@ -475,8 +474,11 @@ impl Invoice {
        /// needed for routing payments across them.
        ///
        /// Blinded paths provide recipient privacy by obfuscating its node id. Note, however, that this
-       /// privacy is lost if a public node id is used for [`Invoice::signing_pubkey`].
-       pub fn payment_paths(&self) -> &[(BlindedPath, BlindedPayInfo)] {
+       /// privacy is lost if a public node id is used for [`Bolt12Invoice::signing_pubkey`].
+       ///
+       /// This is not exported to bindings users as slices with non-reference types cannot be ABI
+       /// matched in another language.
+       pub fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPath)] {
                &self.contents.fields().payment_paths[..]
        }
 
@@ -485,8 +487,8 @@ impl Invoice {
                self.contents.fields().created_at
        }
 
-       /// Duration since [`Invoice::created_at`] when the invoice has expired and therefore should no
-       /// longer be paid.
+       /// Duration since [`Bolt12Invoice::created_at`] when the invoice has expired and therefore
+       /// should no longer be paid.
        pub fn relative_expiry(&self) -> Duration {
                self.contents.fields().relative_expiry.unwrap_or(DEFAULT_RELATIVE_EXPIRY)
        }
@@ -579,7 +581,7 @@ impl Invoice {
                self.contents.fields().signing_pubkey
        }
 
-       /// Signature of the invoice verified using [`Invoice::signing_pubkey`].
+       /// Signature of the invoice verified using [`Bolt12Invoice::signing_pubkey`].
        pub fn signature(&self) -> Signature {
                self.signature
        }
@@ -703,8 +705,8 @@ impl InvoiceFields {
                };
 
                InvoiceTlvStreamRef {
-                       paths: Some(Iterable(self.payment_paths.iter().map(|(path, _)| path))),
-                       blindedpay: Some(Iterable(self.payment_paths.iter().map(|(_, payinfo)| payinfo))),
+                       paths: Some(Iterable(self.payment_paths.iter().map(|(_, path)| path))),
+                       blindedpay: Some(Iterable(self.payment_paths.iter().map(|(payinfo, _)| payinfo))),
                        created_at: Some(self.created_at.as_secs()),
                        relative_expiry: self.relative_expiry.map(|duration| duration.as_secs() as u32),
                        payment_hash: Some(&self.payment_hash),
@@ -716,7 +718,7 @@ impl InvoiceFields {
        }
 }
 
-impl Writeable for Invoice {
+impl Writeable for Bolt12Invoice {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
                WithoutLength(&self.bytes).write(writer)
        }
@@ -728,12 +730,12 @@ impl Writeable for InvoiceContents {
        }
 }
 
-impl TryFrom<Vec<u8>> for Invoice {
-       type Error = ParseError;
+impl TryFrom<Vec<u8>> for Bolt12Invoice {
+       type Error = Bolt12ParseError;
 
        fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
                let parsed_invoice = ParsedMessage::<FullInvoiceTlvStream>::try_from(bytes)?;
-               Invoice::try_from(parsed_invoice)
+               Bolt12Invoice::try_from(parsed_invoice)
        }
 }
 
@@ -750,13 +752,13 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, {
 });
 
 type BlindedPathIter<'a> = core::iter::Map<
-       core::slice::Iter<'a, (BlindedPath, BlindedPayInfo)>,
-       for<'r> fn(&'r (BlindedPath, BlindedPayInfo)) -> &'r BlindedPath,
+       core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>,
+       for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPath,
 >;
 
 type BlindedPayInfoIter<'a> = core::iter::Map<
-       core::slice::Iter<'a, (BlindedPath, BlindedPayInfo)>,
-       for<'r> fn(&'r (BlindedPath, BlindedPayInfo)) -> &'r BlindedPayInfo,
+       core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>,
+       for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPayInfo,
 >;
 
 /// Information needed to route a payment across a [`BlindedPath`].
@@ -840,8 +842,8 @@ type PartialInvoiceTlvStreamRef<'a> = (
        InvoiceTlvStreamRef<'a>,
 );
 
-impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Invoice {
-       type Error = ParseError;
+impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
+       type Error = Bolt12ParseError;
 
        fn try_from(invoice: ParsedMessage<FullInvoiceTlvStream>) -> Result<Self, Self::Error> {
                let ParsedMessage { bytes, tlv_stream } = invoice;
@@ -854,18 +856,18 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Invoice {
                )?;
 
                let signature = match signature {
-                       None => return Err(ParseError::InvalidSemantics(SemanticError::MissingSignature)),
+                       None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
                        Some(signature) => signature,
                };
                let pubkey = contents.fields().signing_pubkey;
                merkle::verify_signature(&signature, SIGNATURE_TAG, &bytes, pubkey)?;
 
-               Ok(Invoice { bytes, contents, signature })
+               Ok(Bolt12Invoice { bytes, contents, signature })
        }
 }
 
 impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
-       type Error = SemanticError;
+       type Error = Bolt12SemanticError;
 
        fn try_from(tlv_stream: PartialInvoiceTlvStream) -> Result<Self, Self::Error> {
                let (
@@ -878,20 +880,20 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
                        },
                ) = tlv_stream;
 
-               let payment_paths = match (paths, blindedpay) {
-                       (None, _) => return Err(SemanticError::MissingPaths),
-                       (_, None) => return Err(SemanticError::InvalidPayInfo),
-                       (Some(paths), _) if paths.is_empty() => return Err(SemanticError::MissingPaths),
-                       (Some(paths), Some(blindedpay)) if paths.len() != blindedpay.len() => {
-                               return Err(SemanticError::InvalidPayInfo);
+               let payment_paths = match (blindedpay, paths) {
+                       (_, None) => return Err(Bolt12SemanticError::MissingPaths),
+                       (None, _) => return Err(Bolt12SemanticError::InvalidPayInfo),
+                       (_, Some(paths)) if paths.is_empty() => return Err(Bolt12SemanticError::MissingPaths),
+                       (Some(blindedpay), Some(paths)) if paths.len() != blindedpay.len() => {
+                               return Err(Bolt12SemanticError::InvalidPayInfo);
                        },
-                       (Some(paths), Some(blindedpay)) => {
-                               paths.into_iter().zip(blindedpay.into_iter()).collect::<Vec<_>>()
+                       (Some(blindedpay), Some(paths)) => {
+                               blindedpay.into_iter().zip(paths.into_iter()).collect::<Vec<_>>()
                        },
                };
 
                let created_at = match created_at {
-                       None => return Err(SemanticError::MissingCreationTime),
+                       None => return Err(Bolt12SemanticError::MissingCreationTime),
                        Some(timestamp) => Duration::from_secs(timestamp),
                };
 
@@ -900,19 +902,19 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
                        .map(Duration::from_secs);
 
                let payment_hash = match payment_hash {
-                       None => return Err(SemanticError::MissingPaymentHash),
+                       None => return Err(Bolt12SemanticError::MissingPaymentHash),
                        Some(payment_hash) => payment_hash,
                };
 
                let amount_msats = match amount {
-                       None => return Err(SemanticError::MissingAmount),
+                       None => return Err(Bolt12SemanticError::MissingAmount),
                        Some(amount) => amount,
                };
 
                let features = features.unwrap_or_else(Bolt12InvoiceFeatures::empty);
 
                let signing_pubkey = match node_id {
-                       None => return Err(SemanticError::MissingSigningPubkey),
+                       None => return Err(Bolt12SemanticError::MissingSigningPubkey),
                        Some(node_id) => node_id,
                };
 
@@ -924,7 +926,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
                match offer_tlv_stream.node_id {
                        Some(expected_signing_pubkey) => {
                                if fields.signing_pubkey != expected_signing_pubkey {
-                                       return Err(SemanticError::InvalidSigningPubkey);
+                                       return Err(Bolt12SemanticError::InvalidSigningPubkey);
                                }
 
                                let invoice_request = InvoiceRequestContents::try_from(
@@ -944,7 +946,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
 
 #[cfg(test)]
 mod tests {
-       use super::{DEFAULT_RELATIVE_EXPIRY, FallbackAddress, FullInvoiceTlvStreamRef, Invoice, InvoiceTlvStreamRef, SIGNATURE_TAG};
+       use super::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, FallbackAddress, FullInvoiceTlvStreamRef, InvoiceTlvStreamRef, SIGNATURE_TAG};
 
        use bitcoin::blockdata::script::Script;
        use bitcoin::hashes::Hash;
@@ -962,7 +964,7 @@ mod tests {
        use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
        use crate::offers::merkle::{SignError, SignatureTlvStreamRef, self};
        use crate::offers::offer::{OfferBuilder, OfferTlvStreamRef, Quantity};
-       use crate::offers::parse::{ParseError, SemanticError};
+       use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
        use crate::offers::payer::PayerTlvStreamRef;
        use crate::offers::refund::RefundBuilder;
        use crate::offers::test_utils::*;
@@ -1052,8 +1054,8 @@ mod tests {
                                        payer_note: None,
                                },
                                InvoiceTlvStreamRef {
-                                       paths: Some(Iterable(payment_paths.iter().map(|(path, _)| path))),
-                                       blindedpay: Some(Iterable(payment_paths.iter().map(|(_, payinfo)| payinfo))),
+                                       paths: Some(Iterable(payment_paths.iter().map(|(_, path)| path))),
+                                       blindedpay: Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))),
                                        created_at: Some(now.as_secs()),
                                        relative_expiry: None,
                                        payment_hash: Some(&payment_hash),
@@ -1066,7 +1068,7 @@ mod tests {
                        ),
                );
 
-               if let Err(e) = Invoice::try_from(buffer) {
+               if let Err(e) = Bolt12Invoice::try_from(buffer) {
                        panic!("error parsing invoice: {:?}", e);
                }
        }
@@ -1130,8 +1132,8 @@ mod tests {
                                        payer_note: None,
                                },
                                InvoiceTlvStreamRef {
-                                       paths: Some(Iterable(payment_paths.iter().map(|(path, _)| path))),
-                                       blindedpay: Some(Iterable(payment_paths.iter().map(|(_, payinfo)| payinfo))),
+                                       paths: Some(Iterable(payment_paths.iter().map(|(_, path)| path))),
+                                       blindedpay: Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))),
                                        created_at: Some(now.as_secs()),
                                        relative_expiry: None,
                                        payment_hash: Some(&payment_hash),
@@ -1144,7 +1146,7 @@ mod tests {
                        ),
                );
 
-               if let Err(e) = Invoice::try_from(buffer) {
+               if let Err(e) = Bolt12Invoice::try_from(buffer) {
                        panic!("error parsing invoice: {:?}", e);
                }
        }
@@ -1181,7 +1183,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::AlreadyExpired),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::AlreadyExpired),
                }
        }
 
@@ -1209,7 +1211,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::AlreadyExpired),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::AlreadyExpired),
                }
        }
 
@@ -1254,7 +1256,7 @@ mod tests {
                        payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx
                ) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidMetadata),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata),
                }
 
                let desc = "foo".to_string();
@@ -1270,7 +1272,7 @@ mod tests {
                        payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx
                ) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidMetadata),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata),
                }
        }
 
@@ -1377,7 +1379,7 @@ mod tests {
                        .respond_with_no_std(payment_paths(), payment_hash(), now())
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
                }
        }
 
@@ -1494,43 +1496,43 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               if let Err(e) = Invoice::try_from(buffer) {
+               if let Err(e) = Bolt12Invoice::try_from(buffer) {
                        panic!("error parsing invoice: {:?}", e);
                }
 
                let mut tlv_stream = invoice.as_tlv_stream();
                tlv_stream.3.paths = None;
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPaths)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaths)),
                }
 
                let mut tlv_stream = invoice.as_tlv_stream();
                tlv_stream.3.blindedpay = None;
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidPayInfo)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidPayInfo)),
                }
 
                let empty_payment_paths = vec![];
                let mut tlv_stream = invoice.as_tlv_stream();
-               tlv_stream.3.paths = Some(Iterable(empty_payment_paths.iter().map(|(path, _)| path)));
+               tlv_stream.3.paths = Some(Iterable(empty_payment_paths.iter().map(|(_, path)| path)));
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPaths)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaths)),
                }
 
                let mut payment_paths = payment_paths();
                payment_paths.pop();
                let mut tlv_stream = invoice.as_tlv_stream();
-               tlv_stream.3.blindedpay = Some(Iterable(payment_paths.iter().map(|(_, payinfo)| payinfo)));
+               tlv_stream.3.blindedpay = Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo)));
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidPayInfo)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidPayInfo)),
                }
        }
 
@@ -1549,17 +1551,17 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               if let Err(e) = Invoice::try_from(buffer) {
+               if let Err(e) = Bolt12Invoice::try_from(buffer) {
                        panic!("error parsing invoice: {:?}", e);
                }
 
                let mut tlv_stream = invoice.as_tlv_stream();
                tlv_stream.3.created_at = None;
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingCreationTime));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingCreationTime));
                        },
                }
        }
@@ -1580,7 +1582,7 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               match Invoice::try_from(buffer) {
+               match Bolt12Invoice::try_from(buffer) {
                        Ok(invoice) => assert_eq!(invoice.relative_expiry(), Duration::from_secs(3600)),
                        Err(e) => panic!("error parsing invoice: {:?}", e),
                }
@@ -1601,17 +1603,17 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               if let Err(e) = Invoice::try_from(buffer) {
+               if let Err(e) = Bolt12Invoice::try_from(buffer) {
                        panic!("error parsing invoice: {:?}", e);
                }
 
                let mut tlv_stream = invoice.as_tlv_stream();
                tlv_stream.3.payment_hash = None;
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPaymentHash));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaymentHash));
                        },
                }
        }
@@ -1631,16 +1633,16 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               if let Err(e) = Invoice::try_from(buffer) {
+               if let Err(e) = Bolt12Invoice::try_from(buffer) {
                        panic!("error parsing invoice: {:?}", e);
                }
 
                let mut tlv_stream = invoice.as_tlv_stream();
                tlv_stream.3.amount = None;
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingAmount)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingAmount)),
                }
        }
 
@@ -1660,7 +1662,7 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               match Invoice::try_from(buffer) {
+               match Bolt12Invoice::try_from(buffer) {
                        Ok(invoice) => {
                                let mut features = Bolt12InvoiceFeatures::empty();
                                features.set_basic_mpp_optional();
@@ -1705,7 +1707,7 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               match Invoice::try_from(buffer) {
+               match Bolt12Invoice::try_from(buffer) {
                        Ok(invoice) => {
                                assert_eq!(
                                        invoice.fallbacks(),
@@ -1749,17 +1751,17 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               if let Err(e) = Invoice::try_from(buffer) {
+               if let Err(e) = Bolt12Invoice::try_from(buffer) {
                        panic!("error parsing invoice: {:?}", e);
                }
 
                let mut tlv_stream = invoice.as_tlv_stream();
                tlv_stream.3.node_id = None;
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSigningPubkey));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
                        },
                }
 
@@ -1767,10 +1769,10 @@ mod tests {
                let mut tlv_stream = invoice.as_tlv_stream();
                tlv_stream.3.node_id = Some(&invalid_pubkey);
 
-               match Invoice::try_from(tlv_stream.to_bytes()) {
+               match Bolt12Invoice::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidSigningPubkey));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidSigningPubkey));
                        },
                }
        }
@@ -1789,9 +1791,9 @@ mod tests {
                        .invoice
                        .write(&mut buffer).unwrap();
 
-               match Invoice::try_from(buffer) {
+               match Bolt12Invoice::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSignature)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
                }
        }
 
@@ -1812,10 +1814,10 @@ mod tests {
                let mut buffer = Vec::new();
                invoice.write(&mut buffer).unwrap();
 
-               match Invoice::try_from(buffer) {
+               match Bolt12Invoice::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSignature(secp256k1::Error::InvalidSignature));
+                               assert_eq!(e, Bolt12ParseError::InvalidSignature(secp256k1::Error::InvalidSignature));
                        },
                }
        }
@@ -1838,9 +1840,9 @@ mod tests {
                BigSize(32).write(&mut encoded_invoice).unwrap();
                [42u8; 32].write(&mut encoded_invoice).unwrap();
 
-               match Invoice::try_from(encoded_invoice) {
+               match Bolt12Invoice::try_from(encoded_invoice) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
                }
        }
 }
index e843264b4e3ed851afc5642fc1e8b5d0869854e5..122049b9295438b0147224a76c6efbc75455146c 100644 (file)
 
 use crate::io;
 use crate::ln::msgs::DecodeError;
-use crate::offers::parse::SemanticError;
+use crate::offers::parse::Bolt12SemanticError;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
 use crate::util::string::UntrustedString;
 
 use crate::prelude::*;
 
-/// An error in response to an [`InvoiceRequest`] or an [`Invoice`].
+/// An error in response to an [`InvoiceRequest`] or an [`Bolt12Invoice`].
 ///
 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 pub struct InvoiceError {
-       /// The field in the [`InvoiceRequest`] or the [`Invoice`] that contained an error.
+       /// The field in the [`InvoiceRequest`] or the [`Bolt12Invoice`] that contained an error.
        ///
        /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-       /// [`Invoice`]: crate::offers::invoice::Invoice
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        pub erroneous_field: Option<ErroneousField>,
 
        /// An explanation of the error.
        pub message: UntrustedString,
 }
 
-/// The field in the [`InvoiceRequest`] or the [`Invoice`] that contained an error.
+/// The field in the [`InvoiceRequest`] or the [`Bolt12Invoice`] that contained an error.
 ///
 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 pub struct ErroneousField {
@@ -93,8 +93,8 @@ impl Readable for InvoiceError {
        }
 }
 
-impl From<SemanticError> for InvoiceError {
-       fn from(error: SemanticError) -> Self {
+impl From<Bolt12SemanticError> for InvoiceError {
+       fn from(error: Bolt12SemanticError) -> Self {
                InvoiceError {
                        erroneous_field: None,
                        message: UntrustedString(format!("{:?}", error)),
index ed884848f4a015a85f365a8801998afc10801224..f014bf120021b52b613a6726f988e8fb6b076f1b 100644 (file)
 //!
 //! An [`InvoiceRequest`] can be built from a parsed [`Offer`] as an "offer to be paid". It is
 //! typically constructed by a customer and sent to the merchant who had published the corresponding
-//! offer. The recipient of the request responds with an [`Invoice`].
+//! offer. The recipient of the request responds with a [`Bolt12Invoice`].
 //!
 //! For an "offer for money" (e.g., refund, ATM withdrawal), where an offer doesn't exist as a
 //! precursor, see [`Refund`].
 //!
-//! [`Invoice`]: crate::offers::invoice::Invoice
+//! [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 //! [`Refund`]: crate::offers::refund::Refund
 //!
 //! ```
@@ -30,7 +30,7 @@
 //! use lightning::offers::offer::Offer;
 //! use lightning::util::ser::Writeable;
 //!
-//! # fn parse() -> Result<(), lightning::offers::parse::ParseError> {
+//! # fn parse() -> Result<(), lightning::offers::parse::Bolt12ParseError> {
 //! let secp_ctx = Secp256k1::new();
 //! let keys = KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32])?);
 //! let pubkey = PublicKey::from(keys);
@@ -68,7 +68,7 @@ use crate::ln::msgs::DecodeError;
 use crate::offers::invoice::{BlindedPayInfo, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder};
 use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, self};
 use crate::offers::offer::{Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef};
-use crate::offers::parse::{ParseError, ParsedMessage, SemanticError};
+use crate::offers::parse::{Bolt12ParseError, ParsedMessage, Bolt12SemanticError};
 use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
 use crate::offers::signer::{Metadata, MetadataMaterial};
 use crate::util::ser::{HighZeroBytesDroppedBigSize, SeekReadable, WithoutLength, Writeable, Writer};
@@ -171,10 +171,10 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
        /// by the offer.
        ///
        /// Successive calls to this method will override the previous setting.
-       pub fn chain(mut self, network: Network) -> Result<Self, SemanticError> {
+       pub fn chain(mut self, network: Network) -> Result<Self, Bolt12SemanticError> {
                let chain = ChainHash::using_genesis_block(network);
                if !self.offer.supports_chain(chain) {
-                       return Err(SemanticError::UnsupportedChain);
+                       return Err(Bolt12SemanticError::UnsupportedChain);
                }
 
                self.invoice_request.chain = Some(chain);
@@ -187,7 +187,7 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
        /// Successive calls to this method will override the previous setting.
        ///
        /// [`quantity`]: Self::quantity
-       pub fn amount_msats(mut self, amount_msats: u64) -> Result<Self, SemanticError> {
+       pub fn amount_msats(mut self, amount_msats: u64) -> Result<Self, Bolt12SemanticError> {
                self.invoice_request.offer.check_amount_msats_for_quantity(
                        Some(amount_msats), self.invoice_request.quantity
                )?;
@@ -199,7 +199,7 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
        /// does not conform to [`Offer::is_valid_quantity`].
        ///
        /// Successive calls to this method will override the previous setting.
-       pub fn quantity(mut self, quantity: u64) -> Result<Self, SemanticError> {
+       pub fn quantity(mut self, quantity: u64) -> Result<Self, Bolt12SemanticError> {
                self.invoice_request.offer.check_quantity(Some(quantity))?;
                self.invoice_request.quantity = Some(quantity);
                Ok(self)
@@ -215,17 +215,17 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
 
        fn build_with_checks(mut self) -> Result<
                (UnsignedInvoiceRequest<'a>, Option<KeyPair>, Option<&'b Secp256k1<T>>),
-               SemanticError
+               Bolt12SemanticError
        > {
                #[cfg(feature = "std")] {
                        if self.offer.is_expired() {
-                               return Err(SemanticError::AlreadyExpired);
+                               return Err(Bolt12SemanticError::AlreadyExpired);
                        }
                }
 
                let chain = self.invoice_request.chain();
                if !self.offer.supports_chain(chain) {
-                       return Err(SemanticError::UnsupportedChain);
+                       return Err(Bolt12SemanticError::UnsupportedChain);
                }
 
                if chain == self.offer.implied_chain() {
@@ -233,7 +233,7 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
                }
 
                if self.offer.amount().is_none() && self.invoice_request.amount_msats.is_none() {
-                       return Err(SemanticError::MissingAmount);
+                       return Err(Bolt12SemanticError::MissingAmount);
                }
 
                self.invoice_request.offer.check_quantity(self.invoice_request.quantity)?;
@@ -247,7 +247,7 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
        fn build_without_checks(mut self) ->
                (UnsignedInvoiceRequest<'a>, Option<KeyPair>, Option<&'b Secp256k1<T>>)
        {
-               // Create the metadata for stateless verification of aInvoice.
+               // Create the metadata for stateless verification of a Bolt12Invoice.
                let mut keys = None;
                let secp_ctx = self.secp_ctx.clone();
                if self.invoice_request.payer.0.has_derivation_material() {
@@ -290,7 +290,7 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
 impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, ExplicitPayerId, T> {
        /// Builds an unsigned [`InvoiceRequest`] after checking for valid semantics. It can be signed
        /// by [`UnsignedInvoiceRequest::sign`].
-       pub fn build(self) -> Result<UnsignedInvoiceRequest<'a>, SemanticError> {
+       pub fn build(self) -> Result<UnsignedInvoiceRequest<'a>, Bolt12SemanticError> {
                let (unsigned_invoice_request, keys, _) = self.build_with_checks()?;
                debug_assert!(keys.is_none());
                Ok(unsigned_invoice_request)
@@ -299,7 +299,7 @@ impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, ExplicitPayerI
 
 impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T> {
        /// Builds a signed [`InvoiceRequest`] after checking for valid semantics.
-       pub fn build_and_sign(self) -> Result<InvoiceRequest, SemanticError> {
+       pub fn build_and_sign(self) -> Result<InvoiceRequest, Bolt12SemanticError> {
                let (unsigned_invoice_request, keys, secp_ctx) = self.build_with_checks()?;
                debug_assert!(keys.is_some());
 
@@ -381,12 +381,12 @@ impl<'a> UnsignedInvoiceRequest<'a> {
        }
 }
 
-/// An `InvoiceRequest` is a request for an [`Invoice`] formulated from an [`Offer`].
+/// An `InvoiceRequest` is a request for a [`Bolt12Invoice`] formulated from an [`Offer`].
 ///
 /// An offer may provide choices such as quantity, amount, chain, features, etc. An invoice request
 /// specifies these such that its recipient can send an invoice for payment.
 ///
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 /// [`Offer`]: crate::offers::offer::Offer
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
@@ -396,9 +396,9 @@ pub struct InvoiceRequest {
        signature: Signature,
 }
 
-/// The contents of an [`InvoiceRequest`], which may be shared with an [`Invoice`].
+/// The contents of an [`InvoiceRequest`], which may be shared with an [`Bolt12Invoice`].
 ///
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 pub(super) struct InvoiceRequestContents {
@@ -480,8 +480,8 @@ impl InvoiceRequest {
        /// [`Duration`]: core::time::Duration
        #[cfg(feature = "std")]
        pub fn respond_with(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash
-       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, SemanticError> {
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash
+       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> {
                let created_at = std::time::SystemTime::now()
                        .duration_since(std::time::SystemTime::UNIX_EPOCH)
                        .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
@@ -492,8 +492,8 @@ impl InvoiceRequest {
        /// Creates an [`InvoiceBuilder`] for the request with the given required fields.
        ///
        /// Unless [`InvoiceBuilder::relative_expiry`] is set, the invoice will expire two hours after
-       /// `created_at`, which is used to set [`Invoice::created_at`]. Useful for `no-std` builds where
-       /// [`std::time::SystemTime`] is not available.
+       /// `created_at`, which is used to set [`Bolt12Invoice::created_at`]. Useful for `no-std` builds
+       /// where [`std::time::SystemTime`] is not available.
        ///
        /// The caller is expected to remember the preimage of `payment_hash` in order to claim a payment
        /// for the invoice.
@@ -507,32 +507,32 @@ impl InvoiceRequest {
        ///
        /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
        ///
-       /// [`Invoice::created_at`]: crate::offers::invoice::Invoice::created_at
+       /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
        pub fn respond_with_no_std(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                created_at: core::time::Duration
-       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, SemanticError> {
+       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> {
                if self.features().requires_unknown_bits() {
-                       return Err(SemanticError::UnknownRequiredFeatures);
+                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
                }
 
                InvoiceBuilder::for_offer(self, payment_paths, created_at, payment_hash)
        }
 
        /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
-       /// derived signing keys from the originating [`Offer`] to sign the [`Invoice`]. Must use the
-       /// same [`ExpandedKey`] as the one used to create the offer.
+       /// derived signing keys from the originating [`Offer`] to sign the [`Bolt12Invoice`]. Must use
+       /// the same [`ExpandedKey`] as the one used to create the offer.
        ///
        /// See [`InvoiceRequest::respond_with`] for further details.
        ///
        /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
        ///
-       /// [`Invoice`]: crate::offers::invoice::Invoice
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        #[cfg(feature = "std")]
        pub fn verify_and_respond_using_derived_keys<T: secp256k1::Signing>(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                expanded_key: &ExpandedKey, secp_ctx: &Secp256k1<T>
-       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, SemanticError> {
+       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError> {
                let created_at = std::time::SystemTime::now()
                        .duration_since(std::time::SystemTime::UNIX_EPOCH)
                        .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
@@ -543,25 +543,25 @@ impl InvoiceRequest {
        }
 
        /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
-       /// derived signing keys from the originating [`Offer`] to sign the [`Invoice`]. Must use the
-       /// same [`ExpandedKey`] as the one used to create the offer.
+       /// derived signing keys from the originating [`Offer`] to sign the [`Bolt12Invoice`]. Must use
+       /// the same [`ExpandedKey`] as the one used to create the offer.
        ///
        /// See [`InvoiceRequest::respond_with_no_std`] for further details.
        ///
        /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
        ///
-       /// [`Invoice`]: crate::offers::invoice::Invoice
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        pub fn verify_and_respond_using_derived_keys_no_std<T: secp256k1::Signing>(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                created_at: core::time::Duration, expanded_key: &ExpandedKey, secp_ctx: &Secp256k1<T>
-       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, SemanticError> {
+       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError> {
                if self.features().requires_unknown_bits() {
-                       return Err(SemanticError::UnknownRequiredFeatures);
+                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
                }
 
                let keys = match self.verify(expanded_key, secp_ctx) {
-                       Err(()) => return Err(SemanticError::InvalidMetadata),
-                       Ok(None) => return Err(SemanticError::InvalidMetadata),
+                       Err(()) => return Err(Bolt12SemanticError::InvalidMetadata),
+                       Ok(None) => return Err(Bolt12SemanticError::InvalidMetadata),
                        Ok(Some(keys)) => keys,
                };
 
@@ -569,10 +569,10 @@ impl InvoiceRequest {
        }
 
        /// Verifies that the request was for an offer created using the given key. Returns the derived
-       /// keys need to sign an [`Invoice`] for the request if they could be extracted from the
+       /// keys need to sign an [`Bolt12Invoice`] for the request if they could be extracted from the
        /// metadata.
        ///
-       /// [`Invoice`]: crate::offers::invoice::Invoice
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        pub fn verify<T: secp256k1::Signing>(
                &self, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
        ) -> Result<Option<KeyPair>, ()> {
@@ -708,7 +708,7 @@ type PartialInvoiceRequestTlvStreamRef<'a> = (
 );
 
 impl TryFrom<Vec<u8>> for InvoiceRequest {
-       type Error = ParseError;
+       type Error = Bolt12ParseError;
 
        fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
                let invoice_request = ParsedMessage::<FullInvoiceRequestTlvStream>::try_from(bytes)?;
@@ -722,7 +722,7 @@ impl TryFrom<Vec<u8>> for InvoiceRequest {
                )?;
 
                let signature = match signature {
-                       None => return Err(ParseError::InvalidSemantics(SemanticError::MissingSignature)),
+                       None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
                        Some(signature) => signature,
                };
                merkle::verify_signature(&signature, SIGNATURE_TAG, &bytes, contents.payer_id)?;
@@ -732,7 +732,7 @@ impl TryFrom<Vec<u8>> for InvoiceRequest {
 }
 
 impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
-       type Error = SemanticError;
+       type Error = Bolt12SemanticError;
 
        fn try_from(tlv_stream: PartialInvoiceRequestTlvStream) -> Result<Self, Self::Error> {
                let (
@@ -742,17 +742,17 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
                ) = tlv_stream;
 
                let payer = match metadata {
-                       None => return Err(SemanticError::MissingPayerMetadata),
+                       None => return Err(Bolt12SemanticError::MissingPayerMetadata),
                        Some(metadata) => PayerContents(Metadata::Bytes(metadata)),
                };
                let offer = OfferContents::try_from(offer_tlv_stream)?;
 
                if !offer.supports_chain(chain.unwrap_or_else(|| offer.implied_chain())) {
-                       return Err(SemanticError::UnsupportedChain);
+                       return Err(Bolt12SemanticError::UnsupportedChain);
                }
 
                if offer.amount().is_none() && amount.is_none() {
-                       return Err(SemanticError::MissingAmount);
+                       return Err(Bolt12SemanticError::MissingAmount);
                }
 
                offer.check_quantity(quantity)?;
@@ -761,7 +761,7 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
                let features = features.unwrap_or_else(InvoiceRequestFeatures::empty);
 
                let payer_id = match payer_id {
-                       None => return Err(SemanticError::MissingPayerId),
+                       None => return Err(Bolt12SemanticError::MissingPayerId),
                        Some(payer_id) => payer_id,
                };
 
@@ -789,10 +789,10 @@ mod tests {
        use crate::ln::features::InvoiceRequestFeatures;
        use crate::ln::inbound_payment::ExpandedKey;
        use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
-       use crate::offers::invoice::{Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
+       use crate::offers::invoice::{Bolt12Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
        use crate::offers::merkle::{SignError, SignatureTlvStreamRef, self};
        use crate::offers::offer::{Amount, OfferBuilder, OfferTlvStreamRef, Quantity};
-       use crate::offers::parse::{ParseError, SemanticError};
+       use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
        use crate::offers::payer::PayerTlvStreamRef;
        use crate::offers::test_utils::*;
        use crate::util::ser::{BigSize, Writeable};
@@ -882,7 +882,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::AlreadyExpired),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::AlreadyExpired),
                }
        }
 
@@ -930,7 +930,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
 
                // Fails verification with altered metadata
@@ -954,7 +954,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
        }
 
@@ -1000,7 +1000,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
 
                // Fails verification with altered payer id
@@ -1024,7 +1024,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
        }
 
@@ -1091,7 +1091,7 @@ mod tests {
                        .chain(Network::Bitcoin)
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::UnsupportedChain),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
                }
 
                match OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1102,7 +1102,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::UnsupportedChain),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
                }
        }
 
@@ -1149,7 +1149,7 @@ mod tests {
                        .amount_msats(999)
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InsufficientAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InsufficientAmount),
                }
 
                match OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1161,7 +1161,7 @@ mod tests {
                        .amount_msats(1000)
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InsufficientAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InsufficientAmount),
                }
 
                match OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1171,7 +1171,7 @@ mod tests {
                        .amount_msats(MAX_VALUE_MSAT + 1)
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
                }
 
                match OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1184,7 +1184,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InsufficientAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InsufficientAmount),
                }
 
                match OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1193,7 +1193,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::MissingAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::MissingAmount),
                }
 
                match OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1205,7 +1205,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
                }
        }
 
@@ -1260,7 +1260,7 @@ mod tests {
                        .quantity(2)
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::UnexpectedQuantity),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::UnexpectedQuantity),
                }
 
                let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1285,7 +1285,7 @@ mod tests {
                        .quantity(11)
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidQuantity),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidQuantity),
                }
 
                let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1309,7 +1309,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::MissingQuantity),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::MissingQuantity),
                }
 
                match OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1320,7 +1320,7 @@ mod tests {
                        .build()
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::MissingQuantity),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::MissingQuantity),
                }
        }
 
@@ -1387,7 +1387,7 @@ mod tests {
                        .respond_with_no_std(payment_paths(), payment_hash(), now())
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::UnknownRequiredFeatures),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),
                }
        }
 
@@ -1438,7 +1438,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnsupportedChain)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnsupportedChain)),
                }
        }
 
@@ -1483,7 +1483,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingAmount)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingAmount)),
                }
 
                let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1499,7 +1499,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InsufficientAmount)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InsufficientAmount)),
                }
 
                let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1515,7 +1515,7 @@ mod tests {
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnsupportedCurrency));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnsupportedCurrency));
                        },
                }
 
@@ -1533,7 +1533,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidAmount)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidAmount)),
                }
        }
 
@@ -1573,7 +1573,7 @@ mod tests {
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnexpectedQuantity));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedQuantity));
                        },
                }
 
@@ -1609,7 +1609,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidQuantity)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidQuantity)),
                }
 
                let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1642,7 +1642,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingQuantity)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingQuantity)),
                }
 
                let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -1658,7 +1658,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingQuantity)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingQuantity)),
                }
        }
 
@@ -1678,7 +1678,7 @@ mod tests {
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPayerMetadata));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPayerMetadata));
                        },
                }
        }
@@ -1698,7 +1698,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPayerId)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPayerId)),
                }
        }
 
@@ -1718,7 +1718,7 @@ mod tests {
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSigningPubkey));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
                        },
                }
        }
@@ -1736,7 +1736,7 @@ mod tests {
 
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSignature)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
                }
        }
 
@@ -1757,7 +1757,7 @@ mod tests {
                match InvoiceRequest::try_from(buffer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSignature(secp256k1::Error::InvalidSignature));
+                               assert_eq!(e, Bolt12ParseError::InvalidSignature(secp256k1::Error::InvalidSignature));
                        },
                }
        }
@@ -1782,7 +1782,7 @@ mod tests {
 
                match InvoiceRequest::try_from(encoded_invoice_request) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
                }
        }
 }
index 9c8489778b08eaee1e444fe3f2584345c5224582..d801be9d26fb969c0b89af9b84a5e7408726efea 100644 (file)
@@ -24,7 +24,7 @@
 //!
 //! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
 //! use lightning::offers::offer::{Offer, OfferBuilder, Quantity};
-//! use lightning::offers::parse::ParseError;
+//! use lightning::offers::parse::Bolt12ParseError;
 //! use lightning::util::ser::{Readable, Writeable};
 //!
 //! # use lightning::blinded_path::BlindedPath;
@@ -35,7 +35,7 @@
 //! # fn create_another_blinded_path() -> BlindedPath { unimplemented!() }
 //! #
 //! # #[cfg(feature = "std")]
-//! # fn build() -> Result<(), ParseError> {
+//! # fn build() -> Result<(), Bolt12ParseError> {
 //! let secp_ctx = Secp256k1::new();
 //! let keys = KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
 //! let pubkey = PublicKey::from(keys);
@@ -82,7 +82,7 @@ use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
 use crate::ln::msgs::MAX_VALUE_MSAT;
 use crate::offers::invoice_request::{DerivedPayerId, ExplicitPayerId, InvoiceRequestBuilder};
 use crate::offers::merkle::TlvStream;
-use crate::offers::parse::{Bech32Encode, ParseError, ParsedMessage, SemanticError};
+use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
 use crate::offers::signer::{Metadata, MetadataMaterial, self};
 use crate::util::ser::{HighZeroBytesDroppedBigSize, WithoutLength, Writeable, Writer};
 use crate::util::string::PrintableString;
@@ -146,7 +146,7 @@ impl<'a> OfferBuilder<'a, ExplicitMetadata, secp256k1::SignOnly> {
        /// Sets the [`Offer::metadata`] to the given bytes.
        ///
        /// Successive calls to this method will override the previous setting.
-       pub fn metadata(mut self, metadata: Vec<u8>) -> Result<Self, SemanticError> {
+       pub fn metadata(mut self, metadata: Vec<u8>) -> Result<Self, Bolt12SemanticError> {
                self.offer.metadata = Some(Metadata::Bytes(metadata));
                Ok(self)
        }
@@ -252,14 +252,14 @@ impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> {
        }
 
        /// Builds an [`Offer`] from the builder's settings.
-       pub fn build(mut self) -> Result<Offer, SemanticError> {
+       pub fn build(mut self) -> Result<Offer, Bolt12SemanticError> {
                match self.offer.amount {
                        Some(Amount::Bitcoin { amount_msats }) => {
                                if amount_msats > MAX_VALUE_MSAT {
-                                       return Err(SemanticError::InvalidAmount);
+                                       return Err(Bolt12SemanticError::InvalidAmount);
                                }
                        },
-                       Some(Amount::Currency { .. }) => return Err(SemanticError::UnsupportedCurrency),
+                       Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
                        None => {},
                }
 
@@ -319,8 +319,8 @@ impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> {
 /// An `Offer` is a potentially long-lived proposal for payment of a good or service.
 ///
 /// An offer is a precursor to an [`InvoiceRequest`]. A merchant publishes an offer from which a
-/// customer may request an [`Invoice`] for a specific quantity and using an amount sufficient to
-/// cover that quantity (i.e., at least `quantity * amount`). See [`Offer::amount`].
+/// customer may request an [`Bolt12Invoice`] for a specific quantity and using an amount sufficient
+/// to cover that quantity (i.e., at least `quantity * amount`). See [`Offer::amount`].
 ///
 /// Offers may be denominated in currency other than bitcoin but are ultimately paid using the
 /// latter.
@@ -328,7 +328,7 @@ impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> {
 /// Through the use of [`BlindedPath`]s, offers provide recipient privacy.
 ///
 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 pub struct Offer {
@@ -338,10 +338,11 @@ pub struct Offer {
        pub(super) contents: OfferContents,
 }
 
-/// The contents of an [`Offer`], which may be shared with an [`InvoiceRequest`] or an [`Invoice`].
+/// The contents of an [`Offer`], which may be shared with an [`InvoiceRequest`] or a
+/// [`Bolt12Invoice`].
 ///
 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 pub(super) struct OfferContents {
@@ -451,8 +452,8 @@ impl Offer {
        /// - derives the [`InvoiceRequest::payer_id`] such that a different key can be used for each
        ///   request, and
        /// - sets the [`InvoiceRequest::metadata`] when [`InvoiceRequestBuilder::build`] is called such
-       ///   that it can be used by [`Invoice::verify`] to determine if the invoice was requested using
-       ///   a base [`ExpandedKey`] from which the payer id was derived.
+       ///   that it can be used by [`Bolt12Invoice::verify`] to determine if the invoice was requested
+       ///   using a base [`ExpandedKey`] from which the payer id was derived.
        ///
        /// Useful to protect the sender's privacy.
        ///
@@ -460,16 +461,16 @@ impl Offer {
        ///
        /// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
        /// [`InvoiceRequest::metadata`]: crate::offers::invoice_request::InvoiceRequest::metadata
-       /// [`Invoice::verify`]: crate::offers::invoice::Invoice::verify
+       /// [`Bolt12Invoice::verify`]: crate::offers::invoice::Bolt12Invoice::verify
        /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
        pub fn request_invoice_deriving_payer_id<'a, 'b, ES: Deref, T: secp256k1::Signing>(
                &'a self, expanded_key: &ExpandedKey, entropy_source: ES, secp_ctx: &'b Secp256k1<T>
-       ) -> Result<InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T>, SemanticError>
+       ) -> Result<InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T>, Bolt12SemanticError>
        where
                ES::Target: EntropySource,
        {
                if self.features().requires_unknown_bits() {
-                       return Err(SemanticError::UnknownRequiredFeatures);
+                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
                }
 
                Ok(InvoiceRequestBuilder::deriving_payer_id(self, expanded_key, entropy_source, secp_ctx))
@@ -485,19 +486,19 @@ impl Offer {
        /// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
        pub fn request_invoice_deriving_metadata<ES: Deref>(
                &self, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES
-       ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, SemanticError>
+       ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, Bolt12SemanticError>
        where
                ES::Target: EntropySource,
        {
                if self.features().requires_unknown_bits() {
-                       return Err(SemanticError::UnknownRequiredFeatures);
+                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
                }
 
                Ok(InvoiceRequestBuilder::deriving_metadata(self, payer_id, expanded_key, entropy_source))
        }
 
        /// Creates an [`InvoiceRequestBuilder`] for the offer with the given `metadata` and `payer_id`,
-       /// which will be reflected in the `Invoice` response.
+       /// which will be reflected in the `Bolt12Invoice` response.
        ///
        /// The `metadata` is useful for including information about the derivation of `payer_id` such
        /// that invoice response handling can be stateless. Also serves as payer-provided entropy while
@@ -513,9 +514,9 @@ impl Offer {
        /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
        pub fn request_invoice(
                &self, metadata: Vec<u8>, payer_id: PublicKey
-       ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, SemanticError> {
+       ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, Bolt12SemanticError> {
                if self.features().requires_unknown_bits() {
-                       return Err(SemanticError::UnknownRequiredFeatures);
+                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
                }
 
                Ok(InvoiceRequestBuilder::new(self, metadata, payer_id))
@@ -571,24 +572,24 @@ impl OfferContents {
 
        pub(super) fn check_amount_msats_for_quantity(
                &self, amount_msats: Option<u64>, quantity: Option<u64>
-       ) -> Result<(), SemanticError> {
+       ) -> Result<(), Bolt12SemanticError> {
                let offer_amount_msats = match self.amount {
                        None => 0,
                        Some(Amount::Bitcoin { amount_msats }) => amount_msats,
-                       Some(Amount::Currency { .. }) => return Err(SemanticError::UnsupportedCurrency),
+                       Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
                };
 
                if !self.expects_quantity() || quantity.is_some() {
                        let expected_amount_msats = offer_amount_msats.checked_mul(quantity.unwrap_or(1))
-                               .ok_or(SemanticError::InvalidAmount)?;
+                               .ok_or(Bolt12SemanticError::InvalidAmount)?;
                        let amount_msats = amount_msats.unwrap_or(expected_amount_msats);
 
                        if amount_msats < expected_amount_msats {
-                               return Err(SemanticError::InsufficientAmount);
+                               return Err(Bolt12SemanticError::InsufficientAmount);
                        }
 
                        if amount_msats > MAX_VALUE_MSAT {
-                               return Err(SemanticError::InvalidAmount);
+                               return Err(Bolt12SemanticError::InvalidAmount);
                        }
                }
 
@@ -599,13 +600,13 @@ impl OfferContents {
                self.supported_quantity
        }
 
-       pub(super) fn check_quantity(&self, quantity: Option<u64>) -> Result<(), SemanticError> {
+       pub(super) fn check_quantity(&self, quantity: Option<u64>) -> Result<(), Bolt12SemanticError> {
                let expects_quantity = self.expects_quantity();
                match quantity {
-                       None if expects_quantity => Err(SemanticError::MissingQuantity),
-                       Some(_) if !expects_quantity => Err(SemanticError::UnexpectedQuantity),
+                       None if expects_quantity => Err(Bolt12SemanticError::MissingQuantity),
+                       Some(_) if !expects_quantity => Err(Bolt12SemanticError::UnexpectedQuantity),
                        Some(quantity) if !self.is_valid_quantity(quantity) => {
-                               Err(SemanticError::InvalidQuantity)
+                               Err(Bolt12SemanticError::InvalidQuantity)
                        },
                        _ => Ok(()),
                }
@@ -767,7 +768,7 @@ impl Bech32Encode for Offer {
 }
 
 impl FromStr for Offer {
-       type Err = ParseError;
+       type Err = Bolt12ParseError;
 
        fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
                Self::from_bech32_str(s)
@@ -775,7 +776,7 @@ impl FromStr for Offer {
 }
 
 impl TryFrom<Vec<u8>> for Offer {
-       type Error = ParseError;
+       type Error = Bolt12ParseError;
 
        fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
                let offer = ParsedMessage::<OfferTlvStream>::try_from(bytes)?;
@@ -786,7 +787,7 @@ impl TryFrom<Vec<u8>> for Offer {
 }
 
 impl TryFrom<OfferTlvStream> for OfferContents {
-       type Error = SemanticError;
+       type Error = Bolt12SemanticError;
 
        fn try_from(tlv_stream: OfferTlvStream) -> Result<Self, Self::Error> {
                let OfferTlvStream {
@@ -799,15 +800,15 @@ impl TryFrom<OfferTlvStream> for OfferContents {
                let amount = match (currency, amount) {
                        (None, None) => None,
                        (None, Some(amount_msats)) if amount_msats > MAX_VALUE_MSAT => {
-                               return Err(SemanticError::InvalidAmount);
+                               return Err(Bolt12SemanticError::InvalidAmount);
                        },
                        (None, Some(amount_msats)) => Some(Amount::Bitcoin { amount_msats }),
-                       (Some(_), None) => return Err(SemanticError::MissingAmount),
+                       (Some(_), None) => return Err(Bolt12SemanticError::MissingAmount),
                        (Some(iso4217_code), Some(amount)) => Some(Amount::Currency { iso4217_code, amount }),
                };
 
                let description = match description {
-                       None => return Err(SemanticError::MissingDescription),
+                       None => return Err(Bolt12SemanticError::MissingDescription),
                        Some(description) => description,
                };
 
@@ -823,7 +824,7 @@ impl TryFrom<OfferTlvStream> for OfferContents {
                };
 
                let signing_pubkey = match node_id {
-                       None => return Err(SemanticError::MissingSigningPubkey),
+                       None => return Err(Bolt12SemanticError::MissingSigningPubkey),
                        Some(node_id) => node_id,
                };
 
@@ -855,7 +856,7 @@ mod tests {
        use crate::ln::features::OfferFeatures;
        use crate::ln::inbound_payment::ExpandedKey;
        use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
-       use crate::offers::parse::{ParseError, SemanticError};
+       use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
        use crate::offers::test_utils::*;
        use crate::util::ser::{BigSize, Writeable};
        use crate::util::string::PrintableString;
@@ -1089,7 +1090,7 @@ mod tests {
                assert_eq!(tlv_stream.currency, Some(b"USD"));
                match builder.build() {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::UnsupportedCurrency),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedCurrency),
                }
 
                let offer = OfferBuilder::new("foo".into(), pubkey(42))
@@ -1104,7 +1105,7 @@ mod tests {
                let invalid_amount = Amount::Bitcoin { amount_msats: MAX_VALUE_MSAT + 1 };
                match OfferBuilder::new("foo".into(), pubkey(42)).amount(invalid_amount).build() {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
                }
        }
 
@@ -1258,7 +1259,7 @@ mod tests {
                        .request_invoice(vec![1; 32], pubkey(43))
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::UnknownRequiredFeatures),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),
                }
        }
 
@@ -1304,7 +1305,7 @@ mod tests {
 
                match Offer::try_from(encoded_offer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingAmount)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingAmount)),
                }
 
                let mut tlv_stream = offer.as_tlv_stream();
@@ -1316,7 +1317,7 @@ mod tests {
 
                match Offer::try_from(encoded_offer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidAmount)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidAmount)),
                }
        }
 
@@ -1336,7 +1337,7 @@ mod tests {
                match Offer::try_from(encoded_offer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingDescription));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingDescription));
                        },
                }
        }
@@ -1426,7 +1427,7 @@ mod tests {
                match Offer::try_from(encoded_offer) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSigningPubkey));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
                        },
                }
        }
@@ -1443,14 +1444,14 @@ mod tests {
 
                match Offer::try_from(encoded_offer) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
                }
        }
 }
 
 #[cfg(test)]
 mod bech32_tests {
-       use super::{Offer, ParseError};
+       use super::{Bolt12ParseError, Offer};
        use bitcoin::bech32;
        use crate::ln::msgs::DecodeError;
 
@@ -1492,7 +1493,7 @@ mod bech32_tests {
                for encoded_offer in &offers {
                        match encoded_offer.parse::<Offer>() {
                                Ok(_) => panic!("Valid offer: {}", encoded_offer),
-                               Err(e) => assert_eq!(e, ParseError::InvalidContinuation),
+                               Err(e) => assert_eq!(e, Bolt12ParseError::InvalidContinuation),
                        }
                }
 
@@ -1503,7 +1504,7 @@ mod bech32_tests {
                let encoded_offer = "lni1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg";
                match encoded_offer.parse::<Offer>() {
                        Ok(_) => panic!("Valid offer: {}", encoded_offer),
-                       Err(e) => assert_eq!(e, ParseError::InvalidBech32Hrp),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::InvalidBech32Hrp),
                }
        }
 
@@ -1512,7 +1513,7 @@ mod bech32_tests {
                let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxo";
                match encoded_offer.parse::<Offer>() {
                        Ok(_) => panic!("Valid offer: {}", encoded_offer),
-                       Err(e) => assert_eq!(e, ParseError::Bech32(bech32::Error::InvalidChar('o'))),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::Bech32(bech32::Error::InvalidChar('o'))),
                }
        }
 
@@ -1521,7 +1522,7 @@ mod bech32_tests {
                let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxgqqqqq";
                match encoded_offer.parse::<Offer>() {
                        Ok(_) => panic!("Valid offer: {}", encoded_offer),
-                       Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
                }
        }
 }
index 42ed2e002d1f29b60169c86954f39cece3101647..e9477086ee981358aea419416e676e4b682c1fc1 100644 (file)
@@ -29,24 +29,24 @@ mod sealed {
        use bitcoin::bech32::{FromBase32, ToBase32};
        use core::convert::TryFrom;
        use core::fmt;
-       use super::ParseError;
+       use super::Bolt12ParseError;
 
        use crate::prelude::*;
 
        /// Indicates a message can be encoded using bech32.
-       pub trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=ParseError> {
+       pub trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=Bolt12ParseError> {
                /// Human readable part of the message's bech32 encoding.
                const BECH32_HRP: &'static str;
 
                /// Parses a bech32-encoded message into a TLV stream.
-               fn from_bech32_str(s: &str) -> Result<Self, ParseError> {
+               fn from_bech32_str(s: &str) -> Result<Self, Bolt12ParseError> {
                        // Offer encoding may be split by '+' followed by optional whitespace.
                        let encoded = match s.split('+').skip(1).next() {
                                Some(_) => {
                                        for chunk in s.split('+') {
                                                let chunk = chunk.trim_start();
                                                if chunk.is_empty() || chunk.contains(char::is_whitespace) {
-                                                       return Err(ParseError::InvalidContinuation);
+                                                       return Err(Bolt12ParseError::InvalidContinuation);
                                                }
                                        }
 
@@ -59,7 +59,7 @@ mod sealed {
                        let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?;
 
                        if hrp != Self::BECH32_HRP {
-                               return Err(ParseError::InvalidBech32Hrp);
+                               return Err(Bolt12ParseError::InvalidBech32Hrp);
                        }
 
                        let data = Vec::<u8>::from_base32(&data)?;
@@ -116,10 +116,8 @@ impl<T: SeekReadable> TryFrom<Vec<u8>> for ParsedMessage<T> {
 }
 
 /// Error when parsing a bech32 encoded message using [`str::parse`].
-///
-/// This is not exported to bindings users as its name conflicts with the BOLT 11 ParseError type.
-#[derive(Debug, PartialEq)]
-pub enum ParseError {
+#[derive(Clone, Debug, PartialEq)]
+pub enum Bolt12ParseError {
        /// The bech32 encoding does not conform to the BOLT 12 requirements for continuing messages
        /// across multiple parts (i.e., '+' followed by whitespace).
        InvalidContinuation,
@@ -131,16 +129,14 @@ pub enum ParseError {
        /// The bech32 decoded string could not be decoded as the expected message type.
        Decode(DecodeError),
        /// The parsed message has invalid semantics.
-       InvalidSemantics(SemanticError),
+       InvalidSemantics(Bolt12SemanticError),
        /// The parsed message has an invalid signature.
        InvalidSignature(secp256k1::Error),
 }
 
 /// Error when interpreting a TLV stream as a specific type.
-///
-/// This is not exported to bindings users as its name conflicts with the BOLT 11 SemanticError type.
-#[derive(Debug, PartialEq)]
-pub enum SemanticError {
+#[derive(Clone, Debug, PartialEq)]
+pub enum Bolt12SemanticError {
        /// The current [`std::time::SystemTime`] is past the offer or invoice's expiration.
        AlreadyExpired,
        /// The provided chain hash does not correspond to a supported chain.
@@ -195,25 +191,25 @@ pub enum SemanticError {
        MissingSignature,
 }
 
-impl From<bech32::Error> for ParseError {
+impl From<bech32::Error> for Bolt12ParseError {
        fn from(error: bech32::Error) -> Self {
                Self::Bech32(error)
        }
 }
 
-impl From<DecodeError> for ParseError {
+impl From<DecodeError> for Bolt12ParseError {
        fn from(error: DecodeError) -> Self {
                Self::Decode(error)
        }
 }
 
-impl From<SemanticError> for ParseError {
-       fn from(error: SemanticError) -> Self {
+impl From<Bolt12SemanticError> for Bolt12ParseError {
+       fn from(error: Bolt12SemanticError) -> Self {
                Self::InvalidSemantics(error)
        }
 }
 
-impl From<secp256k1::Error> for ParseError {
+impl From<secp256k1::Error> for Bolt12ParseError {
        fn from(error: secp256k1::Error) -> Self {
                Self::InvalidSignature(error)
        }
index 8fbc47d122cc88983694d0c5235b58e33e970169..2c8dffeb1516abfa7961d144581d412657861c2a 100644 (file)
 //! Data structures and encoding for refunds.
 //!
 //! A [`Refund`] is an "offer for money" and is typically constructed by a merchant and presented
-//! directly to the customer. The recipient responds with an [`Invoice`] to be paid.
+//! directly to the customer. The recipient responds with a [`Bolt12Invoice`] to be paid.
 //!
 //! This is an [`InvoiceRequest`] produced *not* in response to an [`Offer`].
 //!
-//! [`Invoice`]: crate::offers::invoice::Invoice
+//! [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 //! [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
 //! [`Offer`]: crate::offers::offer::Offer
 //!
@@ -28,7 +28,7 @@
 //!
 //! use bitcoin::network::constants::Network;
 //! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
-//! use lightning::offers::parse::ParseError;
+//! use lightning::offers::parse::Bolt12ParseError;
 //! use lightning::offers::refund::{Refund, RefundBuilder};
 //! use lightning::util::ser::{Readable, Writeable};
 //!
@@ -40,7 +40,7 @@
 //! # fn create_another_blinded_path() -> BlindedPath { unimplemented!() }
 //! #
 //! # #[cfg(feature = "std")]
-//! # fn build() -> Result<(), ParseError> {
+//! # fn build() -> Result<(), Bolt12ParseError> {
 //! let secp_ctx = Secp256k1::new();
 //! let keys = KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
 //! let pubkey = PublicKey::from(keys);
@@ -88,7 +88,7 @@ use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
 use crate::offers::invoice::{BlindedPayInfo, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder};
 use crate::offers::invoice_request::{InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
 use crate::offers::offer::{OfferTlvStream, OfferTlvStreamRef};
-use crate::offers::parse::{Bech32Encode, ParseError, ParsedMessage, SemanticError};
+use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
 use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
 use crate::offers::signer::{Metadata, MetadataMaterial, self};
 use crate::util::ser::{SeekReadable, WithoutLength, Writeable, Writer};
@@ -121,9 +121,9 @@ impl<'a> RefundBuilder<'a, secp256k1::SignOnly> {
        /// [`Refund::amount_msats`].
        pub fn new(
                description: String, metadata: Vec<u8>, payer_id: PublicKey, amount_msats: u64
-       ) -> Result<Self, SemanticError> {
+       ) -> Result<Self, Bolt12SemanticError> {
                if amount_msats > MAX_VALUE_MSAT {
-                       return Err(SemanticError::InvalidAmount);
+                       return Err(Bolt12SemanticError::InvalidAmount);
                }
 
                let metadata = Metadata::Bytes(metadata);
@@ -152,9 +152,9 @@ impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
        pub fn deriving_payer_id<ES: Deref>(
                description: String, node_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES,
                secp_ctx: &'a Secp256k1<T>, amount_msats: u64
-       ) -> Result<Self, SemanticError> where ES::Target: EntropySource {
+       ) -> Result<Self, Bolt12SemanticError> where ES::Target: EntropySource {
                if amount_msats > MAX_VALUE_MSAT {
-                       return Err(SemanticError::InvalidAmount);
+                       return Err(Bolt12SemanticError::InvalidAmount);
                }
 
                let nonce = Nonce::from_entropy_source(entropy_source);
@@ -207,12 +207,12 @@ impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
        }
 
        /// Sets [`Refund::quantity`] of items. This is purely for informational purposes. It is useful
-       /// when the refund pertains to an [`Invoice`] that paid for more than one item from an
+       /// when the refund pertains to a [`Bolt12Invoice`] that paid for more than one item from an
        /// [`Offer`] as specified by [`InvoiceRequest::quantity`].
        ///
        /// Successive calls to this method will override the previous setting.
        ///
-       /// [`Invoice`]: crate::offers::invoice::Invoice
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        /// [`InvoiceRequest::quantity`]: crate::offers::invoice_request::InvoiceRequest::quantity
        /// [`Offer`]: crate::offers::offer::Offer
        pub fn quantity(mut self, quantity: u64) -> Self {
@@ -229,12 +229,12 @@ impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
        }
 
        /// Builds a [`Refund`] after checking for valid semantics.
-       pub fn build(mut self) -> Result<Refund, SemanticError> {
+       pub fn build(mut self) -> Result<Refund, Bolt12SemanticError> {
                if self.refund.chain() == self.refund.implied_chain() {
                        self.refund.chain = None;
                }
 
-               // Create the metadata for stateless verification of aInvoice.
+               // Create the metadata for stateless verification of a Bolt12Invoice.
                if self.refund.payer.0.has_derivation_material() {
                        let mut metadata = core::mem::take(&mut self.refund.payer.0);
 
@@ -272,13 +272,13 @@ impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
        }
 }
 
-/// A `Refund` is a request to send an [`Invoice`] without a preceding [`Offer`].
+/// A `Refund` is a request to send an [`Bolt12Invoice`] without a preceding [`Offer`].
 ///
 /// Typically, after an invoice is paid, the recipient may publish a refund allowing the sender to
 /// recoup their funds. A refund may be used more generally as an "offer for money", such as with a
 /// bitcoin ATM.
 ///
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 /// [`Offer`]: crate::offers::offer::Offer
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
@@ -287,9 +287,9 @@ pub struct Refund {
        pub(super) contents: RefundContents,
 }
 
-/// The contents of a [`Refund`], which may be shared with an [`Invoice`].
+/// The contents of a [`Refund`], which may be shared with an [`Bolt12Invoice`].
 ///
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 pub(super) struct RefundContents {
@@ -394,9 +394,9 @@ impl Refund {
        /// [`Duration`]: core::time::Duration
        #[cfg(feature = "std")]
        pub fn respond_with(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                signing_pubkey: PublicKey,
-       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, SemanticError> {
+       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> {
                let created_at = std::time::SystemTime::now()
                        .duration_since(std::time::SystemTime::UNIX_EPOCH)
                        .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
@@ -407,8 +407,8 @@ impl Refund {
        /// Creates an [`InvoiceBuilder`] for the refund with the given required fields.
        ///
        /// Unless [`InvoiceBuilder::relative_expiry`] is set, the invoice will expire two hours after
-       /// `created_at`, which is used to set [`Invoice::created_at`]. Useful for `no-std` builds where
-       /// [`std::time::SystemTime`] is not available.
+       /// `created_at`, which is used to set [`Bolt12Invoice::created_at`]. Useful for `no-std` builds
+       /// where [`std::time::SystemTime`] is not available.
        ///
        /// The caller is expected to remember the preimage of `payment_hash` in order to
        /// claim a payment for the invoice.
@@ -425,31 +425,31 @@ impl Refund {
        ///
        /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
        ///
-       /// [`Invoice::created_at`]: crate::offers::invoice::Invoice::created_at
+       /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
        pub fn respond_with_no_std(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                signing_pubkey: PublicKey, created_at: Duration
-       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, SemanticError> {
+       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> {
                if self.features().requires_unknown_bits() {
-                       return Err(SemanticError::UnknownRequiredFeatures);
+                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
                }
 
                InvoiceBuilder::for_refund(self, payment_paths, created_at, payment_hash, signing_pubkey)
        }
 
        /// Creates an [`InvoiceBuilder`] for the refund using the given required fields and that uses
-       /// derived signing keys to sign the [`Invoice`].
+       /// derived signing keys to sign the [`Bolt12Invoice`].
        ///
        /// See [`Refund::respond_with`] for further details.
        ///
        /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
        ///
-       /// [`Invoice`]: crate::offers::invoice::Invoice
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        #[cfg(feature = "std")]
        pub fn respond_using_derived_keys<ES: Deref>(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                expanded_key: &ExpandedKey, entropy_source: ES
-       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, SemanticError>
+       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError>
        where
                ES::Target: EntropySource,
        {
@@ -463,22 +463,22 @@ impl Refund {
        }
 
        /// Creates an [`InvoiceBuilder`] for the refund using the given required fields and that uses
-       /// derived signing keys to sign the [`Invoice`].
+       /// derived signing keys to sign the [`Bolt12Invoice`].
        ///
        /// See [`Refund::respond_with_no_std`] for further details.
        ///
        /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
        ///
-       /// [`Invoice`]: crate::offers::invoice::Invoice
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        pub fn respond_using_derived_keys_no_std<ES: Deref>(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                created_at: core::time::Duration, expanded_key: &ExpandedKey, entropy_source: ES
-       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, SemanticError>
+       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError>
        where
                ES::Target: EntropySource,
        {
                if self.features().requires_unknown_bits() {
-                       return Err(SemanticError::UnknownRequiredFeatures);
+                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
                }
 
                let nonce = Nonce::from_entropy_source(entropy_source);
@@ -606,7 +606,7 @@ impl Bech32Encode for Refund {
 }
 
 impl FromStr for Refund {
-       type Err = ParseError;
+       type Err = Bolt12ParseError;
 
        fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
                Refund::from_bech32_str(s)
@@ -614,7 +614,7 @@ impl FromStr for Refund {
 }
 
 impl TryFrom<Vec<u8>> for Refund {
-       type Error = ParseError;
+       type Error = Bolt12ParseError;
 
        fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
                let refund = ParsedMessage::<RefundTlvStream>::try_from(bytes)?;
@@ -626,7 +626,7 @@ impl TryFrom<Vec<u8>> for Refund {
 }
 
 impl TryFrom<RefundTlvStream> for RefundContents {
-       type Error = SemanticError;
+       type Error = Bolt12SemanticError;
 
        fn try_from(tlv_stream: RefundTlvStream) -> Result<Self, Self::Error> {
                let (
@@ -639,45 +639,45 @@ impl TryFrom<RefundTlvStream> for RefundContents {
                ) = tlv_stream;
 
                let payer = match payer_metadata {
-                       None => return Err(SemanticError::MissingPayerMetadata),
+                       None => return Err(Bolt12SemanticError::MissingPayerMetadata),
                        Some(metadata) => PayerContents(Metadata::Bytes(metadata)),
                };
 
                if metadata.is_some() {
-                       return Err(SemanticError::UnexpectedMetadata);
+                       return Err(Bolt12SemanticError::UnexpectedMetadata);
                }
 
                if chains.is_some() {
-                       return Err(SemanticError::UnexpectedChain);
+                       return Err(Bolt12SemanticError::UnexpectedChain);
                }
 
                if currency.is_some() || offer_amount.is_some() {
-                       return Err(SemanticError::UnexpectedAmount);
+                       return Err(Bolt12SemanticError::UnexpectedAmount);
                }
 
                let description = match description {
-                       None => return Err(SemanticError::MissingDescription),
+                       None => return Err(Bolt12SemanticError::MissingDescription),
                        Some(description) => description,
                };
 
                if offer_features.is_some() {
-                       return Err(SemanticError::UnexpectedFeatures);
+                       return Err(Bolt12SemanticError::UnexpectedFeatures);
                }
 
                let absolute_expiry = absolute_expiry.map(Duration::from_secs);
 
                if quantity_max.is_some() {
-                       return Err(SemanticError::UnexpectedQuantity);
+                       return Err(Bolt12SemanticError::UnexpectedQuantity);
                }
 
                if node_id.is_some() {
-                       return Err(SemanticError::UnexpectedSigningPubkey);
+                       return Err(Bolt12SemanticError::UnexpectedSigningPubkey);
                }
 
                let amount_msats = match amount {
-                       None => return Err(SemanticError::MissingAmount),
+                       None => return Err(Bolt12SemanticError::MissingAmount),
                        Some(amount_msats) if amount_msats > MAX_VALUE_MSAT => {
-                               return Err(SemanticError::InvalidAmount);
+                               return Err(Bolt12SemanticError::InvalidAmount);
                        },
                        Some(amount_msats) => amount_msats,
                };
@@ -685,7 +685,7 @@ impl TryFrom<RefundTlvStream> for RefundContents {
                let features = features.unwrap_or_else(InvoiceRequestFeatures::empty);
 
                let payer_id = match payer_id {
-                       None => return Err(SemanticError::MissingPayerId),
+                       None => return Err(Bolt12SemanticError::MissingPayerId),
                        Some(payer_id) => payer_id,
                };
 
@@ -718,7 +718,7 @@ mod tests {
        use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
        use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
        use crate::offers::offer::OfferTlvStreamRef;
-       use crate::offers::parse::{ParseError, SemanticError};
+       use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
        use crate::offers::payer::PayerTlvStreamRef;
        use crate::offers::test_utils::*;
        use crate::util::ser::{BigSize, Writeable};
@@ -795,7 +795,7 @@ mod tests {
        fn fails_building_refund_with_invalid_amount() {
                match RefundBuilder::new("foo".into(), vec![1; 32], payer_pubkey(), MAX_VALUE_MSAT + 1) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::InvalidAmount),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
                }
        }
 
@@ -1064,7 +1064,7 @@ mod tests {
                        .respond_with_no_std(payment_paths(), payment_hash(), recipient_pubkey(), now())
                {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SemanticError::UnknownRequiredFeatures),
+                       Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),
                }
        }
 
@@ -1082,7 +1082,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPayerMetadata));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPayerMetadata));
                        },
                }
        }
@@ -1101,7 +1101,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingDescription));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingDescription));
                        },
                }
        }
@@ -1120,7 +1120,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingAmount));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingAmount));
                        },
                }
 
@@ -1130,7 +1130,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidAmount));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidAmount));
                        },
                }
        }
@@ -1149,7 +1149,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPayerId));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPayerId));
                        },
                }
        }
@@ -1218,7 +1218,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnexpectedMetadata));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedMetadata));
                        },
                }
 
@@ -1229,7 +1229,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnexpectedChain));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedChain));
                        },
                }
 
@@ -1240,7 +1240,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnexpectedAmount));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedAmount));
                        },
                }
 
@@ -1251,7 +1251,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnexpectedFeatures));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedFeatures));
                        },
                }
 
@@ -1261,7 +1261,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnexpectedQuantity));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedQuantity));
                        },
                }
 
@@ -1272,7 +1272,7 @@ mod tests {
                match Refund::try_from(tlv_stream.to_bytes()) {
                        Ok(_) => panic!("expected error"),
                        Err(e) => {
-                               assert_eq!(e, ParseError::InvalidSemantics(SemanticError::UnexpectedSigningPubkey));
+                               assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedSigningPubkey));
                        },
                }
        }
@@ -1292,7 +1292,7 @@ mod tests {
 
                match Refund::try_from(encoded_refund) {
                        Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)),
+                       Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
                }
        }
 }
index 26c0d051223a6c26787055257a187fdfd95f1da7..230c6aa1628d96a180276d228d5742369062886f 100644 (file)
@@ -58,7 +58,7 @@ pub(super) fn privkey(byte: u8) -> SecretKey {
        SecretKey::from_slice(&[byte; 32]).unwrap()
 }
 
-pub(super) fn payment_paths() -> Vec<(BlindedPath, BlindedPayInfo)> {
+pub(super) fn payment_paths() -> Vec<(BlindedPayInfo, BlindedPath)> {
        let paths = vec![
                BlindedPath {
                        introduction_node_id: pubkey(40),
@@ -97,7 +97,7 @@ pub(super) fn payment_paths() -> Vec<(BlindedPath, BlindedPayInfo)> {
                },
        ];
 
-       paths.into_iter().zip(payinfo.into_iter()).collect()
+       payinfo.into_iter().zip(paths.into_iter()).collect()
 }
 
 pub(super) fn payment_hash() -> PaymentHash {
index 2c3cf4307349ff27bcc988806ec337952c339c9d..a3613605cdebbd1ff71014d827b70782e043a160 100644 (file)
@@ -152,6 +152,17 @@ pub trait MessageRouter {
        ) -> Result<OnionMessagePath, ()>;
 }
 
+/// A [`MessageRouter`] that always fails.
+pub struct DefaultMessageRouter;
+
+impl MessageRouter for DefaultMessageRouter {
+       fn find_path(
+               &self, _sender: PublicKey, _peers: Vec<PublicKey>, _destination: Destination
+       ) -> Result<OnionMessagePath, ()> {
+               Err(())
+       }
+}
+
 /// A path for sending an [`msgs::OnionMessage`].
 #[derive(Clone)]
 pub struct OnionMessagePath {
@@ -598,11 +609,11 @@ where
 ///
 /// [`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager
 /// [`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager
-pub type SimpleArcOnionMessenger<L, R> = OnionMessenger<
+pub type SimpleArcOnionMessenger<L> = OnionMessenger<
        Arc<KeysManager>,
        Arc<KeysManager>,
        Arc<L>,
-       Arc<R>,
+       Arc<DefaultMessageRouter>,
        IgnoringMessageHandler,
        IgnoringMessageHandler
 >;
@@ -614,11 +625,11 @@ pub type SimpleArcOnionMessenger<L, R> = OnionMessenger<
 ///
 /// [`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager
 /// [`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager
-pub type SimpleRefOnionMessenger<'a, 'b, 'c, L, R> = OnionMessenger<
+pub type SimpleRefOnionMessenger<'a, 'b, 'c, L> = OnionMessenger<
        &'a KeysManager,
        &'a KeysManager,
        &'b L,
-       &'c R,
+       &'c DefaultMessageRouter,
        IgnoringMessageHandler,
        IgnoringMessageHandler
 >;
index 556ae89820bd33116ec672535a35ea3a79cd1fc4..806f832ff73f557de046d08ebe67e5d87e0a028f 100644 (file)
@@ -27,6 +27,6 @@ mod packet;
 mod functional_tests;
 
 // Re-export structs so they can be imported with just the `onion_message::` module prefix.
-pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
+pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
 pub use self::offers::{OffersMessage, OffersMessageHandler};
 pub(crate) use self::packet::{ControlTlvs, Packet};
index f82afdd618a5bfa78ac02a7e0bfd6476cac4bbdd..de373bda1bce81b104f1cd616be1ea4fb3e0b756 100644 (file)
@@ -14,8 +14,8 @@ use crate::io::{self, Read};
 use crate::ln::msgs::DecodeError;
 use crate::offers::invoice_error::InvoiceError;
 use crate::offers::invoice_request::InvoiceRequest;
-use crate::offers::invoice::Invoice;
-use crate::offers::parse::ParseError;
+use crate::offers::invoice::Bolt12Invoice;
+use crate::offers::parse::Bolt12ParseError;
 use crate::util::logger::Logger;
 use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
 
@@ -30,25 +30,25 @@ const INVOICE_ERROR_TLV_TYPE: u64 = 68;
 ///
 /// [`OnionMessage`]: crate::ln::msgs::OnionMessage
 pub trait OffersMessageHandler {
-       /// Handles the given message by either responding with an [`Invoice`], sending a payment, or
-       /// replying with an error.
+       /// Handles the given message by either responding with an [`Bolt12Invoice`], sending a payment,
+       /// or replying with an error.
        fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage>;
 }
 
 /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`].
 ///
 /// [`OnionMessage`]: crate::ln::msgs::OnionMessage
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub enum OffersMessage {
-       /// A request for an [`Invoice`] for a particular [`Offer`].
+       /// A request for a [`Bolt12Invoice`] for a particular [`Offer`].
        ///
        /// [`Offer`]: crate::offers::offer::Offer
        InvoiceRequest(InvoiceRequest),
 
-       /// An [`Invoice`] sent in response to an [`InvoiceRequest`] or a [`Refund`].
+       /// A [`Bolt12Invoice`] sent in response to an [`InvoiceRequest`] or a [`Refund`].
        ///
        /// [`Refund`]: crate::offers::refund::Refund
-       Invoice(Invoice),
+       Invoice(Bolt12Invoice),
 
        /// An error from handling an [`OffersMessage`].
        InvoiceError(InvoiceError),
@@ -72,11 +72,11 @@ impl OffersMessage {
                }
        }
 
-       fn parse(tlv_type: u64, bytes: Vec<u8>) -> Result<Self, ParseError> {
+       fn parse(tlv_type: u64, bytes: Vec<u8>) -> Result<Self, Bolt12ParseError> {
                match tlv_type {
                        INVOICE_REQUEST_TLV_TYPE => Ok(Self::InvoiceRequest(InvoiceRequest::try_from(bytes)?)),
-                       INVOICE_TLV_TYPE => Ok(Self::Invoice(Invoice::try_from(bytes)?)),
-                       _ => Err(ParseError::Decode(DecodeError::InvalidValue)),
+                       INVOICE_TLV_TYPE => Ok(Self::Invoice(Bolt12Invoice::try_from(bytes)?)),
+                       _ => Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
                }
        }
 }
@@ -103,12 +103,12 @@ impl<L: Logger + ?Sized> ReadableArgs<(u64, &L)> for OffersMessage {
 
                match Self::parse(tlv_type, bytes) {
                        Ok(message) => Ok(message),
-                       Err(ParseError::Decode(e)) => Err(e),
-                       Err(ParseError::InvalidSemantics(e)) => {
+                       Err(Bolt12ParseError::Decode(e)) => Err(e),
+                       Err(Bolt12ParseError::InvalidSemantics(e)) => {
                                log_trace!(logger, "Invalid semantics for TLV type {}: {:?}", tlv_type, e);
                                Err(DecodeError::InvalidValue)
                        },
-                       Err(ParseError::InvalidSignature(e)) => {
+                       Err(Bolt12ParseError::InvalidSignature(e)) => {
                                log_trace!(logger, "Invalid signature for TLV type {}: {:?}", tlv_type, e);
                                Err(DecodeError::InvalidValue)
                        },
index 1c3595c3712526191e0e5f1707dfa51d82ca7505..8a5628f164ca358dd8df1d7aec5e58730247c67e 100644 (file)
@@ -169,7 +169,7 @@ impl<T: CustomOnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
                match &self.0 {
                        Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) => {
                                _encode_varint_length_prefixed_tlv!(w, {
-                                       (4, *encrypted_bytes, vec_type)
+                                       (4, *encrypted_bytes, required_vec)
                                })
                        },
                        Payload::Receive {
@@ -177,7 +177,7 @@ impl<T: CustomOnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
                        } => {
                                _encode_varint_length_prefixed_tlv!(w, {
                                        (2, reply_path, option),
-                                       (4, *encrypted_bytes, vec_type),
+                                       (4, *encrypted_bytes, required_vec),
                                        (message.tlv_type(), message, required)
                                })
                        },
index 40969b180af9d6904d79eb29d8cdf05b3c624bc9..b9b70e0a03165e49f71f7f8c9bf185fd0388d7a2 100644 (file)
@@ -10,7 +10,7 @@
 //! The [`NetworkGraph`] stores the network gossip and [`P2PGossipSync`] fetches it from peers
 
 use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
-use bitcoin::secp256k1::PublicKey;
+use bitcoin::secp256k1::{PublicKey, Verification};
 use bitcoin::secp256k1::Secp256k1;
 use bitcoin::secp256k1;
 
@@ -409,6 +409,29 @@ macro_rules! get_pubkey_from_node_id {
        }
 }
 
+/// Verifies the signature of a [`NodeAnnouncement`].
+///
+/// Returns an error if it is invalid.
+pub fn verify_node_announcement<C: Verification>(msg: &NodeAnnouncement, secp_ctx: &Secp256k1<C>) -> Result<(), LightningError> {
+       let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
+       secp_verify_sig!(secp_ctx, &msg_hash, &msg.signature, &get_pubkey_from_node_id!(msg.contents.node_id, "node_announcement"), "node_announcement");
+
+       Ok(())
+}
+
+/// Verifies all signatures included in a [`ChannelAnnouncement`].
+///
+/// Returns an error if one of the signatures is invalid.
+pub fn verify_channel_announcement<C: Verification>(msg: &ChannelAnnouncement, secp_ctx: &Secp256k1<C>) -> Result<(), LightningError> {
+       let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
+       secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_1, &get_pubkey_from_node_id!(msg.contents.node_id_1, "channel_announcement"), "channel_announcement");
+       secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_2, &get_pubkey_from_node_id!(msg.contents.node_id_2, "channel_announcement"), "channel_announcement");
+       secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_1, "channel_announcement"), "channel_announcement");
+       secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_2, "channel_announcement"), "channel_announcement");
+
+       Ok(())
+}
+
 impl<G: Deref<Target=NetworkGraph<L>>, U: Deref, L: Deref> RoutingMessageHandler for P2PGossipSync<G, U, L>
 where U::Target: UtxoLookup, L::Target: Logger
 {
@@ -1120,26 +1143,26 @@ impl Writeable for NodeAnnouncementInfo {
                        (4, self.rgb, required),
                        (6, self.alias, required),
                        (8, self.announcement_message, option),
-                       (10, empty_addresses, vec_type), // Versions prior to 0.0.115 require this field
+                       (10, empty_addresses, required_vec), // Versions prior to 0.0.115 require this field
                });
                Ok(())
        }
 }
 
 impl Readable for NodeAnnouncementInfo {
-    fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
                _init_and_read_tlv_fields!(reader, {
                        (0, features, required),
                        (2, last_update, required),
                        (4, rgb, required),
                        (6, alias, required),
                        (8, announcement_message, option),
-                       (10, _addresses, vec_type), // deprecated, not used anymore
+                       (10, _addresses, optional_vec), // deprecated, not used anymore
                });
                let _: Option<Vec<NetAddress>> = _addresses;
                Ok(Self { features: features.0.unwrap(), last_update: last_update.0.unwrap(), rgb: rgb.0.unwrap(),
                        alias: alias.0.unwrap(), announcement_message })
-    }
+       }
 }
 
 /// A user-defined name for a node, which may be used when displaying the node in a graph.
@@ -1205,7 +1228,7 @@ impl Writeable for NodeInfo {
                write_tlv_fields!(writer, {
                        // Note that older versions of LDK wrote the lowest inbound fees here at type 0
                        (2, self.announcement_info, option),
-                       (4, self.channels, vec_type),
+                       (4, self.channels, required_vec),
                });
                Ok(())
        }
@@ -1236,19 +1259,17 @@ impl Readable for NodeInfo {
                // with zero inbound fees, causing that heuristic to provide little gain. Worse, because it
                // requires additional complexity and lookups during routing, it ends up being a
                // performance loss. Thus, we simply ignore the old field here and no longer track it.
-               let mut _lowest_inbound_channel_fees: Option<RoutingFees> = None;
-               let mut announcement_info_wrap: Option<NodeAnnouncementInfoDeserWrapper> = None;
-               _init_tlv_field_var!(channels, vec_type);
-
-               read_tlv_fields!(reader, {
+               _init_and_read_tlv_fields!(reader, {
                        (0, _lowest_inbound_channel_fees, option),
                        (2, announcement_info_wrap, upgradable_option),
-                       (4, channels, vec_type),
+                       (4, channels, required_vec),
                });
+               let _: Option<RoutingFees> = _lowest_inbound_channel_fees;
+               let announcement_info_wrap: Option<NodeAnnouncementInfoDeserWrapper> = announcement_info_wrap;
 
                Ok(NodeInfo {
                        announcement_info: announcement_info_wrap.map(|w| w.0),
-                       channels: _init_tlv_based_struct_field!(channels, vec_type),
+                       channels,
                })
        }
 }
@@ -1403,8 +1424,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
        /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept
        /// routing messages from a source using a protocol other than the lightning P2P protocol.
        pub fn update_node_from_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<(), LightningError> {
-               let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
-               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &get_pubkey_from_node_id!(msg.contents.node_id, "node_announcement"), "node_announcement");
+               verify_node_announcement(msg, &self.secp_ctx)?;
                self.update_node_from_announcement_intern(&msg.contents, Some(&msg))
        }
 
@@ -1467,11 +1487,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
        where
                U::Target: UtxoLookup,
        {
-               let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
-               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_1, &get_pubkey_from_node_id!(msg.contents.node_id_1, "channel_announcement"), "channel_announcement");
-               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_2, &get_pubkey_from_node_id!(msg.contents.node_id_2, "channel_announcement"), "channel_announcement");
-               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_1, "channel_announcement"), "channel_announcement");
-               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_2, "channel_announcement"), "channel_announcement");
+               verify_channel_announcement(msg, &self.secp_ctx)?;
                self.update_channel_from_unsigned_announcement_intern(&msg.contents, Some(msg), utxo_lookup)
        }
 
index f7ed173b901a90a9dbe0d81166dfb188b77ccec9..f0822ed5b38a6d69c1f281270ec3502dc2860d4e 100644 (file)
@@ -16,9 +16,9 @@ use bitcoin::hashes::sha256::Hash as Sha256;
 use crate::blinded_path::{BlindedHop, BlindedPath};
 use crate::ln::PaymentHash;
 use crate::ln::channelmanager::{ChannelDetails, PaymentId};
-use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, InvoiceFeatures, NodeFeatures};
+use crate::ln::features::{Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
 use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
-use crate::offers::invoice::BlindedPayInfo;
+use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice};
 use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees};
 use crate::routing::scoring::{ChannelUsage, LockableScore, Score};
 use crate::util::ser::{Writeable, Readable, ReadableArgs, Writer};
@@ -27,15 +27,15 @@ use crate::util::chacha20::ChaCha20;
 
 use crate::io;
 use crate::prelude::*;
-use crate::sync::{Mutex, MutexGuard};
+use crate::sync::{Mutex};
 use alloc::collections::BinaryHeap;
 use core::{cmp, fmt};
-use core::ops::Deref;
+use core::ops::{Deref, DerefMut};
 
 /// A [`Router`] implemented using [`find_route`].
 pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> where
        L::Target: Logger,
-       S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
+       S::Target: for <'a> LockableScore<'a, Score = Sc>,
 {
        network_graph: G,
        logger: L,
@@ -46,7 +46,7 @@ pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref,
 
 impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> DefaultRouter<G, L, S, SP, Sc> where
        L::Target: Logger,
-       S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
+       S::Target: for <'a> LockableScore<'a, Score = Sc>,
 {
        /// Creates a new router.
        pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S, score_params: SP) -> Self {
@@ -55,16 +55,16 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Scor
        }
 }
 
-impl< G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref,  SP: Sized, Sc: Score<ScoreParams = SP>> Router for DefaultRouter<G, L, S, SP, Sc> where
+impl< G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> Router for DefaultRouter<G, L, S, SP, Sc> where
        L::Target: Logger,
-       S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
+       S::Target: for <'a> LockableScore<'a, Score = Sc>,
 {
        fn find_route(
                &self,
                payer: &PublicKey,
                params: &RouteParameters,
                first_hops: Option<&[&ChannelDetails]>,
-               inflight_htlcs: &InFlightHtlcs
+               inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, LightningError> {
                let random_seed_bytes = {
                        let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
@@ -73,7 +73,7 @@ impl< G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref,  SP: Sized, Sc: Sc
                };
                find_route(
                        payer, params, &self.network_graph, first_hops, &*self.logger,
-                       &ScorerAccountingForInFlightHtlcs::new(self.scorer.lock()inflight_htlcs),
+                       &ScorerAccountingForInFlightHtlcs::new(self.scorer.lock().deref_mut(), &inflight_htlcs),
                        &self.score_params,
                        &random_seed_bytes
                )
@@ -85,13 +85,13 @@ pub trait Router {
        /// Finds a [`Route`] between `payer` and `payee` for a payment with the given values.
        fn find_route(
                &self, payer: &PublicKey, route_params: &RouteParameters,
-               first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: &InFlightHtlcs
+               first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, LightningError>;
        /// Finds a [`Route`] between `payer` and `payee` for a payment with the given values. Includes
        /// `PaymentHash` and `PaymentId` to be able to correlate the request with a specific payment.
        fn find_route_with_id(
                &self, payer: &PublicKey, route_params: &RouteParameters,
-               first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: &InFlightHtlcs,
+               first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs,
                _payment_hash: PaymentHash, _payment_id: PaymentId
        ) -> Result<Route, LightningError> {
                self.find_route(payer, route_params, first_hops, inflight_htlcs)
@@ -104,15 +104,15 @@ pub trait Router {
 /// [`find_route`].
 ///
 /// [`Score`]: crate::routing::scoring::Score
-pub struct ScorerAccountingForInFlightHtlcs<'a, S: Score> {
-       scorer: S,
+pub struct ScorerAccountingForInFlightHtlcs<'a, S: Score<ScoreParams = SP>, SP: Sized> {
+       scorer: &'a mut S,
        // Maps a channel's short channel id and its direction to the liquidity used up.
        inflight_htlcs: &'a InFlightHtlcs,
 }
 
-impl<'a, S: Score> ScorerAccountingForInFlightHtlcs<'a, S> {
+impl<'a, S: Score<ScoreParams = SP>, SP: Sized> ScorerAccountingForInFlightHtlcs<'a, S, SP> {
        /// Initialize a new `ScorerAccountingForInFlightHtlcs`.
-       pub fn new(scorer: S, inflight_htlcs: &'a InFlightHtlcs) -> Self {
+       pub fn new(scorer: &'a mut S, inflight_htlcs: &'a InFlightHtlcs) -> Self {
                ScorerAccountingForInFlightHtlcs {
                        scorer,
                        inflight_htlcs
@@ -121,11 +121,11 @@ impl<'a, S: Score> ScorerAccountingForInFlightHtlcs<'a, S> {
 }
 
 #[cfg(c_bindings)]
-impl<'a, S: Score> Writeable for ScorerAccountingForInFlightHtlcs<'a, S> {
+impl<'a, S: Score<ScoreParams = SP>, SP: Sized> Writeable for ScorerAccountingForInFlightHtlcs<'a, S, SP> {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> { self.scorer.write(writer) }
 }
 
-impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
+impl<'a, S: Score<ScoreParams = SP>, SP: Sized> Score for ScorerAccountingForInFlightHtlcs<'a, S, SP>  {
        type ScoreParams = S::ScoreParams;
        fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
                if let Some(used_liquidity) = self.inflight_htlcs.used_liquidity_msat(
@@ -204,6 +204,15 @@ impl InFlightHtlcs {
                }
        }
 
+       /// Adds a known HTLC given the public key of the HTLC source, target, and short channel
+       /// id.
+       pub fn add_inflight_htlc(&mut self, source: &NodeId, target: &NodeId, channel_scid: u64, used_msat: u64){
+               self.0
+                       .entry((channel_scid, source < target))
+                       .and_modify(|used_liquidity_msat| *used_liquidity_msat += used_msat)
+                       .or_insert(used_msat);
+       }
+
        /// Returns liquidity in msat given the public key of the HTLC source, target, and short channel
        /// id.
        pub fn used_liquidity_msat(&self, source: &NodeId, target: &NodeId, channel_scid: u64) -> Option<u64> {
@@ -262,9 +271,9 @@ impl_writeable_tlv_based!(RouteHop, {
 });
 
 /// The blinded portion of a [`Path`], if we're routing to a recipient who provided blinded paths in
-/// their BOLT12 [`Invoice`].
+/// their [`Bolt12Invoice`].
 ///
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct BlindedTail {
        /// The hops of the [`BlindedPath`] provided by the recipient.
@@ -283,7 +292,7 @@ pub struct BlindedTail {
 }
 
 impl_writeable_tlv_based!(BlindedTail, {
-       (0, hops, vec_type),
+       (0, hops, required_vec),
        (2, blinding_point, required),
        (4, excess_final_cltv_expiry_delta, required),
        (6, final_value_msat, required),
@@ -417,7 +426,7 @@ impl Readable for Route {
                let blinded_tails = blinded_tails.unwrap_or(Vec::new());
                if blinded_tails.len() != 0 {
                        if blinded_tails.len() != paths.len() { return Err(DecodeError::InvalidValue) }
-                       for (mut path, blinded_tail_opt) in paths.iter_mut().zip(blinded_tails.into_iter()) {
+                       for (path, blinded_tail_opt) in paths.iter_mut().zip(blinded_tails.into_iter()) {
                                path.blinded_tail = blinded_tail_opt;
                        }
                }
@@ -481,6 +490,8 @@ pub const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008;
 // limits, but for now more than 10 paths likely carries too much one-path failure.
 pub const DEFAULT_MAX_PATH_COUNT: u8 = 10;
 
+const DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF: u8 = 2;
+
 // The median hop CLTV expiry delta currently seen in the network.
 const MEDIAN_HOP_CLTV_EXPIRY_DELTA: u32 = 40;
 
@@ -548,10 +559,10 @@ impl Writeable for PaymentParameters {
                        (1, self.max_total_cltv_expiry_delta, required),
                        (2, self.payee.features(), option),
                        (3, self.max_path_count, required),
-                       (4, *clear_hints, vec_type),
+                       (4, *clear_hints, required_vec),
                        (5, self.max_channel_saturation_power_of_half, required),
                        (6, self.expiry_time, option),
-                       (7, self.previously_failed_channels, vec_type),
+                       (7, self.previously_failed_channels, required_vec),
                        (8, *blinded_hints, optional_vec),
                        (9, self.payee.final_cltv_expiry_delta(), option),
                });
@@ -566,14 +577,13 @@ impl ReadableArgs<u32> for PaymentParameters {
                        (1, max_total_cltv_expiry_delta, (default_value, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA)),
                        (2, features, (option: ReadableArgs, payee_pubkey.is_some())),
                        (3, max_path_count, (default_value, DEFAULT_MAX_PATH_COUNT)),
-                       (4, route_hints, vec_type),
-                       (5, max_channel_saturation_power_of_half, (default_value, 2)),
+                       (4, clear_route_hints, required_vec),
+                       (5, max_channel_saturation_power_of_half, (default_value, DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF)),
                        (6, expiry_time, option),
-                       (7, previously_failed_channels, vec_type),
+                       (7, previously_failed_channels, optional_vec),
                        (8, blinded_route_hints, optional_vec),
                        (9, final_cltv_expiry_delta, (default_value, default_final_cltv_expiry_delta)),
                });
-               let clear_route_hints = route_hints.unwrap_or(vec![]);
                let blinded_route_hints = blinded_route_hints.unwrap_or(vec![]);
                let payee = if blinded_route_hints.len() != 0 {
                        if clear_route_hints.len() != 0 || payee_pubkey.is_some() { return Err(DecodeError::InvalidValue) }
@@ -612,7 +622,7 @@ impl PaymentParameters {
                        expiry_time: None,
                        max_total_cltv_expiry_delta: DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
                        max_path_count: DEFAULT_MAX_PATH_COUNT,
-                       max_channel_saturation_power_of_half: 2,
+                       max_channel_saturation_power_of_half: DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF,
                        previously_failed_channels: Vec::new(),
                }
        }
@@ -630,15 +640,47 @@ impl PaymentParameters {
        /// [`RecipientOnionFields::secret_only`]: crate::ln::channelmanager::RecipientOnionFields::secret_only
        pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32, allow_mpp: bool) -> Self {
                Self::from_node_id(payee_pubkey, final_cltv_expiry_delta)
-                       .with_bolt11_features(InvoiceFeatures::for_keysend(allow_mpp))
+                       .with_bolt11_features(Bolt11InvoiceFeatures::for_keysend(allow_mpp))
                        .expect("PaymentParameters::from_node_id should always initialize the payee as unblinded")
        }
 
-       /// Includes the payee's features. Errors if the parameters were initialized with blinded payment
-       /// paths.
+       /// Creates parameters for paying to a blinded payee from the provided invoice. Sets
+       /// [`Payee::Blinded::route_hints`], [`Payee::Blinded::features`], and
+       /// [`PaymentParameters::expiry_time`].
+       pub fn from_bolt12_invoice(invoice: &Bolt12Invoice) -> Self {
+               Self::blinded(invoice.payment_paths().to_vec())
+                       .with_bolt12_features(invoice.features().clone()).unwrap()
+                       .with_expiry_time(invoice.created_at().as_secs().saturating_add(invoice.relative_expiry().as_secs()))
+       }
+
+       fn blinded(blinded_route_hints: Vec<(BlindedPayInfo, BlindedPath)>) -> Self {
+               Self {
+                       payee: Payee::Blinded { route_hints: blinded_route_hints, features: None },
+                       expiry_time: None,
+                       max_total_cltv_expiry_delta: DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
+                       max_path_count: DEFAULT_MAX_PATH_COUNT,
+                       max_channel_saturation_power_of_half: DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF,
+                       previously_failed_channels: Vec::new(),
+               }
+       }
+
+       /// Includes the payee's features. Errors if the parameters were not initialized with
+       /// [`PaymentParameters::from_bolt12_invoice`].
+       ///
+       /// This is not exported to bindings users since bindings don't support move semantics
+       pub fn with_bolt12_features(self, features: Bolt12InvoiceFeatures) -> Result<Self, ()> {
+               match self.payee {
+                       Payee::Clear { .. } => Err(()),
+                       Payee::Blinded { route_hints, .. } =>
+                               Ok(Self { payee: Payee::Blinded { route_hints, features: Some(features) }, ..self })
+               }
+       }
+
+       /// Includes the payee's features. Errors if the parameters were initialized with
+       /// [`PaymentParameters::from_bolt12_invoice`].
        ///
        /// This is not exported to bindings users since bindings don't support move semantics
-       pub fn with_bolt11_features(self, features: InvoiceFeatures) -> Result<Self, ()> {
+       pub fn with_bolt11_features(self, features: Bolt11InvoiceFeatures) -> Result<Self, ()> {
                match self.payee {
                        Payee::Blinded { .. } => Err(()),
                        Payee::Clear { route_hints, node_id, final_cltv_expiry_delta, .. } =>
@@ -651,7 +693,7 @@ impl PaymentParameters {
        }
 
        /// Includes hints for routing to the payee. Errors if the parameters were initialized with
-       /// blinded payment paths.
+       /// [`PaymentParameters::from_bolt12_invoice`].
        ///
        /// This is not exported to bindings users since bindings don't support move semantics
        pub fn with_route_hints(self, route_hints: Vec<RouteHint>) -> Result<Self, ()> {
@@ -687,7 +729,8 @@ impl PaymentParameters {
                Self { max_path_count, ..self }
        }
 
-       /// Includes a limit for the maximum number of payment paths that may be used.
+       /// Includes a limit for the maximum share of a channel's total capacity that can be sent over, as
+       /// a power of 1/2. See [`PaymentParameters::max_channel_saturation_power_of_half`].
        ///
        /// This is not exported to bindings users since bindings don't support move semantics
        pub fn with_max_channel_saturation_power_of_half(self, max_channel_saturation_power_of_half: u8) -> Self {
@@ -723,7 +766,7 @@ pub enum Payee {
                /// does not contain any features.
                ///
                /// [`for_keysend`]: PaymentParameters::for_keysend
-               features: Option<InvoiceFeatures>,
+               features: Option<Bolt11InvoiceFeatures>,
                /// The minimum CLTV delta at the end of the route. This value must not be zero.
                final_cltv_expiry_delta: u32,
        },
@@ -760,14 +803,27 @@ impl Payee {
                        _ => None,
                }
        }
+       fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPath)] {
+               match self {
+                       Self::Blinded { route_hints, .. } => &route_hints[..],
+                       Self::Clear { .. } => &[]
+               }
+       }
+
+       fn unblinded_route_hints(&self) -> &[RouteHint] {
+               match self {
+                       Self::Blinded { .. } => &[],
+                       Self::Clear { route_hints, .. } => &route_hints[..]
+               }
+       }
 }
 
 enum FeaturesRef<'a> {
-       Bolt11(&'a InvoiceFeatures),
+       Bolt11(&'a Bolt11InvoiceFeatures),
        Bolt12(&'a Bolt12InvoiceFeatures),
 }
 enum Features {
-       Bolt11(InvoiceFeatures),
+       Bolt11(Bolt11InvoiceFeatures),
        Bolt12(Bolt12InvoiceFeatures),
 }
 
@@ -778,7 +834,7 @@ impl Features {
                        _ => None,
                }
        }
-       fn bolt11(self) -> Option<InvoiceFeatures> {
+       fn bolt11(self) -> Option<Bolt11InvoiceFeatures> {
                match self {
                        Self::Bolt11(f) => Some(f),
                        _ => None,
@@ -904,18 +960,34 @@ enum CandidateRouteHop<'a> {
                info: DirectedChannelInfo<'a>,
                short_channel_id: u64,
        },
-       /// A hop to the payee found in the payment invoice, though not necessarily a direct channel.
+       /// A hop to the payee found in the BOLT 11 payment invoice, though not necessarily a direct
+       /// channel.
        PrivateHop {
                hint: &'a RouteHintHop,
-       }
+       },
+       /// The payee's identity is concealed behind blinded paths provided in a BOLT 12 invoice.
+       Blinded {
+               hint: &'a (BlindedPayInfo, BlindedPath),
+               hint_idx: usize,
+       },
+       /// Similar to [`Self::Blinded`], but the path here has 1 blinded hop. `BlindedPayInfo` provided
+       /// for 1-hop blinded paths is ignored because it is meant to apply to the hops *between* the
+       /// introduction node and the destination. Useful for tracking that we need to include a blinded
+       /// path at the end of our [`Route`].
+       OneHopBlinded {
+               hint: &'a (BlindedPayInfo, BlindedPath),
+               hint_idx: usize,
+       },
 }
 
 impl<'a> CandidateRouteHop<'a> {
-       fn short_channel_id(&self) -> u64 {
+       fn short_channel_id(&self) -> Option<u64> {
                match self {
-                       CandidateRouteHop::FirstHop { details } => details.get_outbound_payment_scid().unwrap(),
-                       CandidateRouteHop::PublicHop { short_channel_id, .. } => *short_channel_id,
-                       CandidateRouteHop::PrivateHop { hint } => hint.short_channel_id,
+                       CandidateRouteHop::FirstHop { details } => Some(details.get_outbound_payment_scid().unwrap()),
+                       CandidateRouteHop::PublicHop { short_channel_id, .. } => Some(*short_channel_id),
+                       CandidateRouteHop::PrivateHop { hint } => Some(hint.short_channel_id),
+                       CandidateRouteHop::Blinded { .. } => None,
+                       CandidateRouteHop::OneHopBlinded { .. } => None,
                }
        }
 
@@ -925,6 +997,8 @@ impl<'a> CandidateRouteHop<'a> {
                        CandidateRouteHop::FirstHop { details } => details.counterparty.features.to_context(),
                        CandidateRouteHop::PublicHop { info, .. } => info.channel().features.clone(),
                        CandidateRouteHop::PrivateHop { .. } => ChannelFeatures::empty(),
+                       CandidateRouteHop::Blinded { .. } => ChannelFeatures::empty(),
+                       CandidateRouteHop::OneHopBlinded { .. } => ChannelFeatures::empty(),
                }
        }
 
@@ -933,6 +1007,8 @@ impl<'a> CandidateRouteHop<'a> {
                        CandidateRouteHop::FirstHop { .. } => 0,
                        CandidateRouteHop::PublicHop { info, .. } => info.direction().cltv_expiry_delta as u32,
                        CandidateRouteHop::PrivateHop { hint } => hint.cltv_expiry_delta as u32,
+                       CandidateRouteHop::Blinded { hint, .. } => hint.0.cltv_expiry_delta as u32,
+                       CandidateRouteHop::OneHopBlinded { .. } => 0,
                }
        }
 
@@ -941,6 +1017,8 @@ impl<'a> CandidateRouteHop<'a> {
                        CandidateRouteHop::FirstHop { details } => details.next_outbound_htlc_minimum_msat,
                        CandidateRouteHop::PublicHop { info, .. } => info.direction().htlc_minimum_msat,
                        CandidateRouteHop::PrivateHop { hint } => hint.htlc_minimum_msat.unwrap_or(0),
+                       CandidateRouteHop::Blinded { hint, .. } => hint.0.htlc_minimum_msat,
+                       CandidateRouteHop::OneHopBlinded { .. } => 0,
                }
        }
 
@@ -951,6 +1029,14 @@ impl<'a> CandidateRouteHop<'a> {
                        },
                        CandidateRouteHop::PublicHop { info, .. } => info.direction().fees,
                        CandidateRouteHop::PrivateHop { hint } => hint.fees,
+                       CandidateRouteHop::Blinded { hint, .. } => {
+                               RoutingFees {
+                                       base_msat: hint.0.fee_base_msat,
+                                       proportional_millionths: hint.0.fee_proportional_millionths
+                               }
+                       },
+                       CandidateRouteHop::OneHopBlinded { .. } =>
+                               RoutingFees { base_msat: 0, proportional_millionths: 0 },
                }
        }
 
@@ -964,8 +1050,35 @@ impl<'a> CandidateRouteHop<'a> {
                                EffectiveCapacity::HintMaxHTLC { amount_msat: *max },
                        CandidateRouteHop::PrivateHop { hint: RouteHintHop { htlc_maximum_msat: None, .. }} =>
                                EffectiveCapacity::Infinite,
+                       CandidateRouteHop::Blinded { hint, .. } =>
+                               EffectiveCapacity::HintMaxHTLC { amount_msat: hint.0.htlc_maximum_msat },
+                       CandidateRouteHop::OneHopBlinded { .. } => EffectiveCapacity::Infinite,
                }
        }
+
+       fn id(&self, channel_direction: bool /* src_node_id < target_node_id */) -> CandidateHopId {
+               match self {
+                       CandidateRouteHop::Blinded { hint_idx, .. } => CandidateHopId::Blinded(*hint_idx),
+                       CandidateRouteHop::OneHopBlinded { hint_idx, .. } => CandidateHopId::Blinded(*hint_idx),
+                       _ => CandidateHopId::Clear((self.short_channel_id().unwrap(), channel_direction)),
+               }
+       }
+       fn blinded_path(&self) -> Option<&'a BlindedPath> {
+               match self {
+                       CandidateRouteHop::Blinded { hint, .. } | CandidateRouteHop::OneHopBlinded { hint, .. } => {
+                               Some(&hint.1)
+                       },
+                       _ => None,
+               }
+       }
+}
+
+#[derive(Clone, Copy, Eq, Hash, Ord, PartialOrd, PartialEq)]
+enum CandidateHopId {
+       /// Contains (scid, src_node_id < target_node_id)
+       Clear((u64, bool)),
+       /// Index of the blinded route hint in [`Payee::Blinded::route_hints`].
+       Blinded(usize),
 }
 
 #[inline]
@@ -1116,7 +1229,7 @@ impl<'a> PaymentPath<'a> {
                                cur_hop_fees_msat = self.hops.get(i + 1).unwrap().0.hop_use_fee_msat;
                        }
 
-                       let mut cur_hop = &mut self.hops.get_mut(i).unwrap().0;
+                       let cur_hop = &mut self.hops.get_mut(i).unwrap().0;
                        cur_hop.next_hops_fee_msat = total_fee_paid_msat;
                        // Overpay in fees if we can't save these funds due to htlc_minimum_msat.
                        // We try to account for htlc_minimum_msat in scoring (add_entry!), so that nodes don't
@@ -1207,9 +1320,27 @@ impl fmt::Display for LoggedPayeePubkey {
        }
 }
 
+struct LoggedCandidateHop<'a>(&'a CandidateRouteHop<'a>);
+impl<'a> fmt::Display for LoggedCandidateHop<'a> {
+       fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+               match self.0 {
+                       CandidateRouteHop::Blinded { hint, .. } | CandidateRouteHop::OneHopBlinded { hint, .. } => {
+                               "blinded route hint with introduction node id ".fmt(f)?;
+                               hint.1.introduction_node_id.fmt(f)?;
+                               " and blinding point ".fmt(f)?;
+                               hint.1.blinding_point.fmt(f)
+                       },
+                       _ => {
+                               "SCID ".fmt(f)?;
+                               self.0.short_channel_id().unwrap().fmt(f)
+                       },
+               }
+       }
+}
+
 #[inline]
 fn sort_first_hop_channels(
-       channels: &mut Vec<&ChannelDetails>, used_channel_liquidities: &HashMap<(u64, bool), u64>,
+       channels: &mut Vec<&ChannelDetails>, used_liquidities: &HashMap<CandidateHopId, u64>,
        recommended_value_msat: u64, our_node_pubkey: &PublicKey
 ) {
        // Sort the first_hops channels to the same node(s) in priority order of which channel we'd
@@ -1227,11 +1358,11 @@ fn sort_first_hop_channels(
        // Available outbound balances factor in liquidity already reserved for previously found paths.
        channels.sort_unstable_by(|chan_a, chan_b| {
                let chan_a_outbound_limit_msat = chan_a.next_outbound_htlc_limit_msat
-                       .saturating_sub(*used_channel_liquidities.get(&(chan_a.get_outbound_payment_scid().unwrap(),
-                       our_node_pubkey < &chan_a.counterparty.node_id)).unwrap_or(&0));
+                       .saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_a.get_outbound_payment_scid().unwrap(),
+                       our_node_pubkey < &chan_a.counterparty.node_id))).unwrap_or(&0));
                let chan_b_outbound_limit_msat = chan_b.next_outbound_htlc_limit_msat
-                       .saturating_sub(*used_channel_liquidities.get(&(chan_b.get_outbound_payment_scid().unwrap(),
-                       our_node_pubkey < &chan_b.counterparty.node_id)).unwrap_or(&0));
+                       .saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_b.get_outbound_payment_scid().unwrap(),
+                       our_node_pubkey < &chan_b.counterparty.node_id))).unwrap_or(&0));
                if chan_b_outbound_limit_msat < recommended_value_msat || chan_a_outbound_limit_msat < recommended_value_msat {
                        // Sort in descending order
                        chan_b_outbound_limit_msat.cmp(&chan_a_outbound_limit_msat)
@@ -1295,7 +1426,7 @@ where L::Target: Logger {
        // unblinded payee id as an option. We also need a non-optional "payee id" for path construction,
        // so use a dummy id for this in the blinded case.
        let payee_node_id_opt = payment_params.payee.node_id().map(|pk| NodeId::from_pubkey(&pk));
-       const DUMMY_BLINDED_PAYEE_ID: [u8; 33] = [42u8; 33];
+       const DUMMY_BLINDED_PAYEE_ID: [u8; 33] = [2; 33];
        let maybe_dummy_payee_pk = payment_params.payee.node_id().unwrap_or_else(|| PublicKey::from_slice(&DUMMY_BLINDED_PAYEE_ID).unwrap());
        let maybe_dummy_payee_node_id = NodeId::from_pubkey(&maybe_dummy_payee_pk);
        let our_node_id = NodeId::from_pubkey(&our_node_pubkey);
@@ -1322,8 +1453,23 @@ where L::Target: Logger {
                                }
                        }
                },
-               _ => return Err(LightningError{err: "Routing to blinded paths isn't supported yet".to_owned(), action: ErrorAction::IgnoreError}),
-
+               Payee::Blinded { route_hints, .. } => {
+                       if route_hints.iter().all(|(_, path)| &path.introduction_node_id == our_node_pubkey) {
+                               return Err(LightningError{err: "Cannot generate a route to blinded paths if we are the introduction node to all of them".to_owned(), action: ErrorAction::IgnoreError});
+                       }
+                       for (_, blinded_path) in route_hints.iter() {
+                               if blinded_path.blinded_hops.len() == 0 {
+                                       return Err(LightningError{err: "0-hop blinded path provided".to_owned(), action: ErrorAction::IgnoreError});
+                               } else if &blinded_path.introduction_node_id == our_node_pubkey {
+                                       log_info!(logger, "Got blinded path with ourselves as the introduction node, ignoring");
+                               } else if blinded_path.blinded_hops.len() == 1 &&
+                                       route_hints.iter().any( |(_, p)| p.blinded_hops.len() == 1
+                                               && p.introduction_node_id != blinded_path.introduction_node_id)
+                               {
+                                       return Err(LightningError{err: format!("1-hop blinded paths must all have matching introduction node ids"), action: ErrorAction::IgnoreError});
+                               }
+                       }
+               }
        }
        let final_cltv_expiry_delta = payment_params.payee.final_cltv_expiry_delta().unwrap_or(0);
        if payment_params.max_total_cltv_expiry_delta <= final_cltv_expiry_delta {
@@ -1475,11 +1621,12 @@ where L::Target: Logger {
        // drop the requirement by setting this to 0.
        let mut channel_saturation_pow_half = payment_params.max_channel_saturation_power_of_half;
 
-       // Keep track of how much liquidity has been used in selected channels. Used to determine
-       // if the channel can be used by additional MPP paths or to inform path finding decisions. It is
-       // aware of direction *only* to ensure that the correct htlc_maximum_msat value is used. Hence,
-       // liquidity used in one direction will not offset any used in the opposite direction.
-       let mut used_channel_liquidities: HashMap<(u64, bool), u64> =
+       // Keep track of how much liquidity has been used in selected channels or blinded paths. Used to
+       // determine if the channel can be used by additional MPP paths or to inform path finding
+       // decisions. It is aware of direction *only* to ensure that the correct htlc_maximum_msat value
+       // is used. Hence, liquidity used in one direction will not offset any used in the opposite
+       // direction.
+       let mut used_liquidities: HashMap<CandidateHopId, u64> =
                HashMap::with_capacity(network_nodes.len());
 
        // Keeping track of how much value we already collected across other paths. Helps to decide
@@ -1487,7 +1634,7 @@ where L::Target: Logger {
        let mut already_collected_value_msat = 0;
 
        for (_, channels) in first_hop_targets.iter_mut() {
-               sort_first_hop_channels(channels, &used_channel_liquidities, recommended_value_msat,
+               sort_first_hop_channels(channels, &used_liquidities, recommended_value_msat,
                        our_node_pubkey);
        }
 
@@ -1510,7 +1657,7 @@ where L::Target: Logger {
                        // - for regular channels at channel announcement (TODO)
                        // - for first and last hops early in get_route
                        if $src_node_id != $dest_node_id {
-                               let short_channel_id = $candidate.short_channel_id();
+                               let scid_opt = $candidate.short_channel_id();
                                let effective_capacity = $candidate.effective_capacity();
                                let htlc_maximum_msat = max_htlc_from_capacity(effective_capacity, channel_saturation_pow_half);
 
@@ -1522,8 +1669,8 @@ where L::Target: Logger {
                                // if the amount being transferred over this path is lower.
                                // We do this for now, but this is a subject for removal.
                                if let Some(mut available_value_contribution_msat) = htlc_maximum_msat.checked_sub($next_hops_fee_msat) {
-                                       let used_liquidity_msat = used_channel_liquidities
-                                               .get(&(short_channel_id, $src_node_id < $dest_node_id))
+                                       let used_liquidity_msat = used_liquidities
+                                               .get(&$candidate.id($src_node_id < $dest_node_id))
                                                .map_or(0, |used_liquidity_msat| {
                                                        available_value_contribution_msat = available_value_contribution_msat
                                                                .saturating_sub(*used_liquidity_msat);
@@ -1565,8 +1712,8 @@ where L::Target: Logger {
                                                 (amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
                                                  recommended_value_msat > $next_hops_path_htlc_minimum_msat));
 
-                                       let payment_failed_on_this_channel =
-                                               payment_params.previously_failed_channels.contains(&short_channel_id);
+                                       let payment_failed_on_this_channel = scid_opt.map_or(false,
+                                               |scid| payment_params.previously_failed_channels.contains(&scid));
 
                                        // If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
                                        // bother considering this channel. If retrying with recommended_value_msat may
@@ -1635,9 +1782,9 @@ where L::Target: Logger {
                                                                inflight_htlc_msat: used_liquidity_msat,
                                                                effective_capacity,
                                                        };
-                                                       let channel_penalty_msat = scorer.channel_penalty_msat(
-                                                               short_channel_id, &$src_node_id, &$dest_node_id, channel_usage, score_params
-                                                       );
+                                                       let channel_penalty_msat = scid_opt.map_or(0,
+                                                               |scid| scorer.channel_penalty_msat(scid, &$src_node_id, &$dest_node_id,
+                                                                       channel_usage, score_params));
                                                        let path_penalty_msat = $next_hops_path_penalty_msat
                                                                .saturating_add(channel_penalty_msat);
                                                        let new_graph_node = RouteGraphNode {
@@ -1794,7 +1941,7 @@ where L::Target: Logger {
 
        // TODO: diversify by nodes (so that all paths aren't doomed if one node is offline).
        'paths_collection: loop {
-               // For every new path, start from scratch, except for used_channel_liquidities, which
+               // For every new path, start from scratch, except for used_liquidities, which
                // helps to avoid reusing previously selected paths in future iterations.
                targets.clear();
                dist.clear();
@@ -1807,8 +1954,8 @@ where L::Target: Logger {
                                let candidate = CandidateRouteHop::FirstHop { details };
                                let added = add_entry!(candidate, our_node_id, payee, 0, path_value_msat,
                                                                        0, 0u64, 0, 0).is_some();
-                               log_trace!(logger, "{} direct route to payee via SCID {}",
-                                               if added { "Added" } else { "Skipped" }, candidate.short_channel_id());
+                               log_trace!(logger, "{} direct route to payee via {}",
+                                               if added { "Added" } else { "Skipped" }, LoggedCandidateHop(&candidate));
                        }
                }));
 
@@ -1829,11 +1976,37 @@ where L::Target: Logger {
                // If a caller provided us with last hops, add them to routing targets. Since this happens
                // earlier than general path finding, they will be somewhat prioritized, although currently
                // it matters only if the fees are exactly the same.
-               let route_hints = match &payment_params.payee {
-                       Payee::Clear { route_hints, .. } => route_hints,
-                       _ => return Err(LightningError{err: "Routing to blinded paths isn't supported yet".to_owned(), action: ErrorAction::IgnoreError}),
-               };
-               for route in route_hints.iter().filter(|route| !route.0.is_empty()) {
+               for (hint_idx, hint) in payment_params.payee.blinded_route_hints().iter().enumerate() {
+                       let intro_node_id = NodeId::from_pubkey(&hint.1.introduction_node_id);
+                       let have_intro_node_in_graph =
+                               // Only add the hops in this route to our candidate set if either
+                               // we have a direct channel to the first hop or the first hop is
+                               // in the regular network graph.
+                               first_hop_targets.get(&intro_node_id).is_some() ||
+                               network_nodes.get(&intro_node_id).is_some();
+                       if !have_intro_node_in_graph { continue }
+                       let candidate = if hint.1.blinded_hops.len() == 1 {
+                               CandidateRouteHop::OneHopBlinded { hint, hint_idx }
+                       } else { CandidateRouteHop::Blinded { hint, hint_idx } };
+                       let mut path_contribution_msat = path_value_msat;
+                       if let Some(hop_used_msat) = add_entry!(candidate, intro_node_id, maybe_dummy_payee_node_id,
+                               0, path_contribution_msat, 0, 0_u64, 0, 0)
+                       {
+                               path_contribution_msat = hop_used_msat;
+                       } else { continue }
+                       if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&hint.1.introduction_node_id)) {
+                               sort_first_hop_channels(first_channels, &used_liquidities, recommended_value_msat,
+                                       our_node_pubkey);
+                               for details in first_channels {
+                                       let first_hop_candidate = CandidateRouteHop::FirstHop { details };
+                                       add_entry!(first_hop_candidate, our_node_id, intro_node_id, 0, path_contribution_msat, 0,
+                                               0_u64, 0, 0);
+                               }
+                       }
+               }
+               for route in payment_params.payee.unblinded_route_hints().iter()
+                       .filter(|route| !route.0.is_empty())
+               {
                        let first_hop_in_route = &(route.0)[0];
                        let have_hop_src_in_graph =
                                // Only add the hops in this route to our candidate set if either
@@ -1880,8 +2053,9 @@ where L::Target: Logger {
                                                hop_used = false;
                                        }
 
-                                       let used_liquidity_msat = used_channel_liquidities
-                                               .get(&(hop.short_channel_id, source < target)).copied().unwrap_or(0);
+                                       let used_liquidity_msat = used_liquidities
+                                               .get(&candidate.id(source < target)).copied()
+                                               .unwrap_or(0);
                                        let channel_usage = ChannelUsage {
                                                amount_msat: final_value_msat + aggregate_next_hops_fee_msat,
                                                inflight_htlc_msat: used_liquidity_msat,
@@ -1901,7 +2075,7 @@ where L::Target: Logger {
 
                                        // Searching for a direct channel between last checked hop and first_hop_targets
                                        if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&prev_hop_id)) {
-                                               sort_first_hop_channels(first_channels, &used_channel_liquidities,
+                                               sort_first_hop_channels(first_channels, &used_liquidities,
                                                        recommended_value_msat, our_node_pubkey);
                                                for details in first_channels {
                                                        let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -1942,7 +2116,7 @@ where L::Target: Logger {
                                                // always assumes that the third argument is a node to which we have a
                                                // path.
                                                if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&hop.src_node_id)) {
-                                                       sort_first_hop_channels(first_channels, &used_channel_liquidities,
+                                                       sort_first_hop_channels(first_channels, &used_liquidities,
                                                                recommended_value_msat, our_node_pubkey);
                                                        for details in first_channels {
                                                                let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -1988,10 +2162,12 @@ where L::Target: Logger {
                                        let mut features_set = false;
                                        if let Some(first_channels) = first_hop_targets.get(&ordered_hops.last().unwrap().0.node_id) {
                                                for details in first_channels {
-                                                       if details.get_outbound_payment_scid().unwrap() == ordered_hops.last().unwrap().0.candidate.short_channel_id() {
-                                                               ordered_hops.last_mut().unwrap().1 = details.counterparty.features.to_context();
-                                                               features_set = true;
-                                                               break;
+                                                       if let Some(scid) = ordered_hops.last().unwrap().0.candidate.short_channel_id() {
+                                                               if details.get_outbound_payment_scid().unwrap() == scid {
+                                                                       ordered_hops.last_mut().unwrap().1 = details.counterparty.features.to_context();
+                                                                       features_set = true;
+                                                                       break;
+                                                               }
                                                        }
                                                }
                                        }
@@ -2060,8 +2236,8 @@ where L::Target: Logger {
                                        .chain(payment_path.hops.iter().map(|(hop, _)| &hop.node_id));
                                for (prev_hop, (hop, _)) in prev_hop_iter.zip(payment_path.hops.iter()) {
                                        let spent_on_hop_msat = value_contribution_msat + hop.next_hops_fee_msat;
-                                       let used_liquidity_msat = used_channel_liquidities
-                                               .entry((hop.candidate.short_channel_id(), *prev_hop < hop.node_id))
+                                       let used_liquidity_msat = used_liquidities
+                                               .entry(hop.candidate.id(*prev_hop < hop.node_id))
                                                .and_modify(|used_liquidity_msat| *used_liquidity_msat += spent_on_hop_msat)
                                                .or_insert(spent_on_hop_msat);
                                        let hop_capacity = hop.candidate.effective_capacity();
@@ -2077,11 +2253,12 @@ where L::Target: Logger {
                                        // If we weren't capped by hitting a liquidity limit on a channel in the path,
                                        // we'll probably end up picking the same path again on the next iteration.
                                        // Decrease the available liquidity of a hop in the middle of the path.
-                                       let victim_scid = payment_path.hops[(payment_path.hops.len()) / 2].0.candidate.short_channel_id();
+                                       let victim_candidate = &payment_path.hops[(payment_path.hops.len()) / 2].0.candidate;
                                        let exhausted = u64::max_value();
-                                       log_trace!(logger, "Disabling channel {} for future path building iterations to avoid duplicates.", victim_scid);
-                                       *used_channel_liquidities.entry((victim_scid, false)).or_default() = exhausted;
-                                       *used_channel_liquidities.entry((victim_scid, true)).or_default() = exhausted;
+                                       log_trace!(logger, "Disabling route candidate {} for future path building iterations to
+                                               avoid duplicates.", LoggedCandidateHop(victim_candidate));
+                                       *used_liquidities.entry(victim_candidate.id(false)).or_default() = exhausted;
+                                       *used_liquidities.entry(victim_candidate.id(true)).or_default() = exhausted;
                                }
 
                                // Track the total amount all our collected paths allow to send so that we know
@@ -2209,63 +2386,68 @@ where L::Target: Logger {
        // compare both SCIDs and NodeIds as individual nodes may use random aliases causing collisions
        // across nodes.
        selected_route.sort_unstable_by_key(|path| {
-               let mut key = [0u64; MAX_PATH_LENGTH_ESTIMATE as usize];
+               let mut key = [CandidateHopId::Clear((42, true)) ; MAX_PATH_LENGTH_ESTIMATE as usize];
                debug_assert!(path.hops.len() <= key.len());
-               for (scid, key) in path.hops.iter().map(|h| h.0.candidate.short_channel_id()).zip(key.iter_mut()) {
+               for (scid, key) in path.hops.iter() .map(|h| h.0.candidate.id(true)).zip(key.iter_mut()) {
                        *key = scid;
                }
                key
        });
        for idx in 0..(selected_route.len() - 1) {
                if idx + 1 >= selected_route.len() { break; }
-               if iter_equal(selected_route[idx    ].hops.iter().map(|h| (h.0.candidate.short_channel_id(), h.0.node_id)),
-                             selected_route[idx + 1].hops.iter().map(|h| (h.0.candidate.short_channel_id(), h.0.node_id))) {
+               if iter_equal(selected_route[idx    ].hops.iter().map(|h| (h.0.candidate.id(true), h.0.node_id)),
+                             selected_route[idx + 1].hops.iter().map(|h| (h.0.candidate.id(true), h.0.node_id))) {
                        let new_value = selected_route[idx].get_value_msat() + selected_route[idx + 1].get_value_msat();
                        selected_route[idx].update_value_and_recompute_fees(new_value);
                        selected_route.remove(idx + 1);
                }
        }
 
-       let mut selected_paths = Vec::<Vec<Result<RouteHop, LightningError>>>::new();
+       let mut paths = Vec::new();
        for payment_path in selected_route {
-               let mut path = payment_path.hops.iter().map(|(payment_hop, node_features)| {
-                       Ok(RouteHop {
-                               pubkey: PublicKey::from_slice(payment_hop.node_id.as_slice()).map_err(|_| LightningError{err: format!("Public key {:?} is invalid", &payment_hop.node_id), action: ErrorAction::IgnoreAndLog(Level::Trace)})?,
+               let mut hops = Vec::with_capacity(payment_path.hops.len());
+               for (hop, node_features) in payment_path.hops.iter()
+                       .filter(|(h, _)| h.candidate.short_channel_id().is_some())
+               {
+                       hops.push(RouteHop {
+                               pubkey: PublicKey::from_slice(hop.node_id.as_slice()).map_err(|_| LightningError{err: format!("Public key {:?} is invalid", &hop.node_id), action: ErrorAction::IgnoreAndLog(Level::Trace)})?,
                                node_features: node_features.clone(),
-                               short_channel_id: payment_hop.candidate.short_channel_id(),
-                               channel_features: payment_hop.candidate.features(),
-                               fee_msat: payment_hop.fee_msat,
-                               cltv_expiry_delta: payment_hop.candidate.cltv_expiry_delta(),
-                       })
-               }).collect::<Vec<_>>();
+                               short_channel_id: hop.candidate.short_channel_id().unwrap(),
+                               channel_features: hop.candidate.features(),
+                               fee_msat: hop.fee_msat,
+                               cltv_expiry_delta: hop.candidate.cltv_expiry_delta(),
+                       });
+               }
+               let mut final_cltv_delta = final_cltv_expiry_delta;
+               let blinded_tail = payment_path.hops.last().and_then(|(h, _)| {
+                       if let Some(blinded_path) = h.candidate.blinded_path() {
+                               final_cltv_delta = h.candidate.cltv_expiry_delta();
+                               Some(BlindedTail {
+                                       hops: blinded_path.blinded_hops.clone(),
+                                       blinding_point: blinded_path.blinding_point,
+                                       excess_final_cltv_expiry_delta: 0,
+                                       final_value_msat: h.fee_msat,
+                               })
+                       } else { None }
+               });
                // Propagate the cltv_expiry_delta one hop backwards since the delta from the current hop is
                // applicable for the previous hop.
-               path.iter_mut().rev().fold(final_cltv_expiry_delta, |prev_cltv_expiry_delta, hop| {
-                       core::mem::replace(&mut hop.as_mut().unwrap().cltv_expiry_delta, prev_cltv_expiry_delta)
+               hops.iter_mut().rev().fold(final_cltv_delta, |prev_cltv_expiry_delta, hop| {
+                       core::mem::replace(&mut hop.cltv_expiry_delta, prev_cltv_expiry_delta)
                });
-               selected_paths.push(path);
+
+               paths.push(Path { hops, blinded_tail });
        }
        // Make sure we would never create a route with more paths than we allow.
-       debug_assert!(selected_paths.len() <= payment_params.max_path_count.into());
+       debug_assert!(paths.len() <= payment_params.max_path_count.into());
 
        if let Some(node_features) = payment_params.payee.node_features() {
-               for path in selected_paths.iter_mut() {
-                       if let Ok(route_hop) = path.last_mut().unwrap() {
-                               route_hop.node_features = node_features.clone();
-                       }
+               for path in paths.iter_mut() {
+                       path.hops.last_mut().unwrap().node_features = node_features.clone();
                }
        }
 
-       let mut paths: Vec<Path> = Vec::new();
-       for results_vec in selected_paths {
-               let mut hops = Vec::with_capacity(results_vec.len());
-               for res in results_vec { hops.push(res?); }
-               paths.push(Path { hops, blinded_tail: None });
-       }
-       let route = Route {
-               paths,
-               payment_params: Some(payment_params.clone()),
-       };
+       let route = Route { paths, payment_params: Some(payment_params.clone()) };
        log_info!(logger, "Got route: {}", log_route!(route));
        Ok(route)
 }
@@ -2451,9 +2633,10 @@ mod tests {
        use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel};
        use crate::chain::transaction::OutPoint;
        use crate::sign::EntropySource;
-       use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
+       use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, ChannelFeatures, InitFeatures, NodeFeatures};
        use crate::ln::msgs::{ErrorAction, LightningError, UnsignedChannelUpdate, MAX_VALUE_MSAT};
        use crate::ln::channelmanager;
+       use crate::offers::invoice::BlindedPayInfo;
        use crate::util::config::UserConfig;
        use crate::util::test_utils as ln_test_utils;
        use crate::util::chacha20::ChaCha20;
@@ -2512,7 +2695,8 @@ mod tests {
                        inbound_htlc_minimum_msat: None,
                        inbound_htlc_maximum_msat: None,
                        config: None,
-                       feerate_sat_per_1000_weight: None
+                       feerate_sat_per_1000_weight: None,
+                       channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
                }
        }
 
@@ -4120,14 +4304,66 @@ mod tests {
 
        #[test]
        fn simple_mpp_route_test() {
+               let (secp_ctx, _, _, _, _) = build_graph();
+               let (_, _, _, nodes) = get_nodes(&secp_ctx);
+               let config = UserConfig::default();
+               let clear_payment_params = PaymentParameters::from_node_id(nodes[2], 42)
+                       .with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
+               do_simple_mpp_route_test(clear_payment_params);
+
+               // MPP to a 1-hop blinded path for nodes[2]
+               let bolt12_features: Bolt12InvoiceFeatures = channelmanager::provided_invoice_features(&config).to_context();
+               let blinded_path = BlindedPath {
+                       introduction_node_id: nodes[2],
+                       blinding_point: ln_test_utils::pubkey(42),
+                       blinded_hops: vec![BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }],
+               };
+               let blinded_payinfo = BlindedPayInfo { // These fields are ignored for 1-hop blinded paths
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       htlc_minimum_msat: 0,
+                       htlc_maximum_msat: 0,
+                       cltv_expiry_delta: 0,
+                       features: BlindedHopFeatures::empty(),
+               };
+               let one_hop_blinded_payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), blinded_path.clone())])
+                       .with_bolt12_features(bolt12_features.clone()).unwrap();
+               do_simple_mpp_route_test(one_hop_blinded_payment_params.clone());
+
+               // MPP to 3 2-hop blinded paths
+               let mut blinded_path_node_0 = blinded_path.clone();
+               blinded_path_node_0.introduction_node_id = nodes[0];
+               blinded_path_node_0.blinded_hops.push(blinded_path.blinded_hops[0].clone());
+               let mut node_0_payinfo = blinded_payinfo.clone();
+               node_0_payinfo.htlc_maximum_msat = 50_000;
+
+               let mut blinded_path_node_7 = blinded_path_node_0.clone();
+               blinded_path_node_7.introduction_node_id = nodes[7];
+               let mut node_7_payinfo = blinded_payinfo.clone();
+               node_7_payinfo.htlc_maximum_msat = 60_000;
+
+               let mut blinded_path_node_1 = blinded_path_node_0.clone();
+               blinded_path_node_1.introduction_node_id = nodes[1];
+               let mut node_1_payinfo = blinded_payinfo.clone();
+               node_1_payinfo.htlc_maximum_msat = 180_000;
+
+               let two_hop_blinded_payment_params = PaymentParameters::blinded(
+                       vec![
+                               (node_0_payinfo, blinded_path_node_0),
+                               (node_7_payinfo, blinded_path_node_7),
+                               (node_1_payinfo, blinded_path_node_1)
+                       ])
+                       .with_bolt12_features(bolt12_features).unwrap();
+               do_simple_mpp_route_test(two_hop_blinded_payment_params);
+       }
+
+
+       fn do_simple_mpp_route_test(payment_params: PaymentParameters) {
                let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = ln_test_utils::TestScorer::new();
                let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
-               let config = UserConfig::default();
-               let payment_params = PaymentParameters::from_node_id(nodes[2], 42)
-                       .with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
 
                // We need a route consisting of 3 paths:
                // From our node to node2 via node0, node7, node1 (three paths one hop each).
@@ -4256,8 +4492,12 @@ mod tests {
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
-                               assert_eq!(path.hops.len(), 2);
-                               assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]);
+                               if let Some(bt) = &path.blinded_tail {
+                                       assert_eq!(path.hops.len() + if bt.hops.len() == 1 { 0 } else { 1 }, 2);
+                               } else {
+                                       assert_eq!(path.hops.len(), 2);
+                                       assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]);
+                               }
                                total_amount_paid_msat += path.final_value_msat();
                        }
                        assert_eq!(total_amount_paid_msat, 250_000);
@@ -4270,8 +4510,22 @@ mod tests {
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
-                               assert_eq!(path.hops.len(), 2);
-                               assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]);
+                               if payment_params.payee.blinded_route_hints().len() != 0 {
+                                       assert!(path.blinded_tail.is_some()) } else { assert!(path.blinded_tail.is_none()) }
+                               if let Some(bt) = &path.blinded_tail {
+                                       assert_eq!(path.hops.len() + if bt.hops.len() == 1 { 0 } else { 1 }, 2);
+                                       if bt.hops.len() > 1 {
+                                               assert_eq!(path.hops.last().unwrap().pubkey,
+                                                       payment_params.payee.blinded_route_hints().iter()
+                                                               .find(|(p, _)| p.htlc_maximum_msat == path.final_value_msat())
+                                                               .map(|(_, p)| p.introduction_node_id).unwrap());
+                                       } else {
+                                               assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]);
+                                       }
+                               } else {
+                                       assert_eq!(path.hops.len(), 2);
+                                       assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]);
+                               }
                                total_amount_paid_msat += path.final_value_msat();
                        }
                        assert_eq!(total_amount_paid_msat, 290_000);
@@ -5850,7 +6104,7 @@ mod tests {
 
                let params = ProbabilisticScoringFeeParameters::default();
                let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
-               let features = super::InvoiceFeatures::empty();
+               let features = super::Bolt11InvoiceFeatures::empty();
 
                super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed(), 0, 2);
        }
@@ -6053,6 +6307,36 @@ mod tests {
                assert!(route.paths[0].hops.last().unwrap().fee_msat <= max_htlc_msat);
                assert!(route.paths[1].hops.last().unwrap().fee_msat <= max_htlc_msat);
                assert_eq!(route.get_total_amount(), amt_msat);
+
+               // Make sure this works for blinded route hints.
+               let blinded_path = BlindedPath {
+                       introduction_node_id: intermed_node_id,
+                       blinding_point: ln_test_utils::pubkey(42),
+                       blinded_hops: vec![
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(42), encrypted_payload: vec![] },
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(43), encrypted_payload: vec![] },
+                       ],
+               };
+               let blinded_payinfo = BlindedPayInfo {
+                       fee_base_msat: 100,
+                       fee_proportional_millionths: 0,
+                       htlc_minimum_msat: 1,
+                       htlc_maximum_msat: max_htlc_msat,
+                       cltv_expiry_delta: 10,
+                       features: BlindedHopFeatures::empty(),
+               };
+               let bolt12_features: Bolt12InvoiceFeatures = channelmanager::provided_invoice_features(&config).to_context();
+               let payment_params = PaymentParameters::blinded(vec![
+                       (blinded_payinfo.clone(), blinded_path.clone()),
+                       (blinded_payinfo.clone(), blinded_path.clone())])
+                       .with_bolt12_features(bolt12_features).unwrap();
+               let route = get_route(&our_node_id, &payment_params, &network_graph.read_only(),
+                       Some(&first_hops.iter().collect::<Vec<_>>()), amt_msat, Arc::clone(&logger), &scorer, &(),
+                       &random_seed_bytes).unwrap();
+               assert_eq!(route.paths.len(), 2);
+               assert!(route.paths[0].hops.last().unwrap().fee_msat <= max_htlc_msat);
+               assert!(route.paths[1].hops.last().unwrap().fee_msat <= max_htlc_msat);
+               assert_eq!(route.get_total_amount(), amt_msat);
        }
 
        #[test]
@@ -6199,6 +6483,190 @@ mod tests {
                assert_eq!(route.paths[0].blinded_tail.as_ref().unwrap().excess_final_cltv_expiry_delta, 40);
                assert_eq!(route.paths[0].hops.last().unwrap().cltv_expiry_delta, 40);
        }
+
+       #[test]
+       fn simple_blinded_route_hints() {
+               do_simple_blinded_route_hints(1);
+               do_simple_blinded_route_hints(2);
+               do_simple_blinded_route_hints(3);
+       }
+
+       fn do_simple_blinded_route_hints(num_blinded_hops: usize) {
+               // Check that we can generate a route to a blinded path with the expected hops.
+               let (secp_ctx, network, _, _, logger) = build_graph();
+               let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let network_graph = network.read_only();
+
+               let scorer = ln_test_utils::TestScorer::new();
+               let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+
+               let mut blinded_path = BlindedPath {
+                       introduction_node_id: nodes[2],
+                       blinding_point: ln_test_utils::pubkey(42),
+                       blinded_hops: Vec::with_capacity(num_blinded_hops),
+               };
+               for i in 0..num_blinded_hops {
+                       blinded_path.blinded_hops.push(
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 + i as u8), encrypted_payload: Vec::new() },
+                       );
+               }
+               let blinded_payinfo = BlindedPayInfo {
+                       fee_base_msat: 100,
+                       fee_proportional_millionths: 500,
+                       htlc_minimum_msat: 1000,
+                       htlc_maximum_msat: 100_000_000,
+                       cltv_expiry_delta: 15,
+                       features: BlindedHopFeatures::empty(),
+               };
+
+               let final_amt_msat = 1001;
+               let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), blinded_path.clone())]);
+               let route = get_route(&our_id, &payment_params, &network_graph, None, final_amt_msat , Arc::clone(&logger),
+                       &scorer, &(), &random_seed_bytes).unwrap();
+               assert_eq!(route.paths.len(), 1);
+               assert_eq!(route.paths[0].hops.len(), 2);
+
+               let tail = route.paths[0].blinded_tail.as_ref().unwrap();
+               assert_eq!(tail.hops, blinded_path.blinded_hops);
+               assert_eq!(tail.excess_final_cltv_expiry_delta, 0);
+               assert_eq!(tail.final_value_msat, 1001);
+
+               let final_hop = route.paths[0].hops.last().unwrap();
+               assert_eq!(final_hop.pubkey, blinded_path.introduction_node_id);
+               if tail.hops.len() > 1 {
+                       assert_eq!(final_hop.fee_msat,
+                               blinded_payinfo.fee_base_msat as u64 + blinded_payinfo.fee_proportional_millionths as u64 * tail.final_value_msat / 1000000);
+                       assert_eq!(final_hop.cltv_expiry_delta, blinded_payinfo.cltv_expiry_delta as u32);
+               } else {
+                       assert_eq!(final_hop.fee_msat, 0);
+                       assert_eq!(final_hop.cltv_expiry_delta, 0);
+               }
+       }
+
+       #[test]
+       fn blinded_path_routing_errors() {
+               // Check that we can generate a route to a blinded path with the expected hops.
+               let (secp_ctx, network, _, _, logger) = build_graph();
+               let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let network_graph = network.read_only();
+
+               let scorer = ln_test_utils::TestScorer::new();
+               let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+
+               let mut invalid_blinded_path = BlindedPath {
+                       introduction_node_id: nodes[2],
+                       blinding_point: ln_test_utils::pubkey(42),
+                       blinded_hops: vec![
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(43), encrypted_payload: vec![0; 43] },
+                       ],
+               };
+               let blinded_payinfo = BlindedPayInfo {
+                       fee_base_msat: 100,
+                       fee_proportional_millionths: 500,
+                       htlc_minimum_msat: 1000,
+                       htlc_maximum_msat: 100_000_000,
+                       cltv_expiry_delta: 15,
+                       features: BlindedHopFeatures::empty(),
+               };
+
+               let mut invalid_blinded_path_2 = invalid_blinded_path.clone();
+               invalid_blinded_path_2.introduction_node_id = ln_test_utils::pubkey(45);
+               let payment_params = PaymentParameters::blinded(vec![
+                       (blinded_payinfo.clone(), invalid_blinded_path.clone()),
+                       (blinded_payinfo.clone(), invalid_blinded_path_2)]);
+               match get_route(&our_id, &payment_params, &network_graph, None, 1001, Arc::clone(&logger),
+                       &scorer, &(), &random_seed_bytes)
+               {
+                       Err(LightningError { err, .. }) => {
+                               assert_eq!(err, "1-hop blinded paths must all have matching introduction node ids");
+                       },
+                       _ => panic!("Expected error")
+               }
+
+               invalid_blinded_path.introduction_node_id = our_id;
+               let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), invalid_blinded_path.clone())]);
+               match get_route(&our_id, &payment_params, &network_graph, None, 1001, Arc::clone(&logger),
+                       &scorer, &(), &random_seed_bytes)
+               {
+                       Err(LightningError { err, .. }) => {
+                               assert_eq!(err, "Cannot generate a route to blinded paths if we are the introduction node to all of them");
+                       },
+                       _ => panic!("Expected error")
+               }
+
+               invalid_blinded_path.introduction_node_id = ln_test_utils::pubkey(46);
+               invalid_blinded_path.blinded_hops.clear();
+               let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo, invalid_blinded_path)]);
+               match get_route(&our_id, &payment_params, &network_graph, None, 1001, Arc::clone(&logger),
+                       &scorer, &(), &random_seed_bytes)
+               {
+                       Err(LightningError { err, .. }) => {
+                               assert_eq!(err, "0-hop blinded path provided");
+                       },
+                       _ => panic!("Expected error")
+               }
+       }
+
+       #[test]
+       fn matching_intro_node_paths_provided() {
+               // Check that if multiple blinded paths with the same intro node are provided in payment
+               // parameters, we'll return the correct paths in the resulting MPP route.
+               let (secp_ctx, network, _, _, logger) = build_graph();
+               let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let network_graph = network.read_only();
+
+               let scorer = ln_test_utils::TestScorer::new();
+               let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               let config = UserConfig::default();
+
+               let bolt12_features: Bolt12InvoiceFeatures = channelmanager::provided_invoice_features(&config).to_context();
+               let blinded_path_1 = BlindedPath {
+                       introduction_node_id: nodes[2],
+                       blinding_point: ln_test_utils::pubkey(42),
+                       blinded_hops: vec![
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
+                       ],
+               };
+               let blinded_payinfo_1 = BlindedPayInfo {
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       htlc_minimum_msat: 0,
+                       htlc_maximum_msat: 30_000,
+                       cltv_expiry_delta: 0,
+                       features: BlindedHopFeatures::empty(),
+               };
+
+               let mut blinded_path_2 = blinded_path_1.clone();
+               blinded_path_2.blinding_point = ln_test_utils::pubkey(43);
+               let mut blinded_payinfo_2 = blinded_payinfo_1.clone();
+               blinded_payinfo_2.htlc_maximum_msat = 70_000;
+
+               let blinded_hints = vec![
+                       (blinded_payinfo_1.clone(), blinded_path_1.clone()),
+                       (blinded_payinfo_2.clone(), blinded_path_2.clone()),
+               ];
+               let payment_params = PaymentParameters::blinded(blinded_hints.clone())
+                       .with_bolt12_features(bolt12_features.clone()).unwrap();
+
+               let route = get_route(&our_id, &payment_params, &network_graph, None,
+                       100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
+               assert_eq!(route.paths.len(), 2);
+               let mut total_amount_paid_msat = 0;
+               for path in route.paths.into_iter() {
+                       assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]);
+                       if let Some(bt) = &path.blinded_tail {
+                               assert_eq!(bt.blinding_point,
+                                       blinded_hints.iter().find(|(p, _)| p.htlc_maximum_msat == path.final_value_msat())
+                                               .map(|(_, bp)| bp.blinding_point).unwrap());
+                       } else { panic!(); }
+                       total_amount_paid_msat += path.final_value_msat();
+               }
+               assert_eq!(total_amount_paid_msat, 100_000);
+       }
 }
 
 #[cfg(all(any(test, ldk_bench), not(feature = "no-std")))]
@@ -6212,7 +6680,7 @@ pub(crate) mod bench_utils {
        use crate::chain::transaction::OutPoint;
        use crate::sign::{EntropySource, KeysManager};
        use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails};
-       use crate::ln::features::InvoiceFeatures;
+       use crate::ln::features::Bolt11InvoiceFeatures;
        use crate::routing::gossip::NetworkGraph;
        use crate::util::config::UserConfig;
        use crate::util::ser::ReadableArgs;
@@ -6299,11 +6767,12 @@ pub(crate) mod bench_utils {
                        inbound_htlc_maximum_msat: None,
                        config: None,
                        feerate_sat_per_1000_weight: None,
+                       channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
                }
        }
 
        pub(crate) fn generate_test_routes<S: Score>(graph: &NetworkGraph<&TestLogger>, scorer: &mut S,
-               score_params: &S::ScoreParams, features: InvoiceFeatures, mut seed: u64,
+               score_params: &S::ScoreParams, features: Bolt11InvoiceFeatures, mut seed: u64,
                starting_amount: u64, route_count: usize,
        ) -> Vec<(ChannelDetails, PaymentParameters, u64)> {
                let payer = payer_pubkey();
@@ -6384,7 +6853,7 @@ pub mod benches {
        use super::*;
        use crate::sign::{EntropySource, KeysManager};
        use crate::ln::channelmanager;
-       use crate::ln::features::InvoiceFeatures;
+       use crate::ln::features::Bolt11InvoiceFeatures;
        use crate::routing::gossip::NetworkGraph;
        use crate::routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
        use crate::util::config::UserConfig;
@@ -6402,7 +6871,7 @@ pub mod benches {
                let logger = TestLogger::new();
                let network_graph = bench_utils::read_network_graph(&logger).unwrap();
                let scorer = FixedPenaltyScorer::with_penalty(0);
-               generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty(), 0,
+               generate_routes(bench, &network_graph, scorer, &(), Bolt11InvoiceFeatures::empty(), 0,
                        "generate_routes_with_zero_penalty_scorer");
        }
 
@@ -6420,7 +6889,7 @@ pub mod benches {
                let network_graph = bench_utils::read_network_graph(&logger).unwrap();
                let params = ProbabilisticScoringFeeParameters::default();
                let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
-               generate_routes(bench, &network_graph, scorer, &params, InvoiceFeatures::empty(), 0,
+               generate_routes(bench, &network_graph, scorer, &params, Bolt11InvoiceFeatures::empty(), 0,
                        "generate_routes_with_probabilistic_scorer");
        }
 
@@ -6446,7 +6915,7 @@ pub mod benches {
 
        fn generate_routes<S: Score>(
                bench: &mut Criterion, graph: &NetworkGraph<&TestLogger>, mut scorer: S,
-               score_params: &S::ScoreParams, features: InvoiceFeatures, starting_amount: u64,
+               score_params: &S::ScoreParams, features: Bolt11InvoiceFeatures, starting_amount: u64,
                bench_name: &'static str,
        ) {
                let payer = bench_utils::payer_pubkey();
index ee9c3d0c47356ddc53d9f7efc21f368b1ef77743..615cc1a19eb0ef4d52aac39b71a13aa7776793ee 100644 (file)
@@ -157,8 +157,11 @@ define_score!();
 ///
 /// [`find_route`]: crate::routing::router::find_route
 pub trait LockableScore<'a> {
+       /// The [`Score`] type.
+       type Score: 'a + Score;
+
        /// The locked [`Score`] type.
-       type Locked: 'a + Score;
+       type Locked: DerefMut<Target = Self::Score> + Sized;
 
        /// Returns the locked scorer.
        fn lock(&'a self) -> Self::Locked;
@@ -172,62 +175,38 @@ pub trait WriteableScore<'a>: LockableScore<'a> + Writeable {}
 
 #[cfg(not(c_bindings))]
 impl<'a, T> WriteableScore<'a> for T where T: LockableScore<'a> + Writeable {}
-/// This is not exported to bindings users
+#[cfg(not(c_bindings))]
 impl<'a, T: 'a + Score> LockableScore<'a> for Mutex<T> {
+       type Score = T;
        type Locked = MutexGuard<'a, T>;
 
-       fn lock(&'a self) -> MutexGuard<'a, T> {
+       fn lock(&'a self) -> Self::Locked {
                Mutex::lock(self).unwrap()
        }
 }
 
+#[cfg(not(c_bindings))]
 impl<'a, T: 'a + Score> LockableScore<'a> for RefCell<T> {
+       type Score = T;
        type Locked = RefMut<'a, T>;
 
-       fn lock(&'a self) -> RefMut<'a, T> {
+       fn lock(&'a self) -> Self::Locked {
                self.borrow_mut()
        }
 }
 
 #[cfg(c_bindings)]
 /// A concrete implementation of [`LockableScore`] which supports multi-threading.
-pub struct MultiThreadedLockableScore<S: Score> {
-       score: Mutex<S>,
-}
-#[cfg(c_bindings)]
-/// A locked `MultiThreadedLockableScore`.
-pub struct MultiThreadedScoreLock<'a, S: Score>(MutexGuard<'a, S>);
-#[cfg(c_bindings)]
-impl<'a, T: Score + 'a> Score for MultiThreadedScoreLock<'a, T> {
-       type ScoreParams = <T as Score>::ScoreParams;
-       fn channel_penalty_msat(&self, scid: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
-               self.0.channel_penalty_msat(scid, source, target, usage, score_params)
-       }
-       fn payment_path_failed(&mut self, path: &Path, short_channel_id: u64) {
-               self.0.payment_path_failed(path, short_channel_id)
-       }
-       fn payment_path_successful(&mut self, path: &Path) {
-               self.0.payment_path_successful(path)
-       }
-       fn probe_failed(&mut self, path: &Path, short_channel_id: u64) {
-               self.0.probe_failed(path, short_channel_id)
-       }
-       fn probe_successful(&mut self, path: &Path) {
-               self.0.probe_successful(path)
-       }
-}
-#[cfg(c_bindings)]
-impl<'a, T: Score + 'a> Writeable for MultiThreadedScoreLock<'a, T> {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
-               self.0.write(writer)
-       }
+pub struct MultiThreadedLockableScore<T: Score> {
+       score: Mutex<T>,
 }
 
 #[cfg(c_bindings)]
-impl<'a, T: Score + 'a> LockableScore<'a> for MultiThreadedLockableScore<T> {
+impl<'a, T: 'a + Score> LockableScore<'a> for MultiThreadedLockableScore<T> {
+       type Score = T;
        type Locked = MultiThreadedScoreLock<'a, T>;
 
-       fn lock(&'a self) -> MultiThreadedScoreLock<'a, T> {
+       fn lock(&'a self) -> Self::Locked {
                MultiThreadedScoreLock(Mutex::lock(&self.score).unwrap())
        }
 }
@@ -240,7 +219,7 @@ impl<T: Score> Writeable for MultiThreadedLockableScore<T> {
 }
 
 #[cfg(c_bindings)]
-impl<'a, T: Score + 'a> WriteableScore<'a> for MultiThreadedLockableScore<T> {}
+impl<'a, T: 'a + Score> WriteableScore<'a> for MultiThreadedLockableScore<T> {}
 
 #[cfg(c_bindings)]
 impl<T: Score> MultiThreadedLockableScore<T> {
@@ -251,21 +230,34 @@ impl<T: Score> MultiThreadedLockableScore<T> {
 }
 
 #[cfg(c_bindings)]
-/// This is not exported to bindings users
-impl<'a, T: Writeable> Writeable for RefMut<'a, T> {
+/// A locked `MultiThreadedLockableScore`.
+pub struct MultiThreadedScoreLock<'a, T: Score>(MutexGuard<'a, T>);
+
+#[cfg(c_bindings)]
+impl<'a, T: 'a + Score> Writeable for MultiThreadedScoreLock<'a, T> {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
-               T::write(&**self, writer)
+               self.0.write(writer)
        }
 }
 
 #[cfg(c_bindings)]
-/// This is not exported to bindings users
-impl<'a, S: Writeable> Writeable for MutexGuard<'a, S> {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
-               S::write(&**self, writer)
-       }
+impl<'a, T: 'a + Score> DerefMut for MultiThreadedScoreLock<'a, T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.0.deref_mut()
+    }
+}
+
+#[cfg(c_bindings)]
+impl<'a, T: 'a + Score> Deref for MultiThreadedScoreLock<'a, T> {
+       type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        self.0.deref()
+    }
 }
 
+
+
 /// Proposed use of a channel passed as a parameter to [`Score::channel_penalty_msat`].
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub struct ChannelUsage {
@@ -325,7 +317,7 @@ impl ReadableArgs<u64> for FixedPenaltyScorer {
 }
 
 #[cfg(not(feature = "no-std"))]
-type ConfiguredTime = std::time::Instant;
+type ConfiguredTime = crate::util::time::MonotonicTime;
 #[cfg(feature = "no-std")]
 use crate::util::time::Eternity;
 #[cfg(feature = "no-std")]
index da24510866e775742e9721cf0f68bdc0bd6774c2..a71bdae88768c1b7f97da626af9291589205e736 100644 (file)
@@ -36,7 +36,6 @@ use crate::util::transaction_utils;
 use crate::util::crypto::{hkdf_extract_expand_twice, sign, sign_with_aux_rand};
 use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs};
 use crate::chain::transaction::OutPoint;
-#[cfg(anchors)]
 use crate::events::bump_transaction::HTLCDescriptor;
 use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
 use crate::ln::{chan_utils, PaymentPreimage};
@@ -49,6 +48,7 @@ use core::convert::TryInto;
 use core::ops::Deref;
 use core::sync::atomic::{AtomicUsize, Ordering};
 use crate::io::{self, Error};
+use crate::ln::features::ChannelTypeFeatures;
 use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
 use crate::util::atomic_counter::AtomicCounter;
 use crate::util::chacha20::ChaCha20;
@@ -488,7 +488,6 @@ pub trait EcdsaChannelSigner: ChannelSigner {
        fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64,
                per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment,
                secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
-       #[cfg(anchors)]
        /// Computes the signature for a commitment transaction's HTLC output used as an input within
        /// `htlc_tx`, which spends the commitment transaction at index `input`. The signature returned
        /// must be be computed using [`EcdsaSighashType::All`]. Note that this should only be used to
@@ -834,11 +833,12 @@ impl InMemorySigner {
        pub fn get_channel_parameters(&self) -> &ChannelTransactionParameters {
                self.channel_parameters.as_ref().unwrap()
        }
-       /// Returns whether anchors should be used.
+       /// Returns the channel type features of the channel parameters. Should be helpful for
+       /// determining a channel's category, i. e. legacy/anchors/taproot/etc.
        ///
        /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
-       pub fn opt_anchors(&self) -> bool {
-               self.get_channel_parameters().opt_anchors.is_some()
+       pub fn channel_type_features(&self) -> &ChannelTypeFeatures {
+               &self.get_channel_parameters().channel_type_features
        }
        /// Sign the single input of `spend_tx` at index `input_idx`, which spends the output described
        /// by `descriptor`, returning the witness stack for the input.
@@ -963,9 +963,9 @@ impl EcdsaChannelSigner for InMemorySigner {
                let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len());
                for htlc in commitment_tx.htlcs() {
                        let channel_parameters = self.get_channel_parameters();
-                       let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, self.opt_anchors(), channel_parameters.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
-                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys);
-                       let htlc_sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
+                       let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, &channel_parameters.channel_type_features, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.channel_type_features(), &keys);
+                       let htlc_sighashtype = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
                        let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]);
                        let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key);
                        htlc_sigs.push(sign(secp_ctx, &htlc_sighash, &holder_htlc_key));
@@ -1019,27 +1019,23 @@ impl EcdsaChannelSigner for InMemorySigner {
                let witness_script = {
                        let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint);
                        let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint);
-                       chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey)
+                       chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.channel_type_features(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey)
                };
                let mut sighash_parts = sighash::SighashCache::new(justice_tx);
                let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
                return Ok(sign_with_aux_rand(secp_ctx, &sighash, &revocation_key, &self))
        }
 
-       #[cfg(anchors)]
        fn sign_holder_htlc_transaction(
                &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor,
                secp_ctx: &Secp256k1<secp256k1::All>
        ) -> Result<Signature, ()> {
-               let per_commitment_point = self.get_per_commitment_point(
-                       htlc_descriptor.per_commitment_number, &secp_ctx
-               );
-               let witness_script = htlc_descriptor.witness_script(&per_commitment_point, secp_ctx);
+               let witness_script = htlc_descriptor.witness_script(secp_ctx);
                let sighash = &sighash::SighashCache::new(&*htlc_tx).segwit_signature_hash(
                        input, &witness_script, htlc_descriptor.htlc.amount_msat / 1000, EcdsaSighashType::All
                ).map_err(|_| ())?;
                let our_htlc_private_key = chan_utils::derive_private_key(
-                       &secp_ctx, &per_commitment_point, &self.htlc_base_key
+                       &secp_ctx, &htlc_descriptor.per_commitment_point, &self.htlc_base_key
                );
                Ok(sign_with_aux_rand(&secp_ctx, &hash_to_message!(sighash), &our_htlc_private_key, &self))
        }
@@ -1049,7 +1045,7 @@ impl EcdsaChannelSigner for InMemorySigner {
                let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint);
                let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint);
                let htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint);
-               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey);
+               let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.channel_type_features(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey);
                let mut sighash_parts = sighash::SighashCache::new(htlc_tx);
                let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
                Ok(sign_with_aux_rand(secp_ctx, &sighash, &htlc_key, &self))
@@ -1316,7 +1312,7 @@ impl KeysManager {
        ///
        /// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
        /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
-       pub fn sign_spendable_outputs_psbt<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], psbt: &mut PartiallySignedTransaction, secp_ctx: &Secp256k1<C>) -> Result<(), ()> {
+       pub fn sign_spendable_outputs_psbt<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], mut psbt: PartiallySignedTransaction, secp_ctx: &Secp256k1<C>) -> Result<PartiallySignedTransaction, ()> {
                let mut keys_cache: Option<(InMemorySigner, [u8; 32])> = None;
                for outp in descriptors {
                        match outp {
@@ -1378,7 +1374,7 @@ impl KeysManager {
                        }
                }
 
-               Ok(())
+               Ok(psbt)
        }
 
        /// Creates a [`Transaction`] which spends the given descriptors to the given outputs, plus an
@@ -1400,7 +1396,7 @@ impl KeysManager {
        /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
        pub fn spend_spendable_outputs<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: Script, feerate_sat_per_1000_weight: u32, locktime: Option<PackedLockTime>, secp_ctx: &Secp256k1<C>) -> Result<Transaction, ()> {
                let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime)?;
-               self.sign_spendable_outputs_psbt(descriptors, &mut psbt, secp_ctx)?;
+               psbt = self.sign_spendable_outputs_psbt(descriptors, psbt, secp_ctx)?;
 
                let spend_tx = psbt.extract_tx();
 
index 052968377a5e58fe6a4236c0812718a236eaab54..a5bec2c82b8cf00da2a597d3c68026aa7e87152f 100644 (file)
@@ -341,9 +341,9 @@ mod tests {
                field3: Vec<u8>,
        }
        impl_writeable_tlv_based!(TestWriteable, {
-               (1, field1, vec_type),
-               (2, field2, vec_type),
-               (3, field3, vec_type),
+               (1, field1, required_vec),
+               (2, field2, required_vec),
+               (3, field3, required_vec),
        });
 
        #[test]
index 8f1f77b32aadd2f29b76be8fb6efc6290f2cb55a..267774481b4b98df545112c5f7468721ebb90de6 100644 (file)
@@ -149,11 +149,18 @@ pub struct ChannelHandshakeConfig {
        /// Maximum value: 1,000,000, any values larger than 1 Million will be treated as 1 Million (or 100%)
        ///                instead, although channel negotiations will fail in that case.
        pub their_channel_reserve_proportional_millionths: u32,
-       #[cfg(anchors)]
-       /// If set, we attempt to negotiate the `anchors_zero_fee_htlc_tx`option for outbound channels.
+       /// If set, we attempt to negotiate the `anchors_zero_fee_htlc_tx`option for all future
+       /// channels. This feature requires having a reserve of onchain funds readily available to bump
+       /// transactions in the event of a channel force close to avoid the possibility of losing funds.
+       ///
+       /// Note that if you wish accept inbound channels with anchor outputs, you must enable
+       /// [`UserConfig::manually_accept_inbound_channels`] and manually accept them with
+       /// [`ChannelManager::accept_inbound_channel`]. This is done to give you the chance to check
+       /// whether your reserve of onchain funds is enough to cover the fees for all existing and new
+       /// channels featuring anchor outputs in the event of a force close.
        ///
        /// If this option is set, channels may be created that will not be readable by LDK versions
-       /// prior to 0.0.114, causing [`ChannelManager`]'s read method to return a
+       /// prior to 0.0.116, causing [`ChannelManager`]'s read method to return a
        /// [`DecodeError::InvalidValue`].
        ///
        /// Note that setting this to true does *not* prevent us from opening channels with
@@ -167,6 +174,7 @@ pub struct ChannelHandshakeConfig {
        /// Default value: false. This value is likely to change to true in the future.
        ///
        /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+       /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
        /// [`DecodeError::InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
        /// [`SIGHASH_SINGLE + update_fee Considered Harmful`]: https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-September/002796.html
        pub negotiate_anchors_zero_fee_htlc_tx: bool,
@@ -196,7 +204,6 @@ impl Default for ChannelHandshakeConfig {
                        announced_channel: false,
                        commit_upfront_shutdown_pubkey: true,
                        their_channel_reserve_proportional_millionths: 10_000,
-                       #[cfg(anchors)]
                        negotiate_anchors_zero_fee_htlc_tx: false,
                        our_max_accepted_htlcs: 50,
                }
@@ -308,6 +315,55 @@ impl Default for ChannelHandshakeLimits {
        }
 }
 
+/// Options for how to set the max dust HTLC exposure allowed on a channel. See
+/// [`ChannelConfig::max_dust_htlc_exposure`] for details.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum MaxDustHTLCExposure {
+       /// This sets a fixed limit on the total dust exposure in millisatoshis. Setting this too low
+       /// may prevent the sending or receipt of low-value HTLCs on high-traffic nodes, however this
+       /// limit is very important to prevent stealing of large amounts of dust HTLCs by miners
+       /// through [fee griefing
+       /// attacks](https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-May/002714.html).
+       ///
+       /// Note that if the feerate increases significantly, without a manual increase
+       /// to this maximum the channel may be unable to send/receive HTLCs between the maximum dust
+       /// exposure and the new minimum value for HTLCs to be economically viable to claim.
+       FixedLimitMsat(u64),
+       /// This sets a multiplier on the estimated high priority feerate (sats/KW, as obtained from
+       /// [`FeeEstimator`]) to determine the maximum allowed dust exposure. If this variant is used
+       /// then the maximum dust exposure in millisatoshis is calculated as:
+       /// `high_priority_feerate_per_kw * value`. For example, with our default value
+       /// `FeeRateMultiplier(5000)`:
+       ///
+       /// - For the minimum fee rate of 1 sat/vByte (250 sat/KW, although the minimum
+       /// defaults to 253 sats/KW for rounding, see [`FeeEstimator`]), the max dust exposure would
+       /// be 253 * 5000 = 1,265,000 msats.
+       /// - For a fee rate of 30 sat/vByte (7500 sat/KW), the max dust exposure would be
+       /// 7500 * 5000 = 37,500,000 msats.
+       ///
+       /// This allows the maximum dust exposure to automatically scale with fee rate changes.
+       ///
+       /// Note, if you're using a third-party fee estimator, this may leave you more exposed to a
+       /// fee griefing attack, where your fee estimator may purposely overestimate the fee rate,
+       /// causing you to accept more dust HTLCs than you would otherwise.
+       ///
+       /// This variant is primarily meant to serve pre-anchor channels, as HTLC fees being included
+       /// on HTLC outputs means your channel may be subject to more dust exposure in the event of
+       /// increases in fee rate.
+       ///
+       /// # Backwards Compatibility
+       /// This variant only became available in LDK 0.0.116, so if you downgrade to a prior version
+       /// by default this will be set to a [`Self::FixedLimitMsat`] of 5,000,000 msat.
+       ///
+       /// [`FeeEstimator`]: crate::chain::chaininterface::FeeEstimator
+       FeeRateMultiplier(u64),
+}
+
+impl_writeable_tlv_based_enum!(MaxDustHTLCExposure, ;
+       (1, FixedLimitMsat),
+       (3, FeeRateMultiplier),
+);
+
 /// Options which apply on a per-channel basis and may change at runtime or based on negotiation
 /// with our counterparty.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -365,15 +421,15 @@ pub struct ChannelConfig {
        /// channel negotiated throughout the channel open process, along with the fees required to have
        /// a broadcastable HTLC spending transaction. When a channel supports anchor outputs
        /// (specifically the zero fee HTLC transaction variant), this threshold no longer takes into
-       /// account the HTLC transaction fee as it is zero.
+       /// account the HTLC transaction fee as it is zero. Because of this, you may want to set this
+       /// value to a fixed limit for channels using anchor outputs, while the fee rate multiplier
+       /// variant is primarily intended for use with pre-anchor channels.
        ///
-       /// This limit is applied for sent, forwarded, and received HTLCs and limits the total
-       /// exposure across all three types per-channel. Setting this too low may prevent the
-       /// sending or receipt of low-value HTLCs on high-traffic nodes, and this limit is very
-       /// important to prevent stealing of dust HTLCs by miners.
+       /// The selected limit is applied for sent, forwarded, and received HTLCs and limits the total
+       /// exposure across all three types per-channel.
        ///
-       /// Default value: 5_000_000 msat.
-       pub max_dust_htlc_exposure_msat: u64,
+       /// Default value: [`MaxDustHTLCExposure::FeeRateMultiplier`] with a multiplier of 5000.
+       pub max_dust_htlc_exposure: MaxDustHTLCExposure,
        /// The additional fee we're willing to pay to avoid waiting for the counterparty's
        /// `to_self_delay` to reclaim funds.
        ///
@@ -397,6 +453,38 @@ pub struct ChannelConfig {
        /// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
        /// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
        pub force_close_avoidance_max_fee_satoshis: u64,
+       /// If set, allows this channel's counterparty to skim an additional fee off this node's inbound
+       /// HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users.
+       ///
+       /// Usage:
+       /// - The payee will set this option and set its invoice route hints to use [intercept scids]
+       ///   generated by this channel's counterparty.
+       /// - 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
+       ///
+       /// # Note
+       /// It's important for payee wallet software to verify that [`PaymentClaimable::amount_msat`] is
+       /// as-expected if this feature is activated, otherwise they may lose money!
+       /// [`PaymentClaimable::counterparty_skimmed_fee_msat`] provides the fee taken by the
+       /// counterparty.
+       ///
+       /// # Note
+       /// Switching this config flag on may break compatibility with versions of LDK prior to 0.0.116.
+       /// Unsetting this flag between restarts may lead to payment receive failures.
+       ///
+       /// Default value: false.
+       ///
+       /// [intercept scids]: crate::ln::channelmanager::ChannelManager::get_intercept_scid
+       /// [`forward_intercepted_htlc`]: crate::ln::channelmanager::ChannelManager::forward_intercepted_htlc
+       /// [`HTLCIntercepted`]: crate::events::Event::HTLCIntercepted
+       /// [`HTLCIntercepted::expected_outbound_amount_msat`]: crate::events::Event::HTLCIntercepted::expected_outbound_amount_msat
+       /// [`PaymentClaimable::amount_msat`]: crate::events::Event::PaymentClaimable::amount_msat
+       /// [`PaymentClaimable::counterparty_skimmed_fee_msat`]: crate::events::Event::PaymentClaimable::counterparty_skimmed_fee_msat
+       //  TODO: link to bLIP when it's merged
+       pub accept_underpaying_htlcs: bool,
 }
 
 impl ChannelConfig {
@@ -412,7 +500,7 @@ impl ChannelConfig {
                        self.cltv_expiry_delta = cltv_expiry_delta;
                }
                if let Some(max_dust_htlc_exposure_msat) = update.max_dust_htlc_exposure_msat {
-                       self.max_dust_htlc_exposure_msat = max_dust_htlc_exposure_msat;
+                       self.max_dust_htlc_exposure = max_dust_htlc_exposure_msat;
                }
                if let Some(force_close_avoidance_max_fee_satoshis) = update.force_close_avoidance_max_fee_satoshis {
                        self.force_close_avoidance_max_fee_satoshis = force_close_avoidance_max_fee_satoshis;
@@ -427,22 +515,67 @@ impl Default for ChannelConfig {
                        forwarding_fee_proportional_millionths: 0,
                        forwarding_fee_base_msat: 1000,
                        cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
-                       max_dust_htlc_exposure_msat: 5_000_000,
+                       max_dust_htlc_exposure: MaxDustHTLCExposure::FeeRateMultiplier(5000),
                        force_close_avoidance_max_fee_satoshis: 1000,
+                       accept_underpaying_htlcs: false,
                }
        }
 }
 
-impl_writeable_tlv_based!(ChannelConfig, {
-       (0, forwarding_fee_proportional_millionths, required),
-       (2, forwarding_fee_base_msat, required),
-       (4, cltv_expiry_delta, required),
-       (6, max_dust_htlc_exposure_msat, required),
-       // ChannelConfig serialized this field with a required type of 8 prior to the introduction of
-       // LegacyChannelConfig. To make sure that serialization is not compatible with this one, we use
-       // the next required type of 10, which if seen by the old serialization will always fail.
-       (10, force_close_avoidance_max_fee_satoshis, required),
-});
+impl crate::util::ser::Writeable for ChannelConfig {
+       fn write<W: crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), crate::io::Error> {
+               let max_dust_htlc_exposure_msat_fixed_limit = match self.max_dust_htlc_exposure {
+                       MaxDustHTLCExposure::FixedLimitMsat(limit) => limit,
+                       MaxDustHTLCExposure::FeeRateMultiplier(_) => 5_000_000,
+               };
+               write_tlv_fields!(writer, {
+                       (0, self.forwarding_fee_proportional_millionths, required),
+                       (1, self.accept_underpaying_htlcs, (default_value, false)),
+                       (2, self.forwarding_fee_base_msat, required),
+                       (3, self.max_dust_htlc_exposure, required),
+                       (4, self.cltv_expiry_delta, required),
+                       (6, max_dust_htlc_exposure_msat_fixed_limit, required),
+                       // ChannelConfig serialized this field with a required type of 8 prior to the introduction of
+                       // LegacyChannelConfig. To make sure that serialization is not compatible with this one, we use
+                       // the next required type of 10, which if seen by the old serialization will always fail.
+                       (10, self.force_close_avoidance_max_fee_satoshis, required),
+               });
+               Ok(())
+       }
+}
+
+impl crate::util::ser::Readable for ChannelConfig {
+       fn read<R: crate::io::Read>(reader: &mut R) -> Result<Self, crate::ln::msgs::DecodeError> {
+               let mut forwarding_fee_proportional_millionths = 0;
+               let mut accept_underpaying_htlcs = false;
+               let mut forwarding_fee_base_msat = 1000;
+               let mut cltv_expiry_delta = 6 * 12;
+               let mut max_dust_htlc_exposure_msat = None;
+               let mut max_dust_htlc_exposure_enum = None;
+               let mut force_close_avoidance_max_fee_satoshis = 1000;
+               read_tlv_fields!(reader, {
+                       (0, forwarding_fee_proportional_millionths, required),
+                       (1, accept_underpaying_htlcs, (default_value, false)),
+                       (2, forwarding_fee_base_msat, required),
+                       (3, max_dust_htlc_exposure_enum, option),
+                       (4, cltv_expiry_delta, required),
+                       // Has always been written, but became optionally read in 0.0.116
+                       (6, max_dust_htlc_exposure_msat, option),
+                       (10, force_close_avoidance_max_fee_satoshis, required),
+               });
+               let max_dust_htlc_fixed_limit = max_dust_htlc_exposure_msat.unwrap_or(5_000_000);
+               let max_dust_htlc_exposure_msat = max_dust_htlc_exposure_enum
+                       .unwrap_or(MaxDustHTLCExposure::FixedLimitMsat(max_dust_htlc_fixed_limit));
+               Ok(Self {
+                       forwarding_fee_proportional_millionths,
+                       accept_underpaying_htlcs,
+                       forwarding_fee_base_msat,
+                       cltv_expiry_delta,
+                       max_dust_htlc_exposure: max_dust_htlc_exposure_msat,
+                       force_close_avoidance_max_fee_satoshis,
+               })
+       }
+}
 
 /// A parallel struct to [`ChannelConfig`] to define partial updates.
 #[allow(missing_docs)]
@@ -450,7 +583,7 @@ pub struct ChannelConfigUpdate {
        pub forwarding_fee_proportional_millionths: Option<u32>,
        pub forwarding_fee_base_msat: Option<u32>,
        pub cltv_expiry_delta: Option<u16>,
-       pub max_dust_htlc_exposure_msat: Option<u64>,
+       pub max_dust_htlc_exposure_msat: Option<MaxDustHTLCExposure>,
        pub force_close_avoidance_max_fee_satoshis: Option<u64>,
 }
 
@@ -472,7 +605,7 @@ impl From<ChannelConfig> for ChannelConfigUpdate {
                        forwarding_fee_proportional_millionths: Some(config.forwarding_fee_proportional_millionths),
                        forwarding_fee_base_msat: Some(config.forwarding_fee_base_msat),
                        cltv_expiry_delta: Some(config.cltv_expiry_delta),
-                       max_dust_htlc_exposure_msat: Some(config.max_dust_htlc_exposure_msat),
+                       max_dust_htlc_exposure_msat: Some(config.max_dust_htlc_exposure),
                        force_close_avoidance_max_fee_satoshis: Some(config.force_close_avoidance_max_fee_satoshis),
                }
        }
@@ -505,12 +638,17 @@ impl Default for LegacyChannelConfig {
 
 impl crate::util::ser::Writeable for LegacyChannelConfig {
        fn write<W: crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), crate::io::Error> {
+               let max_dust_htlc_exposure_msat_fixed_limit = match self.options.max_dust_htlc_exposure {
+                       MaxDustHTLCExposure::FixedLimitMsat(limit) => limit,
+                       MaxDustHTLCExposure::FeeRateMultiplier(_) => 5_000_000,
+               };
                write_tlv_fields!(writer, {
                        (0, self.options.forwarding_fee_proportional_millionths, required),
-                       (1, self.options.max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
+                       (1, max_dust_htlc_exposure_msat_fixed_limit, required),
                        (2, self.options.cltv_expiry_delta, required),
                        (3, self.options.force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
                        (4, self.announced_channel, required),
+                       (5, self.options.max_dust_htlc_exposure, required),
                        (6, self.commit_upfront_shutdown_pubkey, required),
                        (8, self.options.forwarding_fee_base_msat, required),
                });
@@ -521,28 +659,36 @@ impl crate::util::ser::Writeable for LegacyChannelConfig {
 impl crate::util::ser::Readable for LegacyChannelConfig {
        fn read<R: crate::io::Read>(reader: &mut R) -> Result<Self, crate::ln::msgs::DecodeError> {
                let mut forwarding_fee_proportional_millionths = 0;
-               let mut max_dust_htlc_exposure_msat = 5_000_000;
+               let mut max_dust_htlc_exposure_msat_fixed_limit = None;
                let mut cltv_expiry_delta = 0;
                let mut force_close_avoidance_max_fee_satoshis = 1000;
                let mut announced_channel = false;
                let mut commit_upfront_shutdown_pubkey = false;
                let mut forwarding_fee_base_msat = 0;
+               let mut max_dust_htlc_exposure_enum = None;
                read_tlv_fields!(reader, {
                        (0, forwarding_fee_proportional_millionths, required),
-                       (1, max_dust_htlc_exposure_msat, (default_value, 5_000_000u64)),
+                       // Has always been written, but became optionally read in 0.0.116
+                       (1, max_dust_htlc_exposure_msat_fixed_limit, option),
                        (2, cltv_expiry_delta, required),
                        (3, force_close_avoidance_max_fee_satoshis, (default_value, 1000u64)),
                        (4, announced_channel, required),
+                       (5, max_dust_htlc_exposure_enum, option),
                        (6, commit_upfront_shutdown_pubkey, required),
                        (8, forwarding_fee_base_msat, required),
                });
+               let max_dust_htlc_exposure_msat_fixed_limit =
+                       max_dust_htlc_exposure_msat_fixed_limit.unwrap_or(5_000_000);
+               let max_dust_htlc_exposure_msat = max_dust_htlc_exposure_enum
+                       .unwrap_or(MaxDustHTLCExposure::FixedLimitMsat(max_dust_htlc_exposure_msat_fixed_limit));
                Ok(Self {
                        options: ChannelConfig {
                                forwarding_fee_proportional_millionths,
-                               max_dust_htlc_exposure_msat,
+                               max_dust_htlc_exposure: max_dust_htlc_exposure_msat,
                                cltv_expiry_delta,
                                force_close_avoidance_max_fee_satoshis,
                                forwarding_fee_base_msat,
+                               accept_underpaying_htlcs: false,
                        },
                        announced_channel,
                        commit_upfront_shutdown_pubkey,
index b96a02afe4b12613cd5f74de774cb87068d19732..df0f13bc3adc7d142165e622caec90da62bdc48f 100644 (file)
@@ -23,10 +23,10 @@ use bitcoin::util::sighash;
 use bitcoin::secp256k1;
 use bitcoin::secp256k1::{SecretKey, PublicKey};
 use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
-#[cfg(anchors)]
 use crate::events::bump_transaction::HTLCDescriptor;
 use crate::util::ser::{Writeable, Writer};
 use crate::io::Error;
+use crate::ln::features::ChannelTypeFeatures;
 
 /// Initial value for revoked commitment downward counter
 pub const INITIAL_REVOKED_COMMITMENT_NUMBER: u64 = 1 << 48;
@@ -88,7 +88,7 @@ impl EnforcingSigner {
                }
        }
 
-       pub fn opt_anchors(&self) -> bool { self.inner.opt_anchors() }
+       pub fn channel_type_features(&self) -> &ChannelTypeFeatures { self.inner.channel_type_features() }
 
        #[cfg(test)]
        pub fn get_enforcement_state(&self) -> MutexGuard<EnforcementState> {
@@ -172,11 +172,11 @@ impl EcdsaChannelSigner for EnforcingSigner {
                for (this_htlc, sig) in trusted_tx.htlcs().iter().zip(&commitment_tx.counterparty_htlc_sigs) {
                        assert!(this_htlc.transaction_output_index.is_some());
                        let keys = trusted_tx.keys();
-                       let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, trusted_tx.feerate_per_kw(), holder_csv, &this_htlc, self.opt_anchors(), false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+                       let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, trusted_tx.feerate_per_kw(), holder_csv, &this_htlc, self.channel_type_features(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
-                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&this_htlc, self.opt_anchors(), &keys);
+                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&this_htlc, self.channel_type_features(), &keys);
 
-                       let sighash_type = if self.opt_anchors() {
+                       let sighash_type = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
                                EcdsaSighashType::SinglePlusAnyoneCanPay
                        } else {
                                EcdsaSighashType::All
@@ -205,14 +205,12 @@ impl EcdsaChannelSigner for EnforcingSigner {
                Ok(self.inner.sign_justice_revoked_htlc(justice_tx, input, amount, per_commitment_key, htlc, secp_ctx).unwrap())
        }
 
-       #[cfg(anchors)]
        fn sign_holder_htlc_transaction(
                &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor,
                secp_ctx: &Secp256k1<secp256k1::All>
        ) -> Result<Signature, ()> {
-               let per_commitment_point = self.get_per_commitment_point(htlc_descriptor.per_commitment_number, secp_ctx);
                assert_eq!(htlc_tx.input[input], htlc_descriptor.unsigned_tx_input());
-               assert_eq!(htlc_tx.output[input], htlc_descriptor.tx_output(&per_commitment_point, secp_ctx));
+               assert_eq!(htlc_tx.output[input], htlc_descriptor.tx_output(secp_ctx));
                Ok(self.inner.sign_holder_htlc_transaction(htlc_tx, input, htlc_descriptor, secp_ctx).unwrap())
        }
 
index aac83f42a3c2f82a5520fc380f4006ca345288e2..dbca9b785e85dfbaf3c68253e7e47b91225c6bdc 100644 (file)
@@ -169,6 +169,26 @@ impl<'a> core::fmt::Display for DebugBytes<'a> {
        }
 }
 
+/// Wrapper for logging `Iterator`s.
+///
+/// This is not exported to bindings users as fmt can't be used in C
+#[doc(hidden)]
+pub struct DebugIter<T: fmt::Display, I: core::iter::Iterator<Item = T> + Clone>(pub I);
+impl<T: fmt::Display, I: core::iter::Iterator<Item = T> + Clone> fmt::Display for DebugIter<T, I> {
+       fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+               write!(f, "[")?;
+               let mut iter = self.0.clone();
+               if let Some(item) = iter.next() {
+                       write!(f, "{}", item)?;
+               }
+               while let Some(item) = iter.next() {
+                       write!(f, ", {}", item)?;
+               }
+               write!(f, "]")?;
+               Ok(())
+       }
+}
+
 #[cfg(test)]
 mod tests {
        use crate::util::logger::{Logger, Level};
index 8742e8e84d0bf27670fb0cb71af3c372e089b9e3..e79980370342ff01920fe5a37b4423719a228ac7 100644 (file)
@@ -17,6 +17,12 @@ use crate::routing::router::Route;
 use crate::ln::chan_utils::HTLCClaim;
 use crate::util::logger::DebugBytes;
 
+macro_rules! log_iter {
+       ($obj: expr) => {
+               $crate::util::logger::DebugIter($obj)
+       }
+}
+
 /// Logs a pubkey in hex format.
 #[macro_export]
 macro_rules! log_pubkey {
index 3dbf4f89634b9b2c7330f774b8f0bd624414dd2c..dd9d2744e1c7927ba82bab9244a355020b5d9660 100644 (file)
@@ -50,11 +50,11 @@ pub(crate) mod crypto;
 pub mod logger;
 pub mod config;
 
-#[cfg(any(test, fuzzing, feature = "_test_utils"))]
+#[cfg(any(test, feature = "_test_utils"))]
 pub mod test_utils;
 
 /// impls of traits that add exra enforcement on the way they're called. Useful for detecting state
 /// machine errors and used in fuzz targets and tests.
-#[cfg(any(test, fuzzing, feature = "_test_utils"))]
+#[cfg(any(test, feature = "_test_utils"))]
 pub mod enforcing_trait_impls;
 
index fb0d0ad8e44e9eb40d203c50b4cf2efaa8af88a3..1eb5e7424c82343d0bb88aef7df632dc408563f0 100644 (file)
@@ -37,6 +37,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
 use bitcoin::hash_types::{Txid, BlockHash};
 use core::marker::Sized;
 use core::time::Duration;
+use crate::chain::ClaimId;
 use crate::ln::msgs::DecodeError;
 #[cfg(taproot)]
 use crate::ln::msgs::PartialSignatureWithNonce;
@@ -357,6 +358,7 @@ impl Readable for U48 {
 /// encoded in several different ways, which we must check for at deserialization-time. Thus, if
 /// you're looking for an example of a variable-length integer to use for your own project, move
 /// along, this is a rather poor design.
+#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
 pub struct BigSize(pub u64);
 impl Writeable for BigSize {
        #[inline]
@@ -847,6 +849,7 @@ impl Readable for Vec<u8> {
 }
 
 impl_for_vec!(ecdsa::Signature);
+impl_for_vec!(crate::chain::channelmonitor::ChannelMonitorUpdate);
 impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction);
 impl_for_vec!((A, B), A, B);
 impl_writeable_for_vec!(&crate::routing::router::BlindedTail);
@@ -1349,6 +1352,7 @@ impl Readable for Hostname {
        }
 }
 
+/// This is not exported to bindings users as `Duration`s are simply mapped as ints.
 impl Writeable for Duration {
        #[inline]
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
@@ -1356,6 +1360,7 @@ impl Writeable for Duration {
                self.subsec_nanos().write(w)
        }
 }
+/// This is not exported to bindings users as `Duration`s are simply mapped as ints.
 impl Readable for Duration {
        #[inline]
        fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
@@ -1409,6 +1414,18 @@ impl Readable for TransactionU16LenLimited {
        }
 }
 
+impl Writeable for ClaimId {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               self.0.write(writer)
+       }
+}
+
+impl Readable for ClaimId {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               Ok(Self(Readable::read(reader)?))
+       }
+}
+
 #[cfg(test)]
 mod tests {
        use core::convert::TryFrom;
index 8ffcec6d17530a7c5674b93e227730da6c097260..1744b923d5e92589eee665c5a1ef1e263b6cfd8b 100644 (file)
 //! [`Readable`]: crate::util::ser::Readable
 //! [`Writeable`]: crate::util::ser::Writeable
 
+// There are quite a few TLV serialization "types" which behave differently. We currently only
+// publicly document the `optional` and `required` types, not supporting anything else publicly and
+// changing them at will.
+//
+// Some of the other types include:
+//  * (default_value, $default) - reads optionally, reading $default if no TLV is present
+//  * (static_value, $value) - ignores any TLVs, always using $value
+//  * required_vec - reads into a Vec without a length prefix, failing if no TLV is present.
+//  * optional_vec - reads into an Option<Vec> without a length prefix, continuing if no TLV is
+//                   present. Writes from a Vec directly, only if any elements are present. Note
+//                   that the struct deserialization macros return a Vec, not an Option.
+//  * upgradable_option - reads via MaybeReadable.
+//  * upgradable_required - reads via MaybeReadable, requiring a TLV be present but may return None
+//                          if MaybeReadable::read() returns None.
+
 /// Implements serialization for a single TLV record.
 /// This is exported for use by other exported macros, do not use directly.
 #[doc(hidden)]
@@ -29,7 +44,7 @@ macro_rules! _encode_tlv {
                BigSize($field.serialized_length() as u64).write($stream)?;
                $field.write($stream)?;
        };
-       ($stream: expr, $type: expr, $field: expr, vec_type) => {
+       ($stream: expr, $type: expr, $field: expr, required_vec) => {
                $crate::_encode_tlv!($stream, $type, $crate::util::ser::WithoutLength(&$field), required);
        };
        ($stream: expr, $optional_type: expr, $optional_field: expr, option) => {
@@ -41,7 +56,7 @@ macro_rules! _encode_tlv {
        };
        ($stream: expr, $type: expr, $field: expr, optional_vec) => {
                if !$field.is_empty() {
-                       $crate::_encode_tlv!($stream, $type, $field, vec_type);
+                       $crate::_encode_tlv!($stream, $type, $field, required_vec);
                }
        };
        ($stream: expr, $type: expr, $field: expr, upgradable_required) => {
@@ -159,7 +174,7 @@ macro_rules! _get_varint_length_prefixed_tlv_length {
                BigSize(field_len as u64).write(&mut $len).expect("No in-memory data may fail to serialize");
                $len.0 += field_len;
        };
-       ($len: expr, $type: expr, $field: expr, vec_type) => {
+       ($len: expr, $type: expr, $field: expr, required_vec) => {
                $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $crate::util::ser::WithoutLength(&$field), required);
        };
        ($len: expr, $optional_type: expr, $optional_field: expr, option) => {
@@ -172,7 +187,7 @@ macro_rules! _get_varint_length_prefixed_tlv_length {
        };
        ($len: expr, $type: expr, $field: expr, optional_vec) => {
                if !$field.is_empty() {
-                       $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, vec_type);
+                       $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required_vec);
                }
        };
        ($len: expr, $type: expr, $field: expr, (option: $trait: ident $(, $read_arg: expr)?)) => {
@@ -236,8 +251,8 @@ macro_rules! _check_decoded_tlv_order {
        ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, option) => {{
                // no-op
        }};
-       ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, vec_type) => {{
-               // no-op
+       ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, required_vec) => {{
+               $crate::_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required);
        }};
        ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, optional_vec) => {{
                // no-op
@@ -281,8 +296,8 @@ macro_rules! _check_missing_tlv {
        ($last_seen_type: expr, $type: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
                $crate::_check_missing_tlv!($last_seen_type, $type, $field, required);
        }};
-       ($last_seen_type: expr, $type: expr, $field: ident, vec_type) => {{
-               // no-op
+       ($last_seen_type: expr, $type: expr, $field: ident, required_vec) => {{
+               $crate::_check_missing_tlv!($last_seen_type, $type, $field, required);
        }};
        ($last_seen_type: expr, $type: expr, $field: ident, option) => {{
                // no-op
@@ -320,15 +335,16 @@ macro_rules! _decode_tlv {
        ($reader: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
                $field = $trait::read(&mut $reader $(, $read_arg)*)?;
        }};
-       ($reader: expr, $field: ident, vec_type) => {{
+       ($reader: expr, $field: ident, required_vec) => {{
                let f: $crate::util::ser::WithoutLength<Vec<_>> = $crate::util::ser::Readable::read(&mut $reader)?;
-               $field = Some(f.0);
+               $field = f.0;
        }};
        ($reader: expr, $field: ident, option) => {{
                $field = Some($crate::util::ser::Readable::read(&mut $reader)?);
        }};
        ($reader: expr, $field: ident, optional_vec) => {{
-               $crate::_decode_tlv!($reader, $field, vec_type);
+               let f: $crate::util::ser::WithoutLength<Vec<_>> = $crate::util::ser::Readable::read(&mut $reader)?;
+               $field = Some(f.0);
        }};
        // `upgradable_required` indicates we're reading a required TLV that may have been upgraded
        // without backwards compat. We'll error if the field is missing, and return `Ok(None)` if the
@@ -694,8 +710,8 @@ macro_rules! _init_tlv_based_struct_field {
        ($field: ident, required) => {
                $field.0.unwrap()
        };
-       ($field: ident, vec_type) => {
-               $field.unwrap()
+       ($field: ident, required_vec) => {
+               $field
        };
        ($field: ident, optional_vec) => {
                $field.unwrap()
@@ -720,8 +736,8 @@ macro_rules! _init_tlv_field_var {
        ($field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {
                $crate::_init_tlv_field_var!($field, required);
        };
-       ($field: ident, vec_type) => {
-               let mut $field = Some(Vec::new());
+       ($field: ident, required_vec) => {
+               let mut $field = Vec::new();
        };
        ($field: ident, option) => {
                let mut $field = None;
@@ -981,7 +997,7 @@ macro_rules! impl_writeable_tlv_based_enum {
                                                f()
                                        }),*
                                        $($tuple_variant_id => {
-                                               Ok($st::$tuple_variant_name(Readable::read(reader)?))
+                                               Ok($st::$tuple_variant_name($crate::util::ser::Readable::read(reader)?))
                                        }),*
                                        _ => {
                                                Err($crate::ln::msgs::DecodeError::UnknownRequiredFeature)
index fe61e9c7214e25a8ad901f5242aea701e03950fe..65c0483a59c9906e36b4a42587698362bd77702c 100644 (file)
@@ -18,6 +18,7 @@ use crate::chain::channelmonitor::MonitorEvent;
 use crate::chain::transaction::OutPoint;
 use crate::sign;
 use crate::events;
+use crate::events::bump_transaction::{WalletSource, Utxo};
 use crate::ln::channelmanager;
 use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
 use crate::ln::{msgs, wire};
@@ -32,6 +33,7 @@ use crate::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
 use crate::util::logger::{Logger, Level, Record};
 use crate::util::ser::{Readable, ReadableArgs, Writer, Writeable};
 
+use bitcoin::EcdsaSighashType;
 use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::blockdata::transaction::{Transaction, TxOut};
@@ -40,16 +42,19 @@ use bitcoin::blockdata::opcodes;
 use bitcoin::blockdata::block::Block;
 use bitcoin::network::constants::Network;
 use bitcoin::hash_types::{BlockHash, Txid};
+use bitcoin::util::sighash::SighashCache;
 
 use bitcoin::secp256k1::{SecretKey, PublicKey, Secp256k1, ecdsa::Signature, Scalar};
 use bitcoin::secp256k1::ecdh::SharedSecret;
 use bitcoin::secp256k1::ecdsa::RecoverableSignature;
 
+#[cfg(any(test, feature = "_test_utils"))]
 use regex;
 
 use crate::io;
 use crate::prelude::*;
 use core::cell::RefCell;
+use core::ops::DerefMut;
 use core::time::Duration;
 use crate::sync::{Mutex, Arc};
 use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
@@ -107,13 +112,13 @@ impl<'a> TestRouter<'a> {
 impl<'a> Router for TestRouter<'a> {
        fn find_route(
                &self, payer: &PublicKey, params: &RouteParameters, first_hops: Option<&[&channelmanager::ChannelDetails]>,
-               inflight_htlcs: &InFlightHtlcs
+               inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, msgs::LightningError> {
                if let Some((find_route_query, find_route_res)) = self.next_routes.lock().unwrap().pop_front() {
                        assert_eq!(find_route_query, *params);
                        if let Ok(ref route) = find_route_res {
-                               let locked_scorer = self.scorer.lock().unwrap();
-                               let scorer = ScorerAccountingForInFlightHtlcs::new(locked_scorer, inflight_htlcs);
+                               let mut binding = self.scorer.lock().unwrap();
+                               let scorer = ScorerAccountingForInFlightHtlcs::new(binding.deref_mut(), &inflight_htlcs);
                                for path in &route.paths {
                                        let mut aggregate_msat = 0u64;
                                        for (idx, hop) in path.hops.iter().rev().enumerate() {
@@ -138,10 +143,9 @@ impl<'a> Router for TestRouter<'a> {
                        return find_route_res;
                }
                let logger = TestLogger::new();
-               let scorer = self.scorer.lock().unwrap();
                find_route(
                        payer, params, &self.network_graph, first_hops, &logger,
-                       &ScorerAccountingForInFlightHtlcs::new(scorer, &inflight_htlcs), &(),
+                       &ScorerAccountingForInFlightHtlcs::new(self.scorer.lock().unwrap().deref_mut(), &inflight_htlcs), &(),
                        &[42; 32]
                )
        }
@@ -738,6 +742,7 @@ impl TestLogger {
        /// 1. belong to the specified module and
        /// 2. match the given regex pattern.
        /// Assert that the number of occurrences equals the given `count`
+       #[cfg(any(test, feature = "_test_utils"))]
        pub fn assert_log_regex(&self, module: &str, pattern: regex::Regex, count: usize) {
                let log_entries = self.lines.lock().unwrap();
                let l: usize = log_entries.iter().filter(|&(&(ref m, ref l), _c)| {
@@ -1065,3 +1070,65 @@ impl Drop for TestScorer {
                }
        }
 }
+
+pub struct TestWalletSource {
+       secret_key: SecretKey,
+       utxos: RefCell<Vec<Utxo>>,
+       secp: Secp256k1<bitcoin::secp256k1::All>,
+}
+
+impl TestWalletSource {
+       pub fn new(secret_key: SecretKey) -> Self {
+               Self {
+                       secret_key,
+                       utxos: RefCell::new(Vec::new()),
+                       secp: Secp256k1::new(),
+               }
+       }
+
+       pub fn add_utxo(&self, outpoint: bitcoin::OutPoint, value: u64) -> TxOut {
+               let public_key = bitcoin::PublicKey::new(self.secret_key.public_key(&self.secp));
+               let utxo = Utxo::new_p2pkh(outpoint, value, &public_key.pubkey_hash());
+               self.utxos.borrow_mut().push(utxo.clone());
+               utxo.output
+       }
+
+       pub fn add_custom_utxo(&self, utxo: Utxo) -> TxOut {
+               let output = utxo.output.clone();
+               self.utxos.borrow_mut().push(utxo);
+               output
+       }
+
+       pub fn remove_utxo(&self, outpoint: bitcoin::OutPoint) {
+               self.utxos.borrow_mut().retain(|utxo| utxo.outpoint != outpoint);
+       }
+}
+
+impl WalletSource for TestWalletSource {
+       fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()> {
+               Ok(self.utxos.borrow().clone())
+       }
+
+       fn get_change_script(&self) -> Result<Script, ()> {
+               let public_key = bitcoin::PublicKey::new(self.secret_key.public_key(&self.secp));
+               Ok(Script::new_p2pkh(&public_key.pubkey_hash()))
+       }
+
+       fn sign_tx(&self, mut tx: Transaction) -> Result<Transaction, ()> {
+               let utxos = self.utxos.borrow();
+               for i in 0..tx.input.len() {
+                       if let Some(utxo) = utxos.iter().find(|utxo| utxo.outpoint == tx.input[i].previous_output) {
+                               let sighash = SighashCache::new(&tx)
+                                       .legacy_signature_hash(i, &utxo.output.script_pubkey, EcdsaSighashType::All as u32)
+                                       .map_err(|_| ())?;
+                               let sig = self.secp.sign_ecdsa(&sighash.as_hash().into(), &self.secret_key);
+                               let bitcoin_sig = bitcoin::EcdsaSig { sig, hash_ty: EcdsaSighashType::All }.to_vec();
+                               tx.input[i].script_sig = Builder::new()
+                                       .push_slice(&bitcoin_sig)
+                                       .push_slice(&self.secret_key.public_key(&self.secp).serialize())
+                                       .into_script();
+                       }
+               }
+               Ok(tx)
+       }
+}
index f450dc2c3015ae4da00faa2d609d01542753b85d..0d969e7470952625d8db04965220c25df589f30f 100644 (file)
@@ -58,10 +58,20 @@ impl Sub<Duration> for Eternity {
        }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[cfg(not(feature = "no-std"))]
+pub struct MonotonicTime(std::time::Instant);
+
+/// The amount of time to shift `Instant` forward to prevent overflow when subtracting a `Duration`
+/// from `Instant::now` on some operating systems (e.g., iOS representing `Instance` as `u64`).
+#[cfg(not(feature = "no-std"))]
+const SHIFT: Duration = Duration::from_secs(10 * 365 * 24 * 60 * 60); // 10 years.
+
 #[cfg(not(feature = "no-std"))]
-impl Time for std::time::Instant {
+impl Time for MonotonicTime {
        fn now() -> Self {
-               std::time::Instant::now()
+               let instant = std::time::Instant::now().checked_add(SHIFT).expect("Overflow on MonotonicTime instantiation");
+               Self(instant)
        }
 
        fn duration_since(&self, earlier: Self) -> Duration {
@@ -70,15 +80,26 @@ impl Time for std::time::Instant {
                // clocks" that go backwards in practice (likely relatively ancient kernels/etc). Thus, we
                // manually check for time going backwards here and return a duration of zero in that case.
                let now = Self::now();
-               if now > earlier { now - earlier } else { Duration::from_secs(0) }
+               if now.0 > earlier.0 { now.0 - earlier.0 } else { Duration::from_secs(0) }
        }
 
        fn duration_since_epoch() -> Duration {
                use std::time::SystemTime;
                SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
        }
+
        fn elapsed(&self) -> Duration {
-               std::time::Instant::elapsed(self)
+               Self::now().0 - self.0
+       }
+}
+
+#[cfg(not(feature = "no-std"))]
+impl Sub<Duration> for MonotonicTime {
+       type Output = Self;
+
+       fn sub(self, other: Duration) -> Self {
+               let instant = self.0.checked_sub(other).expect("MonotonicTime is not supposed to go backward futher than 10 years");
+               Self(instant)
        }
 }
 
@@ -154,4 +175,15 @@ pub mod tests {
                assert_eq!(now.elapsed(), Duration::from_secs(0));
                assert_eq!(later - elapsed, now);
        }
+
+       #[test]
+       #[cfg(not(feature = "no-std"))]
+       fn monotonic_time_subtracts() {
+               let now = super::MonotonicTime::now();
+               assert!(now.elapsed() < Duration::from_secs(10));
+
+               let ten_years = Duration::from_secs(10 * 365 * 24 * 60 * 60);
+               let past = now - ten_years;
+               assert!(past.elapsed() >= ten_years);
+       }
 }
diff --git a/msrv-no-dev-deps-check/Cargo.toml b/msrv-no-dev-deps-check/Cargo.toml
new file mode 100644 (file)
index 0000000..d733607
--- /dev/null
@@ -0,0 +1,13 @@
+[package]
+name = "msrv-check"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+lightning = { path = "../lightning" }
+lightning-block-sync = { path = "../lightning-block-sync", features = [ "rest-client", "rpc-client" ] }
+lightning-invoice = { path = "../lightning-invoice" }
+lightning-net-tokio = { path = "../lightning-net-tokio" }
+lightning-persister = { path = "../lightning-persister" }
+lightning-background-processor = { path = "../lightning-background-processor", features = ["futures"] }
+lightning-rapid-gossip-sync = { path = "../lightning-rapid-gossip-sync" }
diff --git a/msrv-no-dev-deps-check/src/lib.rs b/msrv-no-dev-deps-check/src/lib.rs
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pending_changelog/big-om-error.txt b/pending_changelog/big-om-error.txt
deleted file mode 100644 (file)
index 6f2ce89..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-## Bug Fixes
-
-* Fixed sending large onion messages, which previously would result in an HMAC error on the second
-       hop (#2277).
diff --git a/pending_changelog/blinded_pay_param_compat.txt b/pending_changelog/blinded_pay_param_compat.txt
deleted file mode 100644 (file)
index 8e91e00..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-## Backwards Compatibility
-
-* `PaymentParameters` written with blinded path info using 0.0.115 will not be readable in 0.0.116