Merge pull request #895 from valentinewallace/invoice-chanman-utility
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Thu, 29 Apr 2021 23:55:37 +0000 (23:55 +0000)
committerGitHub <noreply@github.com>
Thu, 29 Apr 2021 23:55:37 +0000 (23:55 +0000)
Invoice chanman utility

27 files changed:
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
lightning-background-processor/Cargo.toml
lightning-invoice/Cargo.toml
lightning-invoice/src/de.rs
lightning-invoice/src/lib.rs
lightning-invoice/src/ser.rs
lightning-invoice/src/utils.rs [new file with mode: 0644]
lightning-invoice/tests/ser_de.rs
lightning-persister/Cargo.toml
lightning/Cargo.toml
lightning/src/chain/channelmonitor.rs
lightning/src/chain/keysinterface.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/chanmon_update_fail_tests.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/mod.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onchaintx.rs
lightning/src/ln/onion_route_tests.rs
lightning/src/ln/onion_utils.rs
lightning/src/util/events.rs
lightning/src/util/ser.rs
lightning/src/util/test_utils.rs

index 4df23f0fc479e99e554571fb6529cd28a1368f87..b48604dbac7e4a29cf1201c7d65f5a262a2dc3be 100644 (file)
@@ -37,7 +37,8 @@ use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr,
 use lightning::chain::transaction::OutPoint;
 use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
 use lightning::chain::keysinterface::{KeysInterface, InMemorySigner};
-use lightning::ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret, PaymentSendFailure, ChannelManagerReadArgs};
+use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
+use lightning::ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs};
 use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
 use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, DecodeError, ErrorAction, UpdateAddHTLC, Init};
 use lightning::util::enforcing_trait_impls::{EnforcingSigner, INITIAL_REVOKED_COMMITMENT_NUMBER};
@@ -55,6 +56,7 @@ use utils::test_logger;
 use utils::test_persister::TestPersister;
 
 use bitcoin::secp256k1::key::{PublicKey,SecretKey};
+use bitcoin::secp256k1::recovery::RecoverableSignature;
 use bitcoin::secp256k1::Secp256k1;
 
 use std::mem;
@@ -205,6 +207,10 @@ impl KeysInterface for KeyProvider {
                        disable_revocation_policy_check: false,
                })
        }
+
+       fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
+               unreachable!()
+       }
 }
 
 impl KeyProvider {
index 85e6e5156a23d893bcf71c3f5d6329a1d83603dd..55fae3a8592b5529dd139fdd0c1a91da3d9b9e15 100644 (file)
@@ -32,7 +32,8 @@ use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget,
 use lightning::chain::chainmonitor;
 use lightning::chain::transaction::OutPoint;
 use lightning::chain::keysinterface::{InMemorySigner, KeysInterface};
-use lightning::ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret};
+use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
+use lightning::ln::channelmanager::{BestBlock, ChainParameters, ChannelManager};
 use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
 use lightning::ln::msgs::DecodeError;
 use lightning::routing::router::get_route;
@@ -47,6 +48,7 @@ use utils::test_logger;
 use utils::test_persister::TestPersister;
 
 use bitcoin::secp256k1::key::{PublicKey,SecretKey};
+use bitcoin::secp256k1::recovery::RecoverableSignature;
 use bitcoin::secp256k1::Secp256k1;
 
 use std::cell::RefCell;
@@ -312,6 +314,10 @@ impl KeysInterface for KeyProvider {
        fn read_chan_signer(&self, data: &[u8]) -> Result<EnforcingSigner, DecodeError> {
                EnforcingSigner::read(&mut std::io::Cursor::new(data))
        }
+
+       fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
+               unreachable!()
+       }
 }
 
 #[inline]
index 89ac216816121a3be55040a47570b28b2b6a57e6..eec9da19015980dd22605af72e948420f6193b2a 100644 (file)
@@ -17,6 +17,3 @@ lightning-persister = { version = "0.0.13", path = "../lightning-persister" }
 [dev-dependencies]
 lightning = { version = "0.0.13", path = "../lightning", features = ["_test_utils"] }
 
-[dev-dependencies.bitcoin]
-version = "0.26"
-features = ["bitcoinconsensus"]
index 758578ca465b5f6cf57e29440e5439002c0ced64..75d9755ad3fd85c8ae152f2ef0e55380b1b2135d 100644 (file)
@@ -15,6 +15,9 @@ secp256k1 = { version = "0.20", features = ["recovery"] }
 num-traits = "0.2.8"
 bitcoin_hashes = "0.9.4"
 
