From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Tue, 24 Nov 2020 22:14:16 +0000 (-0800) Subject: Merge pull request #759 from TheBlueMatt/2020-11-0.0.12 X-Git-Tag: v0.0.12 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=refs%2Ftags%2Fv0.0.12;hp=4aa8e9cda761fab2d4b2ac18d590de7a22dd9285;p=rust-lightning Merge pull request #759 from TheBlueMatt/2020-11-0.0.12 Bump version to 0.0.12 --- diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8c1f2fd0..00000000 --- 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 diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index ef7669f1..671adcfd 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,30 +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 val = slice_to_be64(get_slice!(8)); - let _ = net_graph.update_channel_from_announcement::(&msg, Some(val), 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-c-bindings/include/lightning.h b/lightning-c-bindings/include/lightning.h index 45e4fa3a..61548022 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 49e78e38..5f8b77f3 100644 --- a/lightning-c-bindings/include/lightningpp.hpp +++ b/lightning-c-bindings/include/lightningpp.hpp @@ -1830,6 +1830,20 @@ public: 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 fd77e0d4..38139e0e 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 11eb92a3..b4c8de58 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 +} + diff --git a/lightning/src/routing/network_graph.rs b/lightning/src/routing/network_graph.rs index 932f3779..54783dd1 100644 --- a/lightning/src/routing/network_graph.rs +++ b/lightning/src/routing/network_graph.rs @@ -121,52 +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 { - 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)); + 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); @@ -178,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)> { @@ -562,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(()) } } } @@ -603,44 +580,84 @@ 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 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. + pub fn update_channel_from_announcement + (&mut self, msg: &msgs::ChannelAnnouncement, chain_access: &Option, secp_ctx: &Secp256k1) + -> Result<(), LightningError> + where C::Target: chain::Access { + 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. /// - /// 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 { - 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}); - } + /// 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 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.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.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 { + 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.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 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 @@ -654,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}) @@ -669,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, }); @@ -682,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. @@ -717,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}); } @@ -748,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; @@ -756,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 }; @@ -778,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); } @@ -797,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); @@ -832,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) { @@ -1178,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(),