Merge pull request #2142 from alecchendev/2023-03-expose-fail-reason-in-payment-failure
authorvalentinewallace <valentinewallace@users.noreply.github.com>
Tue, 11 Apr 2023 21:26:16 +0000 (17:26 -0400)
committerGitHub <noreply@github.com>
Tue, 11 Apr 2023 21:26:16 +0000 (17:26 -0400)
Expose a failure reason in `PaymentFailed`

lightning-background-processor/src/lib.rs
lightning-invoice/Cargo.toml
lightning-invoice/src/de.rs
lightning-invoice/src/lib.rs
lightning-invoice/src/ser.rs
lightning-invoice/tests/ser_de.rs
lightning-rapid-gossip-sync/src/lib.rs
lightning-rapid-gossip-sync/src/processing.rs
lightning/src/ln/channelmanager.rs

index 21e9d419471ee6cc5fb619a0480642600096513c..7d705bdcc3ae05630c53f1806e30b95d337ac919 100644 (file)
@@ -1429,8 +1429,8 @@ mod tests {
                        ];
                        $nodes[0].rapid_gossip_sync.update_network_graph_no_std(&initialization_input[..], Some(1642291930)).unwrap();
 
-                       // this should have added two channels
-                       assert_eq!($nodes[0].network_graph.read_only().channels().len(), 3);
+                       // this should have added two channels and pruned the previous one.
+                       assert_eq!($nodes[0].network_graph.read_only().channels().len(), 2);
 
                        $receive.expect("Network graph not pruned within deadline");
 
index a3fb66a8f91425fc8459a38144023cfb8e9fe84e..9ab9bd5482b6eacd359140750bb1ebdf363231ce 100644 (file)
@@ -27,6 +27,7 @@ num-traits = { version = "0.2.8", default-features = false }
 bitcoin_hashes = { version = "0.11", default-features = false }
 hashbrown = { version = "0.8", optional = true }
 serde = { version = "1.0.118", optional = true }
+bitcoin = { version = "0.29.0", default-features = false }
 
 [dev-dependencies]
 lightning = { version = "0.0.114", path = "../lightning", default-features = false, features = ["_test_utils"] }
index ab9fd9cb2bc21446920360759feefec87291f774..925d7265c553526d993f94b29354adcac1db9ac1 100644 (file)
@@ -1,5 +1,6 @@
 #[cfg(feature = "std")]
 use std::error;
+use core::convert::TryFrom;
 use core::fmt;
 use core::fmt::{Display, Formatter};
 use core::num::ParseIntError;
@@ -8,6 +9,8 @@ use core::str::FromStr;
 
 use bech32::{u5, FromBase32};
 
+use bitcoin::{PubkeyHash, ScriptHash};
+use bitcoin::util::address::WitnessVersion;
 use bitcoin_hashes::Hash;
 use bitcoin_hashes::sha256;
 use crate::prelude::*;
@@ -550,27 +553,24 @@ impl FromBase32 for Fallback {
                                if bytes.len() < 2 || bytes.len() > 40 {
                                        return Err(ParseError::InvalidSegWitProgramLength);
                                }
-
+                               let version = WitnessVersion::try_from(version).expect("0 through 16 are valid SegWit versions");
                                Ok(Fallback::SegWitProgram {
                                        version,
                                        program: bytes
                                })
                        },
                        17 => {
-                               if bytes.len() != 20 {
-                                       return Err(ParseError::InvalidPubKeyHashLength);
-                               }
-                               //TODO: refactor once const generics are available
-                               let mut pkh = [0u8; 20];
-                               pkh.copy_from_slice(&bytes);
+                               let pkh = match PubkeyHash::from_slice(&bytes) {
+                                       Ok(pkh) => pkh,
+                                       Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(ParseError::InvalidPubKeyHashLength),
+                               };
                                Ok(Fallback::PubKeyHash(pkh))
                        }
                        18 => {
-                               if bytes.len() != 20 {
-                                       return Err(ParseError::InvalidScriptHashLength);
-                               }
-                               let mut sh = [0u8; 20];
-                               sh.copy_from_slice(&bytes);
+                               let sh = match ScriptHash::from_slice(&bytes) {
+                                       Ok(sh) => sh,
+                                       Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(ParseError::InvalidScriptHashLength),
+                               };
                                Ok(Fallback::ScriptHash(sh))
                        }
                        _ => Err(ParseError::Skip)