+[dev-dependencies]
+lightning = { version = "0.0.13", path = "../lightning", features = ["_test_utils"] }
+
 [lib]
 crate-type = ["cdylib", "rlib"]
 
index 52a2201bdfd4c16eefb4e4d51d5d9ae0730a812a..4b38c89ec9444932daac0f224567dae1e749282b 100644 (file)
@@ -10,6 +10,7 @@ use bech32::{u5, FromBase32};
 
 use bitcoin_hashes::Hash;
 use bitcoin_hashes::sha256;
+use lightning::ln::PaymentSecret;
 use lightning::routing::network_graph::RoutingFees;
 use lightning::routing::router::RouteHintHop;
 
@@ -484,21 +485,6 @@ impl FromBase32 for PayeePubKey {
        }
 }
 
-impl FromBase32 for PaymentSecret {
-       type Err = ParseError;
-
-       fn from_base32(field_data: &[u5]) -> Result<PaymentSecret, ParseError> {
-               if field_data.len() != 52 {
-                       Err(ParseError::Skip)
-               } else {
-                       let data_bytes = Vec::<u8>::from_base32(field_data)?;
-                       let mut payment_secret = [0; 32];
-                       payment_secret.copy_from_slice(&data_bytes);
-                       Ok(PaymentSecret(payment_secret))
-               }
-       }
-}
-
 impl FromBase32 for ExpiryTime {
        type Err = ParseError;
 
index b33b1b374d85b1bea79e5d38a984b7be36e8b0d0..29d221e94ad591e2283f1bfa325bb5b7c60b4db5 100644 (file)
@@ -14,6 +14,7 @@
 //!   * For parsing use `str::parse::<Invoice>(&self)` (see the docs of `impl FromStr for Invoice`)
 //!   * For constructing invoices use the `InvoiceBuilder`
 //!   * For serializing invoices use the `Display`/`ToString` traits
+pub mod utils;
 
 extern crate bech32;
 extern crate bitcoin_hashes;
@@ -24,6 +25,7 @@ extern crate secp256k1;
 use bech32::u5;
 use bitcoin_hashes::Hash;
 use bitcoin_hashes::sha256;
+use lightning::ln::PaymentSecret;
 use lightning::ln::features::InvoiceFeatures;
 #[cfg(any(doc, test))]
 use lightning::routing::network_graph::RoutingFees;
@@ -32,12 +34,12 @@ use lightning::routing::router::RouteHintHop;
 use secp256k1::key::PublicKey;
 use secp256k1::{Message, Secp256k1};
 use secp256k1::recovery::RecoverableSignature;
-use std::ops::Deref;
 
+use std::fmt::{Display, Formatter, self};
 use std::iter::FilterMap;
+use std::ops::Deref;
 use std::slice::Iter;
 use std::time::{SystemTime, Duration, UNIX_EPOCH};
-use std::fmt::{Display, Formatter, self};
 
 mod de;
 mod ser;
@@ -358,10 +360,6 @@ pub struct Description(String);
 #[derive(Eq, PartialEq, Debug, Clone)]
 pub struct PayeePubKey(pub PublicKey);
 
-/// 256-bit payment secret
-#[derive(Eq, PartialEq, Debug, Clone)]
-pub struct PaymentSecret(pub [u8; 32]);
-
 /// Positive duration that defines when (relatively to the timestamp) in the future the invoice
 /// expires
 ///
@@ -731,8 +729,8 @@ macro_rules! find_extract {
 
 #[allow(missing_docs)]
 impl RawInvoice {
-       /// Hash the HRP as bytes and signatureless data part.
-       fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
+       /// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
+       pub(crate) fn construct_invoice_preimage(hrp_bytes: &[u8], data_without_signature: &[u5]) -> Vec<u8> {
                use bech32::FromBase32;
 
                let mut preimage = Vec::<u8>::from(hrp_bytes);
@@ -751,7 +749,12 @@ impl RawInvoice {
 
                preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
                        .expect("No padding error may occur due to appended zero above."));
+               preimage
+       }
 
+       /// Hash the HRP as bytes and signatureless data part.
+       fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
+               let preimage = RawInvoice::construct_invoice_preimage(hrp_bytes, data_without_signature);
                let mut hash: [u8; 32] = Default::default();
                hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
                hash
index cfc4313b94b3561779430409fcd375afb0fa7ce2..8f0ff31b904b78b42f4708ea3af8c4b7fd099a04 100644 (file)
@@ -297,18 +297,6 @@ impl Base32Len for PayeePubKey {
        }
 }
 
-impl ToBase32 for PaymentSecret {
-       fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
-               (&self.0[..]).write_base32(writer)
-       }
-}
-
-impl Base32Len for PaymentSecret {
-       fn base32_len(&self) -> usize {
-               bytes_size_to_base32_size(32)
-       }
-}
-
 impl ToBase32 for ExpiryTime {
        fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
                writer.write(&encode_int_be_base32(self.as_seconds()))
diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs
new file mode 100644 (file)
index 0000000..b90aad8
--- /dev/null
@@ -0,0 +1,157 @@
+//! Convenient utilities to create an invoice.
+use {Currency, Invoice, InvoiceBuilder, SignOrCreationError, RawInvoice};
+use bech32::ToBase32;
+use bitcoin_hashes::Hash;
+use lightning::chain;
+use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
+use lightning::chain::keysinterface::{Sign, KeysInterface};
+use lightning::ln::channelmanager::{ChannelManager, MIN_FINAL_CLTV_EXPIRY};
+use lightning::ln::features::InvoiceFeatures;
+use lightning::routing::network_graph::RoutingFees;
+use lightning::routing::router::RouteHintHop;
+use lightning::util::logger::Logger;
+use std::ops::Deref;
+
+/// Utility to construct an invoice. Generally, unless you want to do something like a custom
+/// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
+/// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
+/// doesn't have to store preimage/payment secret information and (b) `ChannelManager` can verify
+/// that the payment secret is valid when the invoice is paid.
+pub fn create_invoice_from_channelmanager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
+       channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
+       amt_msat: Option<u64>, description: String
+) -> Result<Invoice, SignOrCreationError<()>>
+where
+       M::Target: chain::Watch<Signer>,
+       T::Target: BroadcasterInterface,
+       K::Target: KeysInterface<Signer = Signer>,
+       F::Target: FeeEstimator,
+       L::Target: Logger,
+{
+       // Marshall route hints.
+       let our_channels = channelmanager.list_usable_channels();
+       let mut route_hints = vec![];
+       for channel in our_channels {
+               let short_channel_id = match channel.short_channel_id {
+                       Some(id) => id,
+                       None => continue,
+               };
+               let forwarding_info = match channel.counterparty_forwarding_info {
+                       Some(info) => info,
+                       None => continue,
+               };
+               route_hints.push(vec![RouteHintHop {
+                       src_node_id: channel.remote_network_id,
+                       short_channel_id,
+                       fees: RoutingFees {
+                               base_msat: forwarding_info.fee_base_msat,
+                               proportional_millionths: forwarding_info.fee_proportional_millionths,
+                       },
+                       cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
+                       htlc_minimum_msat: None,
+                       htlc_maximum_msat: None,
+               }]);
+       }
+
+       let (payment_hash, payment_secret) = channelmanager.create_inbound_payment(
+               amt_msat,
+               7200, // default invoice expiry is 2 hours
+               0,
+       );
+       let our_node_pubkey = channelmanager.get_our_node_id();
+       let mut invoice = InvoiceBuilder::new(network)
+               .description(description)
+               .current_timestamp()
+               .payee_pub_key(our_node_pubkey)
+               .payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
+               .payment_secret(payment_secret)
+               .features(InvoiceFeatures::known())
+               .min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into());
+       if let Some(amt) = amt_msat {
+               invoice = invoice.amount_pico_btc(amt * 10);
+       }
+       for hint in route_hints.drain(..) {
+               invoice = invoice.route(hint);
+       }
+
+       let raw_invoice = match invoice.build_raw() {
+               Ok(inv) => inv,
+               Err(e) => return Err(SignOrCreationError::CreationError(e))
+       };
+       let hrp_str = raw_invoice.hrp.to_string();
+       let hrp_bytes = hrp_str.as_bytes();
+       let data_without_signature = raw_invoice.data.to_base32();
+       let invoice_preimage = RawInvoice::construct_invoice_preimage(hrp_bytes, &data_without_signature);
+       let signed_raw_invoice = raw_invoice.sign(|_| keys_manager.sign_invoice(invoice_preimage));
+       match signed_raw_invoice {
+               Ok(inv) => Ok(Invoice::from_signed(inv).unwrap()),
+               Err(e) => Err(SignOrCreationError::SignError(e))
+       }
+}
+
+#[cfg(test)]
+mod test {
+       use {Currency, Description, InvoiceDescription};
+       use lightning::ln::PaymentHash;
+       use lightning::ln::functional_test_utils::*;
+       use lightning::ln::features::InitFeatures;
+       use lightning::ln::msgs::ChannelMessageHandler;
+       use lightning::routing::router;
+       use lightning::util::events::MessageSendEventsProvider;
+       use lightning::util::test_utils;
+       #[test]
+       fn test_from_channelmanager() {
+               let chanmon_cfgs = create_chanmon_cfgs(2);
+               let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+               let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+               let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+               let _chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+               let invoice = ::utils::create_invoice_from_channelmanager(&nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000), "test".to_string()).unwrap();
+               assert_eq!(invoice.amount_pico_btc(), Some(100_000));
+               assert_eq!(invoice.min_final_cltv_expiry(), Some(9));
+               assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
+
+               let mut route_hints = invoice.routes().clone();
+               let mut last_hops = Vec::new();
+               for hint in route_hints.drain(..) {
+                       last_hops.push(hint[hint.len() - 1].clone());
+               }
+               let amt_msat = invoice.amount_pico_btc().unwrap() / 10;
+
+               let first_hops = nodes[0].node.list_usable_channels();
+               let network_graph = nodes[0].net_graph_msg_handler.network_graph.read().unwrap();
+               let logger = test_utils::TestLogger::new();
+               let route = router::get_route(
+                       &nodes[0].node.get_our_node_id(),
+                       &network_graph,
+                       &invoice.recover_payee_pub_key(),
+                       Some(invoice.features().unwrap().clone()),
+                       Some(&first_hops.iter().collect::<Vec<_>>()),
+                       &last_hops.iter().collect::<Vec<_>>(),
+                       amt_msat,
+                       invoice.min_final_cltv_expiry().unwrap() as u32,
+                       &logger,
+               ).unwrap();
+
+               let payment_event = {
+                       let mut payment_hash = PaymentHash([0; 32]);
+                       payment_hash.0.copy_from_slice(&invoice.payment_hash().as_ref()[0..32]);
+                       nodes[0].node.send_payment(&route, payment_hash, &Some(invoice.payment_secret().unwrap().clone())).unwrap();
+                       let mut added_monitors = nodes[0].chain_monitor.added_monitors.lock().unwrap();
+                       assert_eq!(added_monitors.len(), 1);
+                       added_monitors.clear();
+
+                       let mut events = nodes[0].node.get_and_clear_pending_msg_events();
+                       assert_eq!(events.len(), 1);
+                       SendEvent::from_event(events.remove(0))
+
+               };
+               nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
+               nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &payment_event.commitment_msg);
+               let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
+               assert_eq!(added_monitors.len(), 1);
+               added_monitors.clear();
+               let events = nodes[1].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 2);
+       }
+}
index 403f8f1f0ee9f4f9aa395ddf6f6e503ecc559897..cce8cca916a3afa6f85b7f7c28c34a902c434fb3 100644 (file)
@@ -1,9 +1,11 @@
 extern crate bitcoin_hashes;
