From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Thu, 29 Apr 2021 23:55:37 +0000 (+0000) Subject: Merge pull request #895 from valentinewallace/invoice-chanman-utility X-Git-Tag: v0.0.14~6 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=3b67be235a46d8f9a9a6faf7ca7c5872ffbd8646;hp=3be185ad13408da141ec3d7a6396f6f7625aaca2;p=rust-lightning Merge pull request #895 from valentinewallace/invoice-chanman-utility Invoice chanman utility --- diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 4df23f0f..b48604db 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -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) -> Result { + unreachable!() + } } impl KeyProvider { diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 85e6e515..55fae3a8 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -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::read(&mut std::io::Cursor::new(data)) } + + fn sign_invoice(&self, _invoice_preimage: Vec) -> Result { + unreachable!() + } } #[inline] diff --git a/lightning-background-processor/Cargo.toml b/lightning-background-processor/Cargo.toml index 89ac2168..eec9da19 100644 --- a/lightning-background-processor/Cargo.toml +++ b/lightning-background-processor/Cargo.toml @@ -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"] diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index 758578ca..75d9755a 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -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"] diff --git a/lightning-invoice/src/de.rs b/lightning-invoice/src/de.rs index 52a2201b..4b38c89e 100644 --- a/lightning-invoice/src/de.rs +++ b/lightning-invoice/src/de.rs @@ -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 { - if field_data.len() != 52 { - Err(ParseError::Skip) - } else { - let data_bytes = Vec::::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; diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index b33b1b37..29d221e9 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -14,6 +14,7 @@ //! * For parsing use `str::parse::(&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 { use bech32::FromBase32; let mut preimage = Vec::::from(hrp_bytes); @@ -751,7 +749,12 @@ impl RawInvoice { preimage.extend_from_slice(&Vec::::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 diff --git a/lightning-invoice/src/ser.rs b/lightning-invoice/src/ser.rs index cfc4313b..8f0ff31b 100644 --- a/lightning-invoice/src/ser.rs +++ b/lightning-invoice/src/ser.rs @@ -297,18 +297,6 @@ impl Base32Len for PayeePubKey { } } -impl ToBase32 for PaymentSecret { - fn write_base32(&self, writer: &mut W) -> Result<(), ::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(&self, writer: &mut W) -> Result<(), ::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 index 00000000..b90aad82 --- /dev/null +++ b/lightning-invoice/src/utils.rs @@ -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( + channelmanager: &ChannelManager, keys_manager: K, network: Currency, + amt_msat: Option, description: String +) -> Result> +where + M::Target: chain::Watch, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + 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::>()), + &last_hops.iter().collect::>(), + 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); + } +} diff --git a/lightning-invoice/tests/ser_de.rs b/lightning-invoice/tests/ser_de.rs index 403f8f1f..cce8cca9 100644 --- a/lightning-invoice/tests/ser_de.rs +++ b/lightning-invoice/tests/ser_de.rs @@ -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; diff --git a/lightning-persister/Cargo.toml b/lightning-persister/Cargo.toml index a6e7242b..6b69e9af 100644 --- a/lightning-persister/Cargo.toml +++ b/lightning-persister/Cargo.toml @@ -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"] } diff --git a/lightning/Cargo.toml b/lightning/Cargo.toml index da9ac51a..73be5fff 100644 --- a/lightning/Cargo.toml +++ b/lightning/Cargo.toml @@ -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. diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index c68ee39b..f63e4d12 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -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}; diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 02ee9b5f..366afe0d 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -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; + + /// 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) -> Result; } #[derive(Clone)] @@ -1047,6 +1054,10 @@ impl KeysInterface for KeysManager { fn read_chan_signer(&self, reader: &[u8]) -> Result { InMemorySigner::read(&mut std::io::Cursor::new(reader)) } + + fn sign_invoice(&self, invoice_preimage: Vec) -> Result { + Ok(self.secp_ctx.sign_recoverable(&hash_to_message!(&Sha256::hash(&invoice_preimage)), &self.get_node_secret())) + } } // Ensure that BaseSign can have a vtable diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index da7ba15a..44385796 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -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; diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index 266f5b0a..d1da9f7e 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -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}; diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 8a1489d4..fc59c29d 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -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 { panic!(); } + fn sign_invoice(&self, _invoice_preimage: Vec) -> Result { panic!(); } } fn public_from_secret_hex(secp_ctx: &Secp256k1, hex: &str) -> PublicKey { diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 439c9b93..a9f87fa1 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -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 diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 49db3b11..60f5dabe 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -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}; diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 13eddf02..6d6e0937 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -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}; diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 3827cea8..d093b849 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -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 { + if field_data.len() != 52 { + return Err(bech32::Error::InvalidLength) + } else { + let data_bytes = Vec::::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(&self, writer: &mut W) -> Result<(), ::Err> { + (&self.0[..]).write_base32(writer) + } +} + +impl Base32Len for PaymentSecret { + fn base32_len(&self) -> usize { + 52 + } +} diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 5cb72842..974e3009 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -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; diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 8e531b50..e154e5f8 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -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}; diff --git a/lightning/src/ln/onion_route_tests.rs b/lightning/src/ln/onion_route_tests.rs index 24dc1f5a..6f178d21 100644 --- a/lightning/src/ln/onion_route_tests.rs +++ b/lightning/src/ln/onion_route_tests.rs @@ -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}; diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 8feef169..6d9118e2 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -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(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; diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index ac0fc3c8..798f5625 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -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}; diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 1a055701..c31fcaa1 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -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}; diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 153f2f28..00c346a8 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -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 { EnforcingSigner::read(&mut std::io::Cursor::new(reader)) } + fn sign_invoice(&self, _invoice_preimage: Vec) -> Result { 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) -> Result { + self.backing.sign_invoice(invoice_preimage) + } }