From 9642356d9a2af94a5c6995cbe2dd9b1a3aa7dec3 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Nov 2020 11:42:03 -0500 Subject: [PATCH 1/4] Finally drop travis entirely. It seems travis isn't even bothering to spawn our jobs anymore, and Github CI has been pretty stable, so just drop Travis entirely. --- .travis.yml | 48 ------------------------------------------------ 1 file changed, 48 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8c1f2fd0f0d..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,48 +0,0 @@ -language: rust -rust: - - stable - - beta - # 1.30.0 is MSRV for rust-lightning in general: - - 1.30.0 - # 1.34.2 is Debian stable - - 1.34.2 - # 1.39.0 is MSRV for lightning-net-tokio and generates coverage - - 1.39.0 -cache: cargo - -before_install: - - sudo apt-get -qq update - - sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc binutils-dev libiberty-dev - -script: - # Support lightning-net-tokio only on Rust stable, beta, and 1.39.0 - - if [ "$(rustup show | grep default | grep '1.39.0')" != "" ]; then export BUILD_NET_TOKIO=1; fi - - if [ "$(rustup show | grep default | grep '1\.')" == "" ]; then export BUILD_NET_TOKIO=1; fi - # Build the appropriate workspace(s) - - if [ "$BUILD_NET_TOKIO" == "1" ]; then RUSTFLAGS="-C link-dead-code" cargo build --verbose; fi - - if [ "$BUILD_NET_TOKIO" != "1" ]; then RUSTFLAGS="-C link-dead-code" cargo build --verbose -p lightning; fi - - rm -f target/debug/lightning-* # Make sure we drop old test binaries - # Run clippy on Rust 1.39.0 - - if [ "$(rustup show | grep default | grep 1.39.0)" != "" ]; then - rustup component add clippy && - cargo clippy -- -Aclippy::erasing_op -Aclippy::never_loop -Aclippy::if_same_then_else; fi - # Test the appropriate workspace(s) - - if [ "$BUILD_NET_TOKIO" == "1" ]; then RUSTFLAGS="-C link-dead-code" cargo test --verbose; fi - - if [ "$BUILD_NET_TOKIO" != "1" ]; then RUSTFLAGS="-C link-dead-code" cargo test --verbose -p lightning; fi - # Run lightning workspace fuzz tests on Rust stable - - if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./ci-fuzz.sh; fi - # Generate code cov information on Rust 1.39.0 - - if [ "$(rustup show | grep default | grep 1.39.0)" != "" ]; then - wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && - tar xzf master.tar.gz && - cd kcov-master && - mkdir build && - cd build && - cmake .. && - make && - make install DESTDIR=../../kcov-build && - cd ../.. && - rm -rf kcov-master && - for file in target/debug/lightning-*; do [ -x "${file}" ] || continue; mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && - bash <(curl -s https://codecov.io/bash) && - echo "Uploaded code coverage"; fi From d9c03f26f9d52ca96bc889eae64087a690ff1a22 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Nov 2020 12:40:11 -0500 Subject: [PATCH 2/4] Move UTXO-lookup into pub utility function from RoutingMsgHandler This makes the public utility methods in `NetworkGraph` able to do UTXO lookups ala `NetworkMsgHandler`'s `RoutingMessageHandler` implementation, slightly simplifying the public interface. We also take this opportunity to verify signatures before calling out to UTXO lookups, under the "do actions in order of cheapest-to-most-expensive to reduce DoS surface" principle. --- fuzz/src/router.rs | 5 +- lightning/src/routing/network_graph.rs | 81 ++++++++++++-------------- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index ef7669f1eaf..95abf9718c5 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -175,14 +175,13 @@ pub fn do_test(data: &[u8], out: Out) { let msg = decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4); node_pks.insert(msg.contents.node_id_1); node_pks.insert(msg.contents.node_id_2); - let _ = net_graph.update_channel_from_announcement::(&msg, None, None); + let _ = net_graph.update_channel_from_announcement::(&msg, &None, None); }, 2 => { let msg = decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4); node_pks.insert(msg.contents.node_id_1); node_pks.insert(msg.contents.node_id_2); - let val = slice_to_be64(get_slice!(8)); - let _ = net_graph.update_channel_from_announcement::(&msg, Some(val), None); + let _ = net_graph.update_channel_from_announcement::(&msg, &Some(&FuzzChainSource { input: Arc::clone(&input) }), None); }, 3 => { let _ = net_graph.update_channel(&decode_msg!(msgs::ChannelUpdate, 136), None); diff --git a/lightning/src/routing/network_graph.rs b/lightning/src/routing/network_graph.rs index 932f3779def..5003ca512f5 100644 --- a/lightning/src/routing/network_graph.rs +++ b/lightning/src/routing/network_graph.rs @@ -125,40 +125,7 @@ impl RoutingMessageHandler for N } fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result { - if msg.contents.node_id_1 == msg.contents.node_id_2 || msg.contents.bitcoin_key_1 == msg.contents.bitcoin_key_2 { - return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError}); - } - - let utxo_value = match &self.chain_access { - &None => { - // Tentatively accept, potentially exposing us to DoS attacks - None - }, - &Some(ref chain_access) => { - match chain_access.get_utxo(&msg.contents.chain_hash, msg.contents.short_channel_id) { - Ok(TxOut { value, script_pubkey }) => { - let expected_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2) - .push_slice(&msg.contents.bitcoin_key_1.serialize()) - .push_slice(&msg.contents.bitcoin_key_2.serialize()) - .push_opcode(opcodes::all::OP_PUSHNUM_2) - .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh(); - if script_pubkey != expected_script { - return Err(LightningError{err: format!("Channel announcement key ({}) didn't match on-chain script ({})", script_pubkey.to_hex(), expected_script.to_hex()), action: ErrorAction::IgnoreError}); - } - //TODO: Check if value is worth storing, use it to inform routing, and compare it - //to the new HTLC max field in channel_update - Some(value) - }, - Err(chain::AccessError::UnknownChain) => { - return Err(LightningError{err: format!("Channel announced on an unknown chain ({})", msg.contents.chain_hash.encode().to_hex()), action: ErrorAction::IgnoreError}); - }, - Err(chain::AccessError::UnknownTx) => { - return Err(LightningError{err: "Channel announced without corresponding UTXO entry".to_owned(), action: ErrorAction::IgnoreError}); - }, - } - }, - }; - let result = self.network_graph.write().unwrap().update_channel_from_announcement(msg, utxo_value, Some(&self.secp_ctx)); + let result = self.network_graph.write().unwrap().update_channel_from_announcement(msg, &self.chain_access, Some(&self.secp_ctx)); log_trace!(self.logger, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" }); result } @@ -605,17 +572,14 @@ impl NetworkGraph { /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept /// routing messages without checking their signatures. /// - /// If the channel has been confirmed to exist on chain (with correctly-formatted scripts on - /// chain), set utxo_value to the value of the output on chain, otherwise leave it as None. - /// The UTXO value is then used in routing calculation if we have no better information on the - /// maximum HTLC value that can be sent over the channel. - /// - /// Further, setting utxo_value to Some indicates that the announcement message is genuine, - /// allowing us to update existing channel data in the case of reorgs or to replace bogus - /// channel data generated by a DoS attacker. + /// If a `chain::Access` object is provided via `chain_access`, it will be called to verify + /// the corresponding UTXO exists on chain and is correctly-formatted. /// /// Announcement signatures are checked here only if Secp256k1 object is provided. - pub fn update_channel_from_announcement(&mut self, msg: &msgs::ChannelAnnouncement, utxo_value: Option, secp_ctx: Option<&Secp256k1>) -> Result { + pub fn update_channel_from_announcement + (&mut self, msg: &msgs::ChannelAnnouncement, chain_access: &Option, secp_ctx: Option<&Secp256k1>) + -> Result + where C::Target: chain::Access { if msg.contents.node_id_1 == msg.contents.node_id_2 || msg.contents.bitcoin_key_1 == msg.contents.bitcoin_key_2 { return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError}); } @@ -628,8 +592,37 @@ impl NetworkGraph { secp_verify_sig!(sig_verifier, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2); } - let should_relay = msg.contents.excess_data.is_empty(); + let utxo_value = match &chain_access { + &None => { + // Tentatively accept, potentially exposing us to DoS attacks + None + }, + &Some(ref chain_access) => { + match chain_access.get_utxo(&msg.contents.chain_hash, msg.contents.short_channel_id) { + Ok(TxOut { value, script_pubkey }) => { + let expected_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2) + .push_slice(&msg.contents.bitcoin_key_1.serialize()) + .push_slice(&msg.contents.bitcoin_key_2.serialize()) + .push_opcode(opcodes::all::OP_PUSHNUM_2) + .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh(); + if script_pubkey != expected_script { + return Err(LightningError{err: format!("Channel announcement key ({}) didn't match on-chain script ({})", script_pubkey.to_hex(), expected_script.to_hex()), action: ErrorAction::IgnoreError}); + } + //TODO: Check if value is worth storing, use it to inform routing, and compare it + //to the new HTLC max field in channel_update + Some(value) + }, + Err(chain::AccessError::UnknownChain) => { + return Err(LightningError{err: format!("Channel announced on an unknown chain ({})", msg.contents.chain_hash.encode().to_hex()), action: ErrorAction::IgnoreError}); + }, + Err(chain::AccessError::UnknownTx) => { + return Err(LightningError{err: "Channel announced without corresponding UTXO entry".to_owned(), action: ErrorAction::IgnoreError}); + }, + } + }, + }; + let should_relay = msg.contents.excess_data.is_empty(); let chan_info = ChannelInfo { features: msg.contents.features.clone(), node_one: msg.contents.node_id_1.clone(), From 3b6f7f1199a2e3a3f69583a2eaf501c403fe1a53 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Nov 2020 13:38:39 -0500 Subject: [PATCH 3/4] Split `NetworkGraph` message handling fns into unsigned and signed This takes the now-public `NetworkGraph` message handling functions and splits them all into two methods - one which takes a required Secp256k1 context and verifies signatures and one which takes only the unsigned part of the message and does not take a Secp256k1 context. This both clarifies the public API as well as simplifies it, all without duplicating code. Finally, this adds an assertion in the Router fuzzer to make sure the constants used for message deserialization are correct. --- fuzz/src/router.rs | 41 ++--- lightning/src/routing/network_graph.rs | 200 ++++++++++++++----------- 2 files changed, 136 insertions(+), 105 deletions(-) diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index 95abf9718c5..671adcfda51 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -11,8 +11,6 @@ use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::transaction::TxOut; use bitcoin::hash_types::BlockHash; -use bitcoin::secp256k1; - use lightning::chain; use lightning::ln::channelmanager::ChannelDetails; use lightning::ln::features::InitFeatures; @@ -120,7 +118,10 @@ pub fn do_test(data: &[u8], out: Out) { ($MsgType: path, $len: expr) => {{ let mut reader = ::std::io::Cursor::new(get_slice!($len)); match <$MsgType>::read(&mut reader) { - Ok(msg) => msg, + Ok(msg) => { + assert_eq!(reader.position(), $len as u64); + msg + }, Err(e) => match e { msgs::DecodeError::UnknownVersion => return, msgs::DecodeError::UnknownRequiredFeature => return, @@ -134,10 +135,10 @@ pub fn do_test(data: &[u8], out: Out) { } macro_rules! decode_msg_with_len16 { - ($MsgType: path, $begin_len: expr, $excess: expr) => { + ($MsgType: path, $excess: expr) => { { - let extra_len = slice_to_be16(&get_slice_nonadvancing!($begin_len as usize + 2)[$begin_len..$begin_len + 2]); - decode_msg!($MsgType, $begin_len as usize + 2 + (extra_len as usize) + $excess) + let extra_len = slice_to_be16(get_slice_nonadvancing!(2)); + decode_msg!($MsgType, 2 + (extra_len as usize) + $excess) } } } @@ -162,29 +163,29 @@ pub fn do_test(data: &[u8], out: Out) { loop { match get_slice!(1)[0] { 0 => { - let start_len = slice_to_be16(&get_slice_nonadvancing!(64 + 2)[64..64 + 2]) as usize; - let addr_len = slice_to_be16(&get_slice_nonadvancing!(64+start_len+2 + 74)[64+start_len+2 + 72..64+start_len+2 + 74]); + let start_len = slice_to_be16(&get_slice_nonadvancing!(2)[0..2]) as usize; + let addr_len = slice_to_be16(&get_slice_nonadvancing!(start_len+2 + 74)[start_len+2 + 72..start_len+2 + 74]); if addr_len > (37+1)*4 { return; } - let msg = decode_msg_with_len16!(msgs::NodeAnnouncement, 64, 288); - node_pks.insert(msg.contents.node_id); - let _ = net_graph.update_node_from_announcement::(&msg, None); + let msg = decode_msg_with_len16!(msgs::UnsignedNodeAnnouncement, 288); + node_pks.insert(msg.node_id); + let _ = net_graph.update_node_from_unsigned_announcement(&msg); }, 1 => { - let msg = decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4); - node_pks.insert(msg.contents.node_id_1); - node_pks.insert(msg.contents.node_id_2); - let _ = net_graph.update_channel_from_announcement::(&msg, &None, None); + let msg = decode_msg_with_len16!(msgs::UnsignedChannelAnnouncement, 32+8+33*4); + node_pks.insert(msg.node_id_1); + node_pks.insert(msg.node_id_2); + let _ = net_graph.update_channel_from_unsigned_announcement::<&FuzzChainSource>(&msg, &None); }, 2 => { - let msg = decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4); - node_pks.insert(msg.contents.node_id_1); - node_pks.insert(msg.contents.node_id_2); - let _ = net_graph.update_channel_from_announcement::(&msg, &Some(&FuzzChainSource { input: Arc::clone(&input) }), None); + let msg = decode_msg_with_len16!(msgs::UnsignedChannelAnnouncement, 32+8+33*4); + node_pks.insert(msg.node_id_1); + node_pks.insert(msg.node_id_2); + let _ = net_graph.update_channel_from_unsigned_announcement(&msg, &Some(&FuzzChainSource { input: Arc::clone(&input) })); }, 3 => { - let _ = net_graph.update_channel(&decode_msg!(msgs::ChannelUpdate, 136), None); + let _ = net_graph.update_channel_unsigned(&decode_msg!(msgs::UnsignedChannelUpdate, 72)); }, 4 => { let short_channel_id = slice_to_be64(get_slice!(8)); diff --git a/lightning/src/routing/network_graph.rs b/lightning/src/routing/network_graph.rs index 5003ca512f5..54783dd1dc3 100644 --- a/lightning/src/routing/network_graph.rs +++ b/lightning/src/routing/network_graph.rs @@ -121,19 +121,20 @@ macro_rules! secp_verify_sig { impl RoutingMessageHandler for NetGraphMsgHandler where C::Target: chain::Access, L::Target: Logger { fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result { - self.network_graph.write().unwrap().update_node_from_announcement(msg, Some(&self.secp_ctx)) + self.network_graph.write().unwrap().update_node_from_announcement(msg, &self.secp_ctx)?; + Ok(msg.contents.excess_data.is_empty() && msg.contents.excess_address_data.is_empty()) } fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result { - let result = self.network_graph.write().unwrap().update_channel_from_announcement(msg, &self.chain_access, Some(&self.secp_ctx)); + self.network_graph.write().unwrap().update_channel_from_announcement(msg, &self.chain_access, &self.secp_ctx)?; log_trace!(self.logger, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" }); - result + Ok(msg.contents.excess_data.is_empty()) } fn handle_htlc_fail_channel_update(&self, update: &msgs::HTLCFailChannelUpdate) { match update { &msgs::HTLCFailChannelUpdate::ChannelUpdateMessage { ref msg } => { - let _ = self.network_graph.write().unwrap().update_channel(msg, Some(&self.secp_ctx)); + let _ = self.network_graph.write().unwrap().update_channel(msg, &self.secp_ctx); }, &msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id, is_permanent } => { self.network_graph.write().unwrap().close_channel_from_update(short_channel_id, is_permanent); @@ -145,7 +146,8 @@ impl RoutingMessageHandler for N } fn handle_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result { - self.network_graph.write().unwrap().update_channel(msg, Some(&self.secp_ctx)) + self.network_graph.write().unwrap().update_channel(msg, &self.secp_ctx)?; + Ok(msg.contents.excess_data.is_empty()) } fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(ChannelAnnouncement, Option, Option)> { @@ -529,39 +531,47 @@ impl NetworkGraph { } } - /// For an already known node (from channel announcements), update its stored properties from a given node announcement. + /// For an already known node (from channel announcements), update its stored properties from a + /// given node announcement. /// /// You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept - /// routing messages without checking their signatures. - /// - /// Announcement signatures are checked here only if Secp256k1 object is provided. - pub fn update_node_from_announcement(&mut self, msg: &msgs::NodeAnnouncement, secp_ctx: Option<&Secp256k1>) -> Result { - if let Some(sig_verifier) = secp_ctx { - let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); - secp_verify_sig!(sig_verifier, &msg_hash, &msg.signature, &msg.contents.node_id); - } + /// routing messages from a source using a protocol other than the lightning P2P protocol. + pub fn update_node_from_announcement(&mut self, msg: &msgs::NodeAnnouncement, secp_ctx: &Secp256k1) -> Result<(), LightningError> { + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id); + self.update_node_from_announcement_intern(&msg.contents, Some(&msg)) + } + + /// For an already known node (from channel announcements), update its stored properties from a + /// given node announcement without verifying the associated signatures. Because we aren't + /// given the associated signatures here we cannot relay the node announcement to any of our + /// peers. + pub fn update_node_from_unsigned_announcement(&mut self, msg: &msgs::UnsignedNodeAnnouncement) -> Result<(), LightningError> { + self.update_node_from_announcement_intern(msg, None) + } - match self.nodes.get_mut(&msg.contents.node_id) { + fn update_node_from_announcement_intern(&mut self, msg: &msgs::UnsignedNodeAnnouncement, full_msg: Option<&msgs::NodeAnnouncement>) -> Result<(), LightningError> { + match self.nodes.get_mut(&msg.node_id) { None => Err(LightningError{err: "No existing channels for node_announcement".to_owned(), action: ErrorAction::IgnoreError}), Some(node) => { if let Some(node_info) = node.announcement_info.as_ref() { - if node_info.last_update >= msg.contents.timestamp { + if node_info.last_update >= msg.timestamp { return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError}); } } - let should_relay = msg.contents.excess_data.is_empty() && msg.contents.excess_address_data.is_empty(); + let should_relay = msg.excess_data.is_empty() && msg.excess_address_data.is_empty(); node.announcement_info = Some(NodeAnnouncementInfo { - features: msg.contents.features.clone(), - last_update: msg.contents.timestamp, - rgb: msg.contents.rgb, - alias: msg.contents.alias, - addresses: msg.contents.addresses.clone(), - announcement_message: if should_relay { Some(msg.clone()) } else { None }, + features: msg.features.clone(), + last_update: msg.timestamp, + rgb: msg.rgb, + alias: msg.alias, + addresses: msg.addresses.clone(), + announcement_message: if should_relay { full_msg.cloned() } else { None }, }); - Ok(should_relay) + Ok(()) } } } @@ -570,26 +580,41 @@ impl NetworkGraph { /// /// You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept - /// routing messages without checking their signatures. + /// routing messages from a source using a protocol other than the lightning P2P protocol. /// /// If a `chain::Access` object is provided via `chain_access`, it will be called to verify /// the corresponding UTXO exists on chain and is correctly-formatted. - /// - /// Announcement signatures are checked here only if Secp256k1 object is provided. pub fn update_channel_from_announcement - (&mut self, msg: &msgs::ChannelAnnouncement, chain_access: &Option, secp_ctx: Option<&Secp256k1>) - -> Result + (&mut self, msg: &msgs::ChannelAnnouncement, chain_access: &Option, secp_ctx: &Secp256k1) + -> Result<(), LightningError> where C::Target: chain::Access { - if msg.contents.node_id_1 == msg.contents.node_id_2 || msg.contents.bitcoin_key_1 == msg.contents.bitcoin_key_2 { - return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError}); - } + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1); + secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2); + self.update_channel_from_unsigned_announcement_intern(&msg.contents, Some(msg), chain_access) + } + + /// Store or update channel info from a channel announcement without verifying the associated + /// signatures. Because we aren't given the associated signatures here we cannot relay the + /// channel announcement to any of our peers. + /// + /// If a `chain::Access` object is provided via `chain_access`, it will be called to verify + /// the corresponding UTXO exists on chain and is correctly-formatted. + pub fn update_channel_from_unsigned_announcement + (&mut self, msg: &msgs::UnsignedChannelAnnouncement, chain_access: &Option) + -> Result<(), LightningError> + where C::Target: chain::Access { + self.update_channel_from_unsigned_announcement_intern(msg, None, chain_access) + } - if let Some(sig_verifier) = secp_ctx { - let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); - secp_verify_sig!(sig_verifier, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1); - secp_verify_sig!(sig_verifier, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2); - secp_verify_sig!(sig_verifier, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1); - secp_verify_sig!(sig_verifier, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2); + fn update_channel_from_unsigned_announcement_intern + (&mut self, msg: &msgs::UnsignedChannelAnnouncement, full_msg: Option<&msgs::ChannelAnnouncement>, chain_access: &Option) + -> Result<(), LightningError> + where C::Target: chain::Access { + if msg.node_id_1 == msg.node_id_2 || msg.bitcoin_key_1 == msg.bitcoin_key_2 { + return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError}); } let utxo_value = match &chain_access { @@ -598,11 +623,11 @@ impl NetworkGraph { None }, &Some(ref chain_access) => { - match chain_access.get_utxo(&msg.contents.chain_hash, msg.contents.short_channel_id) { + match chain_access.get_utxo(&msg.chain_hash, msg.short_channel_id) { Ok(TxOut { value, script_pubkey }) => { let expected_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2) - .push_slice(&msg.contents.bitcoin_key_1.serialize()) - .push_slice(&msg.contents.bitcoin_key_2.serialize()) + .push_slice(&msg.bitcoin_key_1.serialize()) + .push_slice(&msg.bitcoin_key_2.serialize()) .push_opcode(opcodes::all::OP_PUSHNUM_2) .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh(); if script_pubkey != expected_script { @@ -613,7 +638,7 @@ impl NetworkGraph { Some(value) }, Err(chain::AccessError::UnknownChain) => { - return Err(LightningError{err: format!("Channel announced on an unknown chain ({})", msg.contents.chain_hash.encode().to_hex()), action: ErrorAction::IgnoreError}); + return Err(LightningError{err: format!("Channel announced on an unknown chain ({})", msg.chain_hash.encode().to_hex()), action: ErrorAction::IgnoreError}); }, Err(chain::AccessError::UnknownTx) => { return Err(LightningError{err: "Channel announced without corresponding UTXO entry".to_owned(), action: ErrorAction::IgnoreError}); @@ -622,18 +647,17 @@ impl NetworkGraph { }, }; - let should_relay = msg.contents.excess_data.is_empty(); let chan_info = ChannelInfo { - features: msg.contents.features.clone(), - node_one: msg.contents.node_id_1.clone(), + features: msg.features.clone(), + node_one: msg.node_id_1.clone(), one_to_two: None, - node_two: msg.contents.node_id_2.clone(), + node_two: msg.node_id_2.clone(), two_to_one: None, capacity_sats: utxo_value, - announcement_message: if should_relay { Some(msg.clone()) } else { None }, + announcement_message: if msg.excess_data.is_empty() { full_msg.cloned() } else { None }, }; - match self.channels.entry(msg.contents.short_channel_id) { + match self.channels.entry(msg.short_channel_id) { BtreeEntry::Occupied(mut entry) => { //TODO: because asking the blockchain if short_channel_id is valid is only optional //in the blockchain API, we need to handle it smartly here, though it's unclear @@ -647,7 +671,7 @@ impl NetworkGraph { // b) we don't track UTXOs of channels we know about and remove them if they // get reorg'd out. // c) it's unclear how to do so without exposing ourselves to massive DoS risk. - Self::remove_channel_in_nodes(&mut self.nodes, &entry.get(), msg.contents.short_channel_id); + Self::remove_channel_in_nodes(&mut self.nodes, &entry.get(), msg.short_channel_id); *entry.get_mut() = chan_info; } else { return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreError}) @@ -662,11 +686,11 @@ impl NetworkGraph { ( $node_id: expr ) => { match self.nodes.entry($node_id) { BtreeEntry::Occupied(node_entry) => { - node_entry.into_mut().channels.push(msg.contents.short_channel_id); + node_entry.into_mut().channels.push(msg.short_channel_id); }, BtreeEntry::Vacant(node_entry) => { node_entry.insert(NodeInfo { - channels: vec!(msg.contents.short_channel_id), + channels: vec!(msg.short_channel_id), lowest_inbound_channel_fees: None, announcement_info: None, }); @@ -675,10 +699,10 @@ impl NetworkGraph { }; } - add_channel_to_node!(msg.contents.node_id_1); - add_channel_to_node!(msg.contents.node_id_2); + add_channel_to_node!(msg.node_id_1); + add_channel_to_node!(msg.node_id_2); - Ok(should_relay) + Ok(()) } /// Close a channel if a corresponding HTLC fail was sent. @@ -710,22 +734,32 @@ impl NetworkGraph { } } - /// For an already known (from announcement) channel, update info about one of the directions of a channel. + /// For an already known (from announcement) channel, update info about one of the directions + /// of the channel. /// /// You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept - /// routing messages without checking their signatures. - /// - /// Announcement signatures are checked here only if Secp256k1 object is provided. - pub fn update_channel(&mut self, msg: &msgs::ChannelUpdate, secp_ctx: Option<&Secp256k1>) -> Result { + /// routing messages from a source using a protocol other than the lightning P2P protocol. + pub fn update_channel(&mut self, msg: &msgs::ChannelUpdate, secp_ctx: &Secp256k1) -> Result<(), LightningError> { + self.update_channel_intern(&msg.contents, Some(&msg), Some((&msg.signature, secp_ctx))) + } + + /// For an already known (from announcement) channel, update info about one of the directions + /// of the channel without verifying the associated signatures. Because we aren't given the + /// associated signatures here we cannot relay the channel update to any of our peers. + pub fn update_channel_unsigned(&mut self, msg: &msgs::UnsignedChannelUpdate) -> Result<(), LightningError> { + self.update_channel_intern(msg, None, None::<(&secp256k1::Signature, &Secp256k1)>) + } + + fn update_channel_intern(&mut self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>, sig_info: Option<(&secp256k1::Signature, &Secp256k1)>) -> Result<(), LightningError> { let dest_node_id; - let chan_enabled = msg.contents.flags & (1 << 1) != (1 << 1); + let chan_enabled = msg.flags & (1 << 1) != (1 << 1); let chan_was_enabled; - match self.channels.get_mut(&msg.contents.short_channel_id) { + match self.channels.get_mut(&msg.short_channel_id) { None => return Err(LightningError{err: "Couldn't find channel for update".to_owned(), action: ErrorAction::IgnoreError}), Some(channel) => { - if let OptionalField::Present(htlc_maximum_msat) = msg.contents.htlc_maximum_msat { + if let OptionalField::Present(htlc_maximum_msat) = msg.htlc_maximum_msat { if htlc_maximum_msat > MAX_VALUE_MSAT { return Err(LightningError{err: "htlc_maximum_msat is larger than maximum possible msats".to_owned(), action: ErrorAction::IgnoreError}); } @@ -741,7 +775,7 @@ impl NetworkGraph { macro_rules! maybe_update_channel_info { ( $target: expr, $src_node: expr) => { if let Some(existing_chan_info) = $target.as_ref() { - if existing_chan_info.last_update >= msg.contents.timestamp { + if existing_chan_info.last_update >= msg.timestamp { return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError}); } chan_was_enabled = existing_chan_info.enabled; @@ -749,21 +783,17 @@ impl NetworkGraph { chan_was_enabled = false; } - let last_update_message = if msg.contents.excess_data.is_empty() { - Some(msg.clone()) - } else { - None - }; + let last_update_message = if msg.excess_data.is_empty() { full_msg.cloned() } else { None }; let updated_channel_dir_info = DirectionalChannelInfo { enabled: chan_enabled, - last_update: msg.contents.timestamp, - cltv_expiry_delta: msg.contents.cltv_expiry_delta, - htlc_minimum_msat: msg.contents.htlc_minimum_msat, - htlc_maximum_msat: if let OptionalField::Present(max_value) = msg.contents.htlc_maximum_msat { Some(max_value) } else { None }, + last_update: msg.timestamp, + cltv_expiry_delta: msg.cltv_expiry_delta, + htlc_minimum_msat: msg.htlc_minimum_msat, + htlc_maximum_msat: if let OptionalField::Present(max_value) = msg.htlc_maximum_msat { Some(max_value) } else { None }, fees: RoutingFees { - base_msat: msg.contents.fee_base_msat, - proportional_millionths: msg.contents.fee_proportional_millionths, + base_msat: msg.fee_base_msat, + proportional_millionths: msg.fee_proportional_millionths, }, last_update_message }; @@ -771,17 +801,17 @@ impl NetworkGraph { } } - let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]); - if msg.contents.flags & 1 == 1 { + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); + if msg.flags & 1 == 1 { dest_node_id = channel.node_one.clone(); - if let Some(sig_verifier) = secp_ctx { - secp_verify_sig!(sig_verifier, &msg_hash, &msg.signature, &channel.node_two); + if let Some((sig, ctx)) = sig_info { + secp_verify_sig!(ctx, &msg_hash, &sig, &channel.node_two); } maybe_update_channel_info!(channel.two_to_one, channel.node_two); } else { dest_node_id = channel.node_two.clone(); - if let Some(sig_verifier) = secp_ctx { - secp_verify_sig!(sig_verifier, &msg_hash, &msg.signature, &channel.node_one); + if let Some((sig, ctx)) = sig_info { + secp_verify_sig!(ctx, &msg_hash, &sig, &channel.node_one); } maybe_update_channel_info!(channel.one_to_two, channel.node_one); } @@ -790,8 +820,8 @@ impl NetworkGraph { if chan_enabled { let node = self.nodes.get_mut(&dest_node_id).unwrap(); - let mut base_msat = msg.contents.fee_base_msat; - let mut proportional_millionths = msg.contents.fee_proportional_millionths; + let mut base_msat = msg.fee_base_msat; + let mut proportional_millionths = msg.fee_proportional_millionths; if let Some(fees) = node.lowest_inbound_channel_fees { base_msat = cmp::min(base_msat, fees.base_msat); proportional_millionths = cmp::min(proportional_millionths, fees.proportional_millionths); @@ -825,7 +855,7 @@ impl NetworkGraph { node.lowest_inbound_channel_fees = lowest_inbound_channel_fees; } - Ok(msg.contents.excess_data.is_empty()) + Ok(()) } fn remove_channel_in_nodes(nodes: &mut BTreeMap, chan: &ChannelInfo, short_channel_id: u64) { @@ -1171,8 +1201,8 @@ mod tests { unsigned_announcement.node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey); msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]); let channel_to_itself_announcement = ChannelAnnouncement { - node_signature_1: secp_ctx.sign(&msghash, node_1_privkey), - node_signature_2: secp_ctx.sign(&msghash, node_1_privkey), + node_signature_1: secp_ctx.sign(&msghash, node_2_privkey), + node_signature_2: secp_ctx.sign(&msghash, node_2_privkey), bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey), bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey), contents: unsigned_announcement.clone(), From ccd4a7acaaee6cc05998d89ccd24b296ddb3ee0e Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Nov 2020 13:41:06 -0500 Subject: [PATCH 4/4] Update auto-generated bindings with new NetworkGraph API --- lightning-c-bindings/include/lightning.h | 103 +++++++++++++++--- lightning-c-bindings/include/lightningpp.hpp | 14 +++ lightning-c-bindings/src/c_types/derived.rs | 13 +++ .../src/routing/network_graph.rs | 83 ++++++++++++++ 4 files changed, 199 insertions(+), 14 deletions(-) diff --git a/lightning-c-bindings/include/lightning.h b/lightning-c-bindings/include/lightning.h index 45e4fa3ab6b..61548022686 100644 --- a/lightning-c-bindings/include/lightning.h +++ b/lightning-c-bindings/include/lightning.h @@ -586,6 +586,32 @@ typedef struct LDKC2TupleTempl_HTLCOutputInCommitment__Signature { typedef LDKC2TupleTempl_HTLCOutputInCommitment__Signature LDKC2Tuple_HTLCOutputInCommitmentSignatureZ; + + +/** + * An Err type for failure to process messages. + */ +typedef struct MUST_USE_STRUCT LDKLightningError { + /** + * Nearly everywhere, inner must be non-null, however in places where + * the Rust equivalent takes an Option, it may be set to null to indicate None. + */ + LDKnativeLightningError *inner; + bool is_owned; +} LDKLightningError; + +typedef union LDKCResultPtr_u8__LightningError { + uint8_t *result; + LDKLightningError *err; +} LDKCResultPtr_u8__LightningError; + +typedef struct LDKCResultTempl_u8__LightningError { + LDKCResultPtr_u8__LightningError contents; + bool result_ok; +} LDKCResultTempl_u8__LightningError; + +typedef LDKCResultTempl_u8__LightningError LDKCResult_NoneLightningErrorZ; + typedef struct LDKPublicKey { uint8_t compressed_form[33]; } LDKPublicKey; @@ -2641,20 +2667,6 @@ typedef struct MUST_USE_STRUCT LDKGossipTimestampFilter { bool is_owned; } LDKGossipTimestampFilter; - - -/** - * An Err type for failure to process messages. - */ -typedef struct MUST_USE_STRUCT LDKLightningError { - /** - * Nearly everywhere, inner must be non-null, however in places where - * the Rust equivalent takes an Option, it may be set to null to indicate None. - */ - LDKnativeLightningError *inner; - bool is_owned; -} LDKLightningError; - typedef struct LDKCVecTempl_UpdateAddHTLC { LDKUpdateAddHTLC *data; uintptr_t datalen; @@ -3153,6 +3165,10 @@ extern const LDKCResult_NoneChannelMonitorUpdateErrZ (*CResult_NoneChannelMonito extern const void (*CResult_NoneChannelMonitorUpdateErrZ_free)(LDKCResult_NoneChannelMonitorUpdateErrZ); +extern const LDKCResult_NoneLightningErrorZ (*CResult_NoneLightningErrorZ_err)(LDKLightningError); + +extern const void (*CResult_NoneLightningErrorZ_free)(LDKCResult_NoneLightningErrorZ); + extern const LDKCResult_NoneMonitorUpdateErrorZ (*CResult_NoneMonitorUpdateErrorZ_err)(LDKMonitorUpdateError); extern const void (*CResult_NoneMonitorUpdateErrorZ_free)(LDKCResult_NoneMonitorUpdateErrorZ); @@ -3301,6 +3317,8 @@ LDKCResult_NonePeerHandleErrorZ CResult_NonePeerHandleErrorZ_ok(void); LDKC2Tuple_HTLCOutputInCommitmentSignatureZ C2Tuple_HTLCOutputInCommitmentSignatureZ_new(LDKHTLCOutputInCommitment a, LDKSignature b); +LDKCResult_NoneLightningErrorZ CResult_NoneLightningErrorZ_ok(void); + void Event_free(LDKEvent this_ptr); LDKEvent Event_clone(const LDKEvent *orig); @@ -7262,6 +7280,46 @@ LDKNetworkGraph NetworkGraph_read(LDKu8slice ser); */ MUST_USE_RES LDKNetworkGraph NetworkGraph_new(void); +/** + * For an already known node (from channel announcements), update its stored properties from a + * given node announcement. + * + * You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's + * 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. + */ +MUST_USE_RES LDKCResult_NoneLightningErrorZ NetworkGraph_update_node_from_announcement(LDKNetworkGraph *this_arg, const LDKNodeAnnouncement *msg); + +/** + * For an already known node (from channel announcements), update its stored properties from a + * given node announcement without verifying the associated signatures. Because we aren't + * given the associated signatures here we cannot relay the node announcement to any of our + * peers. + */ +MUST_USE_RES LDKCResult_NoneLightningErrorZ NetworkGraph_update_node_from_unsigned_announcement(LDKNetworkGraph *this_arg, const LDKUnsignedNodeAnnouncement *msg); + +/** + * Store or update channel info from a channel announcement. + * + * You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's + * 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. + * + * If a `chain::Access` object is provided via `chain_access`, it will be called to verify + * the corresponding UTXO exists on chain and is correctly-formatted. + */ +MUST_USE_RES LDKCResult_NoneLightningErrorZ NetworkGraph_update_channel_from_announcement(LDKNetworkGraph *this_arg, const LDKChannelAnnouncement *msg, LDKAccess *chain_access); + +/** + * Store or update channel info from a channel announcement without verifying the associated + * signatures. Because we aren't given the associated signatures here we cannot relay the + * channel announcement to any of our peers. + * + * If a `chain::Access` object is provided via `chain_access`, it will be called to verify + * the corresponding UTXO exists on chain and is correctly-formatted. + */ +MUST_USE_RES LDKCResult_NoneLightningErrorZ NetworkGraph_update_channel_from_unsigned_announcement(LDKNetworkGraph *this_arg, const LDKUnsignedChannelAnnouncement *msg, LDKAccess *chain_access); + /** * Close a channel if a corresponding HTLC fail was sent. * If permanent, removes a channel from the local storage. @@ -7270,4 +7328,21 @@ MUST_USE_RES LDKNetworkGraph NetworkGraph_new(void); */ void NetworkGraph_close_channel_from_update(LDKNetworkGraph *this_arg, uint64_t short_channel_id, bool is_permanent); +/** + * For an already known (from announcement) channel, update info about one of the directions + * of the channel. + * + * You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's + * 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. + */ +MUST_USE_RES LDKCResult_NoneLightningErrorZ NetworkGraph_update_channel(LDKNetworkGraph *this_arg, const LDKChannelUpdate *msg); + +/** + * For an already known (from announcement) channel, update info about one of the directions + * of the channel without verifying the associated signatures. Because we aren't given the + * associated signatures here we cannot relay the channel update to any of our peers. + */ +MUST_USE_RES LDKCResult_NoneLightningErrorZ NetworkGraph_update_channel_unsigned(LDKNetworkGraph *this_arg, const LDKUnsignedChannelUpdate *msg); + /* Text to put at the end of the generated file */ diff --git a/lightning-c-bindings/include/lightningpp.hpp b/lightning-c-bindings/include/lightningpp.hpp index 49e78e3841e..5f8b77f3f6e 100644 --- a/lightning-c-bindings/include/lightningpp.hpp +++ b/lightning-c-bindings/include/lightningpp.hpp @@ -1830,6 +1830,20 @@ class CResult_RouteLightningErrorZ { const LDKCResult_RouteLightningErrorZ* operator &() const { return &self; } const LDKCResult_RouteLightningErrorZ* operator ->() const { return &self; } }; +class CResult_NoneLightningErrorZ { +private: + LDKCResult_NoneLightningErrorZ self; +public: + CResult_NoneLightningErrorZ(const CResult_NoneLightningErrorZ&) = delete; + ~CResult_NoneLightningErrorZ() { CResult_NoneLightningErrorZ_free(self); } + CResult_NoneLightningErrorZ(CResult_NoneLightningErrorZ&& o) : self(o.self) { memset(&o, 0, sizeof(CResult_NoneLightningErrorZ)); } + CResult_NoneLightningErrorZ(LDKCResult_NoneLightningErrorZ&& m_self) : self(m_self) { memset(&m_self, 0, sizeof(LDKCResult_NoneLightningErrorZ)); } + operator LDKCResult_NoneLightningErrorZ() { LDKCResult_NoneLightningErrorZ res = self; memset(&self, 0, sizeof(LDKCResult_NoneLightningErrorZ)); return res; } + LDKCResult_NoneLightningErrorZ* operator &() { return &self; } + LDKCResult_NoneLightningErrorZ* operator ->() { return &self; } + const LDKCResult_NoneLightningErrorZ* operator &() const { return &self; } + const LDKCResult_NoneLightningErrorZ* operator ->() const { return &self; } +}; class CResult_CVec_SignatureZNoneZ { private: LDKCResult_CVec_SignatureZNoneZ self; diff --git a/lightning-c-bindings/src/c_types/derived.rs b/lightning-c-bindings/src/c_types/derived.rs index fd77e0d4cf1..38139e0e0b9 100644 --- a/lightning-c-bindings/src/c_types/derived.rs +++ b/lightning-c-bindings/src/c_types/derived.rs @@ -400,3 +400,16 @@ pub static CResult_RouteLightningErrorZ_ok: extern "C" fn (crate::routing::route pub static CResult_RouteLightningErrorZ_err: extern "C" fn (crate::ln::msgs::LightningError) -> CResult_RouteLightningErrorZ = crate::c_types::CResultTempl::::err; +#[no_mangle] +pub type CResult_NoneLightningErrorZ = crate::c_types::CResultTempl; +#[no_mangle] +pub static CResult_NoneLightningErrorZ_free: extern "C" fn(CResult_NoneLightningErrorZ) = crate::c_types::CResultTempl_free::; +#[no_mangle] +pub extern "C" fn CResult_NoneLightningErrorZ_ok() -> CResult_NoneLightningErrorZ { + crate::c_types::CResultTempl::ok(0) +} + +#[no_mangle] +pub static CResult_NoneLightningErrorZ_err: extern "C" fn (crate::ln::msgs::LightningError) -> CResult_NoneLightningErrorZ = + crate::c_types::CResultTempl::::err; + diff --git a/lightning-c-bindings/src/routing/network_graph.rs b/lightning-c-bindings/src/routing/network_graph.rs index 11eb92a363a..b4c8de585c5 100644 --- a/lightning-c-bindings/src/routing/network_graph.rs +++ b/lightning-c-bindings/src/routing/network_graph.rs @@ -826,6 +826,64 @@ pub extern "C" fn NetworkGraph_new() -> crate::routing::network_graph::NetworkGr crate::routing::network_graph::NetworkGraph { inner: Box::into_raw(Box::new(ret)), is_owned: true } } +/// For an already known node (from channel announcements), update its stored properties from a +/// given node announcement. +/// +/// You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's +/// 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. +#[must_use] +#[no_mangle] +pub extern "C" fn NetworkGraph_update_node_from_announcement(this_arg: &mut NetworkGraph, msg: &crate::ln::msgs::NodeAnnouncement) -> crate::c_types::derived::CResult_NoneLightningErrorZ { + let mut ret = unsafe { &mut (*(this_arg.inner as *mut nativeNetworkGraph)) }.update_node_from_announcement(unsafe { &*msg.inner }, &bitcoin::secp256k1::Secp256k1::new()); + let mut local_ret = match ret { Ok(mut o) => crate::c_types::CResultTempl::ok( { 0u8 /*o*/ }), Err(mut e) => crate::c_types::CResultTempl::err( { crate::ln::msgs::LightningError { inner: Box::into_raw(Box::new(e)), is_owned: true } }) }; + local_ret +} + +/// For an already known node (from channel announcements), update its stored properties from a +/// given node announcement without verifying the associated signatures. Because we aren't +/// given the associated signatures here we cannot relay the node announcement to any of our +/// peers. +#[must_use] +#[no_mangle] +pub extern "C" fn NetworkGraph_update_node_from_unsigned_announcement(this_arg: &mut NetworkGraph, msg: &crate::ln::msgs::UnsignedNodeAnnouncement) -> crate::c_types::derived::CResult_NoneLightningErrorZ { + let mut ret = unsafe { &mut (*(this_arg.inner as *mut nativeNetworkGraph)) }.update_node_from_unsigned_announcement(unsafe { &*msg.inner }); + let mut local_ret = match ret { Ok(mut o) => crate::c_types::CResultTempl::ok( { 0u8 /*o*/ }), Err(mut e) => crate::c_types::CResultTempl::err( { crate::ln::msgs::LightningError { inner: Box::into_raw(Box::new(e)), is_owned: true } }) }; + local_ret +} + +/// Store or update channel info from a channel announcement. +/// +/// You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's +/// 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. +/// +/// If a `chain::Access` object is provided via `chain_access`, it will be called to verify +/// the corresponding UTXO exists on chain and is correctly-formatted. +#[must_use] +#[no_mangle] +pub extern "C" fn NetworkGraph_update_channel_from_announcement(this_arg: &mut NetworkGraph, msg: &crate::ln::msgs::ChannelAnnouncement, chain_access: *mut crate::chain::Access) -> crate::c_types::derived::CResult_NoneLightningErrorZ { + let mut local_chain_access = if chain_access == std::ptr::null_mut() { None } else { Some( { unsafe { *Box::from_raw(chain_access) } }) }; + let mut ret = unsafe { &mut (*(this_arg.inner as *mut nativeNetworkGraph)) }.update_channel_from_announcement(unsafe { &*msg.inner }, &local_chain_access, &bitcoin::secp256k1::Secp256k1::new()); + let mut local_ret = match ret { Ok(mut o) => crate::c_types::CResultTempl::ok( { 0u8 /*o*/ }), Err(mut e) => crate::c_types::CResultTempl::err( { crate::ln::msgs::LightningError { inner: Box::into_raw(Box::new(e)), is_owned: true } }) }; + local_ret +} + +/// Store or update channel info from a channel announcement without verifying the associated +/// signatures. Because we aren't given the associated signatures here we cannot relay the +/// channel announcement to any of our peers. +/// +/// If a `chain::Access` object is provided via `chain_access`, it will be called to verify +/// the corresponding UTXO exists on chain and is correctly-formatted. +#[must_use] +#[no_mangle] +pub extern "C" fn NetworkGraph_update_channel_from_unsigned_announcement(this_arg: &mut NetworkGraph, msg: &crate::ln::msgs::UnsignedChannelAnnouncement, chain_access: *mut crate::chain::Access) -> crate::c_types::derived::CResult_NoneLightningErrorZ { + let mut local_chain_access = if chain_access == std::ptr::null_mut() { None } else { Some( { unsafe { *Box::from_raw(chain_access) } }) }; + let mut ret = unsafe { &mut (*(this_arg.inner as *mut nativeNetworkGraph)) }.update_channel_from_unsigned_announcement(unsafe { &*msg.inner }, &local_chain_access); + let mut local_ret = match ret { Ok(mut o) => crate::c_types::CResultTempl::ok( { 0u8 /*o*/ }), Err(mut e) => crate::c_types::CResultTempl::err( { crate::ln::msgs::LightningError { inner: Box::into_raw(Box::new(e)), is_owned: true } }) }; + local_ret +} + /// Close a channel if a corresponding HTLC fail was sent. /// If permanent, removes a channel from the local storage. /// May cause the removal of nodes too, if this was their last channel. @@ -835,3 +893,28 @@ pub extern "C" fn NetworkGraph_close_channel_from_update(this_arg: &mut NetworkG unsafe { &mut (*(this_arg.inner as *mut nativeNetworkGraph)) }.close_channel_from_update(short_channel_id, is_permanent) } +/// For an already known (from announcement) channel, update info about one of the directions +/// of the channel. +/// +/// You probably don't want to call this directly, instead relying on a NetGraphMsgHandler's +/// 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. +#[must_use] +#[no_mangle] +pub extern "C" fn NetworkGraph_update_channel(this_arg: &mut NetworkGraph, msg: &crate::ln::msgs::ChannelUpdate) -> crate::c_types::derived::CResult_NoneLightningErrorZ { + let mut ret = unsafe { &mut (*(this_arg.inner as *mut nativeNetworkGraph)) }.update_channel(unsafe { &*msg.inner }, &bitcoin::secp256k1::Secp256k1::new()); + let mut local_ret = match ret { Ok(mut o) => crate::c_types::CResultTempl::ok( { 0u8 /*o*/ }), Err(mut e) => crate::c_types::CResultTempl::err( { crate::ln::msgs::LightningError { inner: Box::into_raw(Box::new(e)), is_owned: true } }) }; + local_ret +} + +/// For an already known (from announcement) channel, update info about one of the directions +/// of the channel without verifying the associated signatures. Because we aren't given the +/// associated signatures here we cannot relay the channel update to any of our peers. +#[must_use] +#[no_mangle] +pub extern "C" fn NetworkGraph_update_channel_unsigned(this_arg: &mut NetworkGraph, msg: &crate::ln::msgs::UnsignedChannelUpdate) -> crate::c_types::derived::CResult_NoneLightningErrorZ { + let mut ret = unsafe { &mut (*(this_arg.inner as *mut nativeNetworkGraph)) }.update_channel_unsigned(unsafe { &*msg.inner }); + let mut local_ret = match ret { Ok(mut o) => crate::c_types::CResultTempl::ok( { 0u8 /*o*/ }), Err(mut e) => crate::c_types::CResultTempl::err( { crate::ln::msgs::LightningError { inner: Box::into_raw(Box::new(e)), is_owned: true } }) }; + local_ret +} +