+extern crate lightning;
 extern crate lightning_invoice;
 extern crate secp256k1;
 
 use bitcoin_hashes::hex::FromHex;
 use bitcoin_hashes::sha256;
+use lightning::ln::PaymentSecret;
 use lightning_invoice::*;
 use secp256k1::Secp256k1;
 use secp256k1::key::SecretKey;
index a6e7242b0cb9c13e0eae26ea6bb43063870eb8c1..6b69e9afe28b1d6ab435ba1fcffa9e08a0cce926 100644 (file)
@@ -19,9 +19,5 @@ libc = "0.2"
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["winbase"] }
 
-[dev-dependencies.bitcoin]
-version = "0.26"
-features = ["bitcoinconsensus"]
-
 [dev-dependencies]
 lightning = { version = "0.0.13", path = "../lightning", features = ["_test_utils"] }
index da9ac51a79f4acfd512c132c034d2e606650e5d8..73be5fff34da17f17dca0b213587418cf2bdbf08 100644 (file)
@@ -14,7 +14,7 @@ Still missing tons of error-handling. See GitHub issues for suggested projects i
 allow_wallclock_use = []
 fuzztarget = ["bitcoin/fuzztarget", "regex"]
 # Internal test utilities exposed to other repo crates
-_test_utils = ["hex", "regex"]
+_test_utils = ["hex", "regex", "bitcoin/bitcoinconsensus"]
 # Unlog messages superior at targeted level.
 max_level_off = []
 max_level_error = []