@@ -852,26 +852,29 @@ mod test {
        fn test_parse_fallback() {
                use crate::Fallback;
                use bech32::FromBase32;
+               use bitcoin::{PubkeyHash, ScriptHash};
+               use bitcoin::util::address::WitnessVersion;
+               use bitcoin_hashes::Hash;
 
                let cases = vec![
                        (
                                from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
-                               Ok(Fallback::PubKeyHash([
+                               Ok(Fallback::PubKeyHash(PubkeyHash::from_slice(&[
                                        0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
                                        0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
-                               ]))
+                               ]).unwrap()))
                        ),
                        (
                                from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
-                               Ok(Fallback::ScriptHash([
+                               Ok(Fallback::ScriptHash(ScriptHash::from_slice(&[
                                        0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
                                        0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
-                               ]))
+                               ]).unwrap()))
                        ),
                        (
                                from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
                                Ok(Fallback::SegWitProgram {
-                                       version: u5::try_from_u8(0).unwrap(),
+                                       version: WitnessVersion::V0,
                                        program: Vec::from(&[
                                                0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
                                                0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
index 9ff22b8a3c316a3371149d8873e89f528e2f634b..e9565f4ce30d26af2cb85d104c46c5faef4babd9 100644 (file)
@@ -47,8 +47,9 @@ extern crate serde;
 use std::time::SystemTime;
 
 use bech32::u5;
-use bitcoin_hashes::Hash;
-use bitcoin_hashes::sha256;
+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;
 #[cfg(any(doc, test))]
@@ -389,6 +390,29 @@ pub enum Currency {
        Signet,
 }
 
+impl From<Network> for Currency {
+       fn from(network: Network) -> Self {
+               match network {
+                       Network::Bitcoin => Currency::Bitcoin,
+                       Network::Testnet => Currency::BitcoinTestnet,
+                       Network::Regtest => Currency::Regtest,
+                       Network::Signet => Currency::Signet,
+               }
+       }
+}
+
+impl From<Currency> for Network {
+       fn from(currency: Currency) -> Self {
+               match currency {
+                       Currency::Bitcoin => Network::Bitcoin,
+                       Currency::BitcoinTestnet => Network::Testnet,
+                       Currency::Regtest => Network::Regtest,
+                       Currency::Simnet => Network::Regtest,
+                       Currency::Signet => Network::Signet,
+               }
+       }
+}
+
 /// Tagged field which may have an unknown tag
 ///
 /// This is not exported to bindings users as we don't currently support TaggedField
@@ -446,17 +470,16 @@ pub struct ExpiryTime(Duration);
 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
 pub struct MinFinalCltvExpiryDelta(pub u64);
 
-// TODO: better types instead onf byte arrays
 /// Fallback address in case no LN payment is possible
 #[allow(missing_docs)]
 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
 pub enum Fallback {
        SegWitProgram {
-               version: u5,
+               version: WitnessVersion,
                program: Vec<u8>,
        },
-       PubKeyHash([u8; 20]),
-       ScriptHash([u8; 20]),
+       PubKeyHash(PubkeyHash),
+       ScriptHash(ScriptHash),
 }
 
 /// Recoverable signature
@@ -1300,6 +1323,25 @@ impl Invoice {
                self.signed_invoice.fallbacks()
        }
 
+       /// Returns a list of all fallback addresses as [`Address`]es
+       pub fn fallback_addresses(&self) -> Vec<Address> {
+               self.fallbacks().iter().map(|fallback| {
+                       let payload = match fallback {
+                               Fallback::SegWitProgram { version, program } => {
+                                       Payload::WitnessProgram { version: *version, program: program.to_vec() }
+                               }
+                               Fallback::PubKeyHash(pkh) => {
+                                       Payload::PubkeyHash(*pkh)
+                               }
+                               Fallback::ScriptHash(sh) => {
+                                       Payload::ScriptHash(*sh)
+                               }
+                       };
+
+                       Address { payload, network: self.network() }
+               }).collect()
+       }
+
        /// Returns a list of all routes included in the invoice
        pub fn private_routes(&self) -> Vec<&PrivateRoute> {
                self.signed_invoice.private_routes()
@@ -1317,6 +1359,11 @@ impl Invoice {
                self.signed_invoice.currency()
        }
 
+       /// Returns the network for which the invoice was issued
+       pub fn network(&self) -> Network {
+               self.signed_invoice.currency().into()
+       }
+
        /// Returns the amount if specified in the invoice as millisatoshis.
        pub fn amount_milli_satoshis(&self) -> Option<u64> {
                self.signed_invoice.amount_pico_btc().map(|v| v / 10)
@@ -1609,6 +1656,7 @@ impl<'de> Deserialize<'de> for Invoice {
 
 #[cfg(test)]
 mod test {
+       use bitcoin::Script;
        use bitcoin_hashes::hex::FromHex;
        use bitcoin_hashes::sha256;
 
@@ -1972,7 +2020,7 @@ mod test {
                        .payee_pub_key(public_key)
                        .expiry_time(Duration::from_secs(54321))
                        .min_final_cltv_expiry_delta(144)
-                       .fallback(Fallback::PubKeyHash([0;20]))
+                       .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[0;20]).unwrap()))
                        .private_route(route_1.clone())
                        .private_route(route_2.clone())
                        .description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
@@ -1998,7 +2046,9 @@ mod test {
                assert_eq!(invoice.payee_pub_key(), Some(&public_key));
                assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
                assert_eq!(invoice.min_final_cltv_expiry_delta(), 144);
-               assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
+               assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash(PubkeyHash::from_slice(&[0;20]).unwrap())]);
+               let address = Address::from_script(&Script::new_p2pkh(&PubkeyHash::from_slice(&[0;20]).unwrap()), Network::Testnet).unwrap();
+               assert_eq!(invoice.fallback_addresses(), vec![address]);
                assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
                assert_eq!(
                        invoice.description(),
index c9fca01f11f48fa9923e7d748ec824f43622b7f6..29a2ca074edf0185c7d3ac97d74baa087dd1af29 100644 (file)
@@ -329,7 +329,7 @@ impl ToBase32 for Fallback {
        fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
                match *self {
                        Fallback::SegWitProgram {version: v, program: ref p} => {
-                               writer.write_u5(v)?;
+                               writer.write_u5(Into::<u5>::into(v))?;
                                p.write_base32(writer)
                        },
                        Fallback::PubKeyHash(ref hash) => {
index 272d9062a6e4c9a062e622c55f2ed568bbae5409..73e2ea8384a1190680c913cf50a5336317f6f171 100644 (file)
@@ -5,9 +5,10 @@ extern crate lightning_invoice;
 extern crate secp256k1;
 extern crate hex;
 
+use bitcoin::util::address::WitnessVersion;
+use bitcoin::{PubkeyHash, ScriptHash};
 use bitcoin_hashes::hex::FromHex;
 use bitcoin_hashes::{sha256, Hash};
-use bech32::u5;
 use lightning::ln::PaymentSecret;
 use lightning::routing::gossip::RoutingFees;
 use lightning::routing::router::{RouteHint, RouteHintHop};
@@ -115,7 +116,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
                                ).unwrap())
-                               .fallback(Fallback::PubKeyHash([49, 114, 181, 101, 79, 102, 131, 200, 251, 20, 105, 89, 211, 71, 206, 48, 60, 174, 76, 167]))
+                               .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[49, 114, 181, 101, 79, 102, 131, 200, 251, 20, 105, 89, 211, 71, 206, 48, 60, 174, 76, 167]).unwrap()))
                                .build_raw()
                                .unwrap()
                                .sign(|_| {
@@ -137,7 +138,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
                                ).unwrap())
-                               .fallback(Fallback::PubKeyHash([4, 182, 31, 125, 193, 234, 13, 201, 148, 36, 70, 76, 196, 6, 77, 197, 100, 217, 30, 137]))
+                               .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[4, 182, 31, 125, 193, 234, 13, 201, 148, 36, 70, 76, 196, 6, 77, 197, 100, 217, 30, 137]).unwrap()))
                                .private_route(RouteHint(vec![RouteHintHop {
                                        src_node_id: PublicKey::from_slice(&hex::decode(
                                                        "029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"
@@ -176,7 +177,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
                                ).unwrap())
-                               .fallback(Fallback::ScriptHash([143, 85, 86, 59, 154, 25, 243, 33, 194, 17, 233, 185, 243, 140, 223, 104, 110, 160, 120, 69]))
+                               .fallback(Fallback::ScriptHash(ScriptHash::from_slice(&[143, 85, 86, 59, 154, 25, 243, 33, 194, 17, 233, 185, 243, 140, 223, 104, 110, 160, 120, 69]).unwrap()))
                                .build_raw()
                                .unwrap()
                                .sign(|_| {
@@ -198,7 +199,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
                                ).unwrap())
-                               .fallback(Fallback::SegWitProgram { version: u5::try_from_u8(0).unwrap(),
+                               .fallback(Fallback::SegWitProgram { version: WitnessVersion::V0,
                                        program: vec![117, 30, 118, 232, 25, 145, 150, 212, 84, 148, 28, 69, 209, 179, 163, 35, 241, 67, 59, 214]
                                })
                                .build_raw()
@@ -222,7 +223,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
                                ).unwrap())
-                               .fallback(Fallback::SegWitProgram { version: u5::try_from_u8(0).unwrap(),
+                               .fallback(Fallback::SegWitProgram { version: WitnessVersion::V0,
                                        program: vec![24, 99, 20, 60, 20, 197, 22, 104, 4, 189, 25, 32, 51, 86, 218, 19, 108, 152, 86, 120, 205, 77, 39, 161, 184, 198, 50, 150, 4, 144, 50, 98]
                                })
                                .build_raw()
index ce329e241370a5dfc216ef7199fe42ddc94479c2..c8f140cc18955d8225bbf300fcda2aee6ddae267 100644 (file)
 //! let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
 //! let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
 //! let snapshot_contents: &[u8] = &[0; 0];
-//! let new_last_sync_timestamp_result = rapid_sync.update_network_graph(snapshot_contents);
+//! // In no-std you need to provide the current time in unix epoch seconds
+//! // otherwise you can use update_network_graph
+//! let current_time_unix = 0;
+//! let new_last_sync_timestamp_result = rapid_sync.update_network_graph_no_std(snapshot_contents, Some(current_time_unix));
 //! ```
 
 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
@@ -128,6 +131,7 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
        /// Returns the last sync timestamp to be used the next time rapid sync data is queried.
        ///
        /// `update_data`: `&[u8]` binary stream that comprises the update data
+       #[cfg(feature = "std")]
        pub fn update_network_graph(&self, update_data: &[u8]) -> Result<u32, GraphSyncError> {
                let mut read_cursor = io::Cursor::new(update_data);
                self.update_network_graph_from_byte_stream(&mut read_cursor)
index 400fe1ccc5d4f803d395fbfa2adc2d066146957d..b387d49998e9a38d6f1693e1a18d05c4da57e675 100644 (file)
@@ -38,13 +38,14 @@ const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY: u32 = 50_000;
 const STALE_RGS_UPDATE_AGE_LIMIT_SECS: u64 = 60 * 60 * 24 * 14;
 
 impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
+       #[cfg(feature = "std")]
        pub(crate) fn update_network_graph_from_byte_stream<R: io::Read>(
                &self,
                read_cursor: &mut R,
        ) -> Result<u32, GraphSyncError> {
                #[allow(unused_mut, unused_assignments)]
                let mut current_time_unix = None;
-               #[cfg(all(feature = "std", not(test)))]
+               #[cfg(not(test))]
                {
                        // Note that many tests rely on being able to set arbitrarily old timestamps, thus we
                        // disable this check during tests!
@@ -237,6 +238,11 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                }
 
                self.network_graph.set_last_rapid_gossip_sync_timestamp(latest_seen_timestamp);
+
+               if let Some(time) = current_time_unix {
+                       self.network_graph.remove_stale_channels_and_tracking_with_time(time)
+               }
+
                self.is_initial_sync_complete.store(true, Ordering::Release);
                log_trace!(self.logger, "Done processing RGS data from {}", latest_seen_timestamp);
                Ok(latest_seen_timestamp)
@@ -247,7 +253,9 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
 mod tests {
        use bitcoin::Network;
 
+       #[cfg(feature = "std")]
        use lightning::ln::msgs::DecodeError;
+
        use lightning::routing::gossip::NetworkGraph;
        use lightning::util::test_utils::TestLogger;
 
@@ -275,6 +283,7 @@ mod tests {
        const VALID_BINARY_TIMESTAMP: u64 = 1642291930;
 
        #[test]
+       #[cfg(feature = "std")]
        fn network_graph_fails_to_update_from_clipped_input() {
                let logger = TestLogger::new();
                let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
@@ -306,6 +315,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_only_update_ignores_missing_channel() {
                let incremental_update_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -326,6 +336,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_only_update_fails_without_prior_updates() {
                let announced_update_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -353,6 +364,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_only_update_fails_without_prior_same_direction_updates() {
                let initialization_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -408,6 +420,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_update_succeeds_with_prior_announcements_and_full_updates() {
                let initialization_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -467,6 +480,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn update_succeeds_when_duplicate_gossip_is_applied() {
                let initialization_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -510,6 +524,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn full_update_succeeds() {
                let logger = TestLogger::new();
                let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
@@ -554,6 +569,34 @@ mod tests {
                assert_eq!(network_graph.read_only().channels().len(), 2);
        }
 
+       #[test]
+       fn prunes_after_update() {
+               // this is the timestamp encoded in the binary data of valid_input below
+               let logger = TestLogger::new();
+
+               let latest_nonpruning_time = VALID_BINARY_TIMESTAMP + 60 * 60 * 24 * 7;
+
+               {
+                       let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
+
+                       let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
+                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time));
+                       assert!(update_result.is_ok());
+                       assert_eq!(network_graph.read_only().channels().len(), 2);
+               }
+
+               {
+                       let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
+
+                       let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
+                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time + 1));
+                       assert!(update_result.is_ok());
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
+               }
+       }
+
        #[test]
        fn timestamp_edge_cases_are_handled_correctly() {
                // this is the timestamp encoded in the binary data of valid_input below
@@ -569,7 +612,7 @@ mod tests {
                        let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
                        let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_succeeding_time));
                        assert!(update_result.is_ok());
-                       assert_eq!(network_graph.read_only().channels().len(), 2);
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
                }
 
                {
@@ -591,6 +634,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        pub fn update_fails_with_unknown_version() {
                let unknown_version_input = vec![
                        76, 68, 75, 2, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
index 6dd1e8d220b63a6793d31ed21e842701b3f5ac4a..3748c5688da81f9f9ac493ac059573b71b79a67b 100644 (file)
@@ -1354,15 +1354,15 @@ pub struct PhantomRouteHints {
 }
 
 macro_rules! handle_error {
-       ($self: ident, $internal: expr, $counterparty_node_id: expr) => {
+       ($self: ident, $internal: expr, $counterparty_node_id: expr) => { {
+               // In testing, ensure there are no deadlocks where the lock is already held upon
+               // entering the macro.
+               debug_assert_ne!($self.pending_events.held_by_thread(), LockHeldState::HeldByThread);
+               debug_assert_ne!($self.per_peer_state.held_by_thread(), LockHeldState::HeldByThread);
+
                match $internal {
                        Ok(msg) => Ok(msg),
                        Err(MsgHandleErrInternal { err, chan_id, shutdown_finish }) => {
-                               // In testing, ensure there are no deadlocks where the lock is already held upon
-                               // entering the macro.
-                               debug_assert_ne!($self.pending_events.held_by_thread(), LockHeldState::HeldByThread);
-                               debug_assert_ne!($self.per_peer_state.held_by_thread(), LockHeldState::HeldByThread);
-
                                let mut msg_events = Vec::with_capacity(2);
 
                                if let Some((shutdown_res, update_option)) = shutdown_finish {
@@ -1401,7 +1401,7 @@ macro_rules! handle_error {
                                Err(err)
                        },
                }
-       }
+       } }
 }
 
 macro_rules! update_maps_on_chan_removal {
@@ -2786,29 +2786,34 @@ where
 
                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                let peer_state = &mut *peer_state_lock;
-               let (chan, msg) = {
-                       let (res, chan) = {
-                               match peer_state.channel_by_id.remove(temporary_channel_id) {
-                                       Some(mut chan) => {
-                                               let funding_txo = find_funding_output(&chan, &funding_transaction)?;
-
-                                               (chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger)
-                                                       .map_err(|e| if let ChannelError::Close(msg) = e {
-                                                               MsgHandleErrInternal::from_finish_shutdown(msg, chan.channel_id(), chan.get_user_id(), chan.force_shutdown(true), None)
-                                                       } else { unreachable!(); })
-                                               , chan)
+               let (msg, chan) = match peer_state.channel_by_id.remove(temporary_channel_id) {
+                       Some(mut chan) => {
+                               let funding_txo = find_funding_output(&chan, &funding_transaction)?;
+
+                               let funding_res = chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger)
+                                       .map_err(|e| if let ChannelError::Close(msg) = e {
+                                               MsgHandleErrInternal::from_finish_shutdown(msg, chan.channel_id(), chan.get_user_id(), chan.force_shutdown(true), None)
+                                       } else { unreachable!(); });
+                               match funding_res {
+                                       Ok(funding_msg) => (funding_msg, chan),
+                                       Err(_) => {
+                                               mem::drop(peer_state_lock);
+                                               mem::drop(per_peer_state);
+
+                                               let _ = handle_error!(self, funding_res, chan.get_counterparty_node_id());
+                                               return Err(APIError::ChannelUnavailable {
+                                                       err: "Signer refused to sign the initial commitment transaction".to_owned()
+                                               });
                                        },
-                                       None => { return Err(APIError::ChannelUnavailable { err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*temporary_channel_id), counterparty_node_id) }) },
                                }
-                       };
-                       match handle_error!(self, res, chan.get_counterparty_node_id()) {
-                               Ok(funding_msg) => {
-                                       (chan, funding_msg)
-                               },
-                               Err(_) => { return Err(APIError::ChannelUnavailable {
-                                       err: "Signer refused to sign the initial commitment transaction".to_owned()
-                               }) },
-                       }
+                       },
+                       None => {
+                               return Err(APIError::ChannelUnavailable {
+                                       err: format!(
+                                               "Channel with id {} not found for the passed counterparty node_id {}",
+                                               log_bytes!(*temporary_channel_id), counterparty_node_id),
+                               })
+                       },
                };
 
                peer_state.pending_msg_events.push(events::MessageSendEvent::SendFundingCreated {