@@ -32,13 +32,13 @@ bitcoin = "0.26"
 hex = { version = "0.3", optional = true }
 regex = { version = "0.1.80", optional = true }
 
-[dev-dependencies.bitcoin]
-version = "0.26"
-features = ["bitcoinconsensus"]
-
 [dev-dependencies]
 hex = "0.3"
 regex = "0.1.80"
 
+[dev-dependencies.bitcoin]
+version = "0.26"
+features = ["bitcoinconsensus"]
+
 [package.metadata.docs.rs]
 features = ["allow_wallclock_use"] # When https://github.com/rust-lang/rust/issues/43781 complies with our MSVR, we can add nice banners in the docs for the methods behind this feature-gate.
index c68ee39bb47a9c1b01b7ec72c52604f356267962..f63e4d12d55adc59fa1f81270aea9f669d03a65f 100644 (file)
@@ -34,10 +34,11 @@ use bitcoin::secp256k1::{Secp256k1,Signature};
 use bitcoin::secp256k1::key::{SecretKey,PublicKey};
 use bitcoin::secp256k1;
 
+use ln::{PaymentHash, PaymentPreimage};
 use ln::msgs::DecodeError;
 use ln::chan_utils;
 use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCType, ChannelTransactionParameters, HolderCommitmentTransaction};
-use ln::channelmanager::{BestBlock, HTLCSource, PaymentPreimage, PaymentHash};
+use ln::channelmanager::{BestBlock, HTLCSource};
 use ln::onchaintx::{OnchainTxHandler, InputDescriptors};
 use chain;
 use chain::WatchedOutput;
@@ -3048,7 +3049,8 @@ mod tests {
        use hex;
        use chain::channelmonitor::ChannelMonitor;
        use chain::transaction::OutPoint;
-       use ln::channelmanager::{BestBlock, PaymentPreimage, PaymentHash};
+       use ln::{PaymentPreimage, PaymentHash};
+       use ln::channelmanager::BestBlock;
        use ln::onchaintx::{OnchainTxHandler, InputDescriptors};
        use ln::chan_utils;
        use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
index 02ee9b5f563b11ab095b592d0b68d866506efa73..366afe0db0969b9f757302b2df256c27767dec55 100644 (file)
@@ -26,6 +26,7 @@ use bitcoin::hash_types::WPubkeyHash;
 
 use bitcoin::secp256k1::key::{SecretKey, PublicKey};
 use bitcoin::secp256k1::{Secp256k1, Signature, Signing};
+use bitcoin::secp256k1::recovery::RecoverableSignature;
 use bitcoin::secp256k1;
 
 use util::{byte_utils, transaction_utils};
@@ -391,6 +392,12 @@ pub trait KeysInterface {
        /// contain no versioning scheme. You may wish to include your own version prefix and ensure
        /// you've read all of the provided bytes to ensure no corruption occurred.
        fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, DecodeError>;
+
+       /// Sign an invoice's preimage (note that this is the preimage of the invoice, not the HTLC's
+       /// preimage). By parameterizing by the preimage instead of the hash, we allow implementors of
+       /// this trait to parse the invoice and make sure they're signing what they expect, rather than
+       /// blindly signing the hash.
+       fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()>;
 }
 
 #[derive(Clone)]
@@ -1047,6 +1054,10 @@ impl KeysInterface for KeysManager {
        fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, DecodeError> {
                InMemorySigner::read(&mut std::io::Cursor::new(reader))
        }
+
+       fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
+               Ok(self.secp_ctx.sign_recoverable(&hash_to_message!(&Sha256::hash(&invoice_preimage)), &self.get_node_secret()))
+       }
 }
 
 // Ensure that BaseSign can have a vtable
index da7ba15a1ace67de30ca0e8a01b1173e9253f6ac..4438579657eecc74e6cf1cb9458b339c2db82292 100644 (file)
@@ -20,7 +20,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::hashes::ripemd160::Hash as Ripemd160;
 use bitcoin::hash_types::{Txid, PubkeyHash};
 
-use ln::channelmanager::{PaymentHash, PaymentPreimage};
+use ln::{PaymentHash, PaymentPreimage};
 use ln::msgs::DecodeError;
 use util::ser::{Readable, Writeable, Writer, MAX_BUF_SIZE};
 use util::byte_utils;
index 266f5b0aff7a0e11e11e301bb9e749940dd35418..d1da9f7ef3090300284152820d037b27ab8e8ea0 100644 (file)
@@ -19,7 +19,8 @@ use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr};
 use chain::transaction::OutPoint;
 use chain::Listen;
 use chain::Watch;
-use ln::channelmanager::{RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSendFailure};
+use ln::{PaymentPreimage, PaymentHash};
+use ln::channelmanager::{RAACommitmentOrder, PaymentSendFailure};
 use ln::features::{InitFeatures, InvoiceFeatures};
 use ln::msgs;
 use ln::msgs::{ChannelMessageHandler, ErrorAction, RoutingMessageHandler};
index 8a1489d4ef775c7be7d515bcc3153895437eb726..fc59c29d7043e72f169931c46ab02aa0e01db364 100644 (file)
@@ -21,10 +21,11 @@ use bitcoin::secp256k1::key::{PublicKey,SecretKey};
 use bitcoin::secp256k1::{Secp256k1,Signature};
 use bitcoin::secp256k1;
 
+use ln::{PaymentPreimage, PaymentHash};
 use ln::features::{ChannelFeatures, InitFeatures};
 use ln::msgs;
 use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
-use ln::channelmanager::{BestBlock, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
+use ln::channelmanager::{BestBlock, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
 use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor};
 use ln::chan_utils;
 use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
@@ -4824,7 +4825,8 @@ mod tests {
        use bitcoin::network::constants::Network;
        use bitcoin::hashes::hex::FromHex;
        use hex;
-       use ln::channelmanager::{BestBlock, HTLCSource, PaymentPreimage, PaymentHash};
+       use ln::{PaymentPreimage, PaymentHash};
+       use ln::channelmanager::{BestBlock, HTLCSource};
        use ln::channel::{Channel,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys};
        use ln::channel::MAX_FUNDING_SATOSHIS;
        use ln::features::InitFeatures;
@@ -4841,6 +4843,7 @@ mod tests {
        use bitcoin::secp256k1::{Secp256k1, Message, Signature, All};
        use bitcoin::secp256k1::ffi::Signature as FFISignature;
        use bitcoin::secp256k1::key::{SecretKey,PublicKey};
+       use bitcoin::secp256k1::recovery::RecoverableSignature;
        use bitcoin::hashes::sha256::Hash as Sha256;
        use bitcoin::hashes::Hash;
        use bitcoin::hash_types::{Txid, WPubkeyHash};
@@ -4886,6 +4889,7 @@ mod tests {
                }
                fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }
                fn read_chan_signer(&self, _data: &[u8]) -> Result<Self::Signer, DecodeError> { panic!(); }
+               fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> { panic!(); }
        }
 
        fn public_from_secret_hex(secp_ctx: &Secp256k1<All>, hex: &str) -> PublicKey {
index 439c9b93c27af37858a783147dd796f5b6aa7746..a9f87fa149ccfdde8f09e4ee6e01c6d375ab4cf9 100644 (file)
@@ -43,6 +43,7 @@ use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitor
 use chain::transaction::{OutPoint, TransactionData};
 // Since this struct is returned in `list_channels` methods, expose it here in case users want to
 // construct one themselves.
+use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 pub use ln::channel::CounterpartyForwardingInfo;
 use ln::channel::{Channel, ChannelError};
 use ln::features::{InitFeatures, NodeFeatures};
@@ -196,19 +197,6 @@ pub(super) enum HTLCFailReason {
        }
 }
 
-/// payment_hash type, use to cross-lock hop
-/// (C-not exported) as we just use [u8; 32] directly
-#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
-pub struct PaymentHash(pub [u8;32]);
-/// payment_preimage type, use to route payment between hop
-/// (C-not exported) as we just use [u8; 32] directly
-#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
-pub struct PaymentPreimage(pub [u8;32]);
-/// payment_secret type, use to authenticate sender to the receiver and tie MPP HTLCs together
-/// (C-not exported) as we just use [u8; 32] directly
-#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
-pub struct PaymentSecret(pub [u8;32]);
-
 type ShutdownResult = (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash)>);
 
 /// Error type returned across the channel_state mutex boundary. When an Err is generated for a
index 49db3b1158a361260bbe408f01b363f44f177f1f..60f5dabe91b52f007608c9c0dcc237c5f35ade96 100644 (file)
@@ -13,7 +13,8 @@
 use chain::{Confirm, Listen, Watch};
 use chain::channelmonitor::ChannelMonitor;
 use chain::transaction::OutPoint;
-use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure};
+use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure};
 use routing::router::{Route, get_route};
 use routing::network_graph::{NetGraphMsgHandler, NetworkGraph};
 use ln::features::{InitFeatures, InvoiceFeatures};
index 13eddf02f23776914000b37b2cefc5f1c7365064..6d6e0937c54625c6bb975978923009f90e1faf72 100644 (file)
@@ -18,8 +18,9 @@ use chain::channelmonitor;
 use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
 use chain::transaction::OutPoint;
 use chain::keysinterface::{KeysInterface, BaseSign};
+use ln::{PaymentPreimage, PaymentSecret, PaymentHash};
 use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
-use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentSecret, PaymentHash, PaymentSendFailure, BREAKDOWN_TIMEOUT};
+use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT};
 use ln::channel::{Channel, ChannelError};
 use ln::{chan_utils, onion_utils};
 use routing::router::{Route, RouteHop, get_route};
index 3827cea84e0a3d983c8946bf9703fa5f9ff6826c..d093b849a94ece8cdc9870ae98d6cd9f64888abb 100644 (file)
@@ -55,3 +55,46 @@ mod reorg_tests;
 mod onion_route_tests;
 
 pub use self::peer_channel_encryptor::LN_MAX_MSG_LEN;
+
+/// payment_hash type, use to cross-lock hop
+/// (C-not exported) as we just use [u8; 32] directly
+#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
+pub struct PaymentHash(pub [u8;32]);
+/// payment_preimage type, use to route payment between hop
+/// (C-not exported) as we just use [u8; 32] directly
+#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
+pub struct PaymentPreimage(pub [u8;32]);
+/// payment_secret type, use to authenticate sender to the receiver and tie MPP HTLCs together
+/// (C-not exported) as we just use [u8; 32] directly
+#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
+pub struct PaymentSecret(pub [u8;32]);
+
+use bitcoin::bech32;
+use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, WriteBase32, u5};
+
+impl FromBase32 for PaymentSecret {
+       type Err = bech32::Error;
+
+       fn from_base32(field_data: &[u5]) -> Result<PaymentSecret, bech32::Error> {
+               if field_data.len() != 52 {
+                       return Err(bech32::Error::InvalidLength)
+               } else {
+                       let data_bytes = Vec::<u8>::from_base32(field_data)?;
+                       let mut payment_secret = [0; 32];
+                       payment_secret.copy_from_slice(&data_bytes);
+                       Ok(PaymentSecret(payment_secret))
+               }
+       }
+}
+
+impl ToBase32 for PaymentSecret {
+       fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
+               (&self.0[..]).write_base32(writer)
+       }
+}
+
+impl Base32Len for PaymentSecret {
+       fn base32_len(&self) -> usize {
+               52
+       }
+}
index 5cb72842a85faa3ee557a51563a68d1665cd1b36..974e30095109e3647e2acd006ce36bad03e9e928 100644 (file)
@@ -39,7 +39,7 @@ use std::io::Read;
 use util::events::MessageSendEventsProvider;
 use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt};
 
-use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret};
+use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 
 /// 21 million * 10^8 * 1000
 pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
@@ -854,7 +854,7 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider {
 }
 
 mod fuzzy_internal_msgs {
-       use ln::channelmanager::PaymentSecret;
+       use ln::PaymentSecret;
 
        // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
        // them from untrusted input):
@@ -1813,9 +1813,9 @@ impl Writeable for GossipTimestampFilter {
 #[cfg(test)]
 mod tests {
        use hex;
+       use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use ln::msgs;
        use ln::msgs::{ChannelFeatures, FinalOnionHopData, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket, OnionHopDataFormat};
-       use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret};
        use util::ser::{Writeable, Readable};
 
        use bitcoin::hashes::hex::FromHex;
index 8e531b501c3c0ede233154596e08d340a39aef35..e154e5f8f226d73a6a2604bc0fae8d9823ac632c 100644 (file)
@@ -22,7 +22,7 @@ use bitcoin::secp256k1::{Secp256k1, Signature};
 use bitcoin::secp256k1;
 
 use ln::msgs::DecodeError;
-use ln::channelmanager::PaymentPreimage;
+use ln::PaymentPreimage;
 use ln::chan_utils;
 use ln::chan_utils::{TxCreationKeys, ChannelTransactionParameters, HolderCommitmentTransaction};
 use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
index 24dc1f5a62b48d22fbf495e9da5f534083b6bc73..6f178d2136e30be5c9b4e03a6ea6612f3c575191 100644 (file)
@@ -12,7 +12,8 @@
 //! returned errors decode to the correct thing.
 
 use chain::channelmonitor::{CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
-use ln::channelmanager::{HTLCForwardInfo, PaymentPreimage, PaymentHash, PaymentSecret};
+use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+use ln::channelmanager::HTLCForwardInfo;
 use ln::onion_utils;
 use routing::router::{Route, get_route};
 use ln::features::{InitFeatures, InvoiceFeatures};
index 8feef1697af40ad33032afe23b7bf5f77e8a6b21..6d9118e21a8e38529e4ab5f93f8109c5b21a1363 100644 (file)
@@ -7,7 +7,8 @@
 // You may not use this file except in accordance with one or both of these
 // licenses.
 
-use ln::channelmanager::{PaymentHash, PaymentSecret, HTLCSource};
+use ln::{PaymentHash, PaymentSecret};
+use ln::channelmanager::HTLCSource;
 use ln::msgs;
 use routing::router::RouteHop;
 use util::byte_utils;
@@ -477,7 +478,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing, L: Deref>(secp_ctx: &
 
 #[cfg(test)]
 mod tests {
-       use ln::channelmanager::PaymentHash;
+       use ln::PaymentHash;
        use ln::features::{ChannelFeatures, NodeFeatures};
        use routing::router::{Route, RouteHop};
        use ln::msgs;
index ac0fc3c89dcc484a9cd37a71745f41225598940d..798f562526fa8acbba55e4353e94c08b03d50980 100644 (file)
@@ -15,7 +15,7 @@
 //! few other things.
 
 use ln::msgs;
-use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret};
+use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 use chain::keysinterface::SpendableOutputDescriptor;
 use util::ser::{Writeable, Writer, MaybeReadable, Readable};
 
index 1a055701fe3929a9cdcbdf2451571dfb205923ef..c31fcaa1ff6de28eb450f770182414145cda1909 100644 (file)
@@ -27,7 +27,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
 use bitcoin::hash_types::{Txid, BlockHash};
 use std::marker::Sized;
 use ln::msgs::DecodeError;
-use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret};
+use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 use util::byte_utils;
 
 use util::byte_utils::{be64_to_array, be48_to_array, be32_to_array, be16_to_array, slice_to_be16, slice_to_be32, slice_to_be48, slice_to_be64};
index 153f2f28eed11ffe7e55536c98c191714edb6443..00c346a80cb8c48c31f6aae7e61f527647df82ba 100644 (file)
@@ -32,6 +32,7 @@ use bitcoin::network::constants::Network;
 use bitcoin::hash_types::{BlockHash, Txid};
 
 use bitcoin::secp256k1::{SecretKey, PublicKey, Secp256k1, Signature};
+use bitcoin::secp256k1::recovery::RecoverableSignature;
 
 use regex;
 
@@ -75,6 +76,7 @@ impl keysinterface::KeysInterface for OnlyReadsKeysInterface {
        fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, msgs::DecodeError> {
                EnforcingSigner::read(&mut std::io::Cursor::new(reader))
        }
+       fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> { unreachable!(); }
 }
 
 pub struct TestChainMonitor<'a> {
@@ -483,6 +485,10 @@ impl keysinterface::KeysInterface for TestKeysInterface {
                        disable_revocation_policy_check: self.disable_revocation_policy_check,
                })
        }
+
+       fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
+               self.backing.sign_invoice(invoice_preimage)
+       }
 }