use lightning::ln::msgs::DecodeError;
use lightning::ln::script::ShutdownScript;
use lightning::routing::network_graph::{NetGraphMsgHandler, NetworkGraph};
-use lightning::routing::router::{find_route, Payee, RouteParameters};
+use lightning::routing::router::{find_route, PaymentParameters, RouteParameters};
use lightning::routing::scoring::Scorer;
use lightning::util::config::UserConfig;
use lightning::util::errors::APIError;
use std::cmp;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicU64,AtomicUsize,Ordering};
+ use bitcoin::bech32::u5;
#[inline]
pub fn slice_to_be16(v: &[u8]) -> u16 {
))
}
- fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
+ fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5]) -> Result<RecoverableSignature, ()> {
unreachable!()
}
}
},
4 => {
let final_value_msat = slice_to_be24(get_slice!(3)) as u64;
- let payee = Payee::from_node_id(get_pubkey!());
+ let payment_params = PaymentParameters::from_node_id(get_pubkey!());
let params = RouteParameters {
- payee,
+ payment_params,
final_value_msat,
final_cltv_expiry_delta: 42,
};
},
15 => {
let final_value_msat = slice_to_be24(get_slice!(3)) as u64;
- let payee = Payee::from_node_id(get_pubkey!());
+ let payment_params = PaymentParameters::from_node_id(get_pubkey!());
let params = RouteParameters {
- payee,
+ payment_params,
final_value_msat,
final_cltv_expiry_delta: 42,
};
//! Convenient utilities to create an invoice.
- use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError, RawInvoice};
+ use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError};
use payment::{Payer, Router};
use bech32::ToBase32;
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));
+ let signed_raw_invoice = raw_invoice.sign(|_| keys_manager.sign_invoice(hrp_bytes, &data_without_signature));
match signed_raw_invoice {
Ok(inv) => Ok(Invoice::from_signed(inv).unwrap()),
Err(e) => Err(SignOrCreationError::SignError(e))
use lightning::ln::functional_test_utils::*;
use lightning::ln::features::InitFeatures;
use lightning::ln::msgs::ChannelMessageHandler;
- use lightning::routing::router::{Payee, RouteParameters, find_route};
+ use lightning::routing::router::{PaymentParameters, RouteParameters, find_route};
use lightning::util::events::MessageSendEventsProvider;
use lightning::util::test_utils;
use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
- let payee = Payee::from_node_id(invoice.recover_payee_pub_key())
+ let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
.with_features(invoice.features().unwrap().clone())
.with_route_hints(invoice.route_hints());
- let params = RouteParameters {
- payee,
+ let route_params = RouteParameters {
+ payment_params,
final_value_msat: invoice.amount_milli_satoshis().unwrap(),
final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
};
let logger = test_utils::TestLogger::new();
let scorer = test_utils::TestScorer::with_fixed_penalty(0);
let route = find_route(
- &nodes[0].node.get_our_node_id(), ¶ms, network_graph,
+ &nodes[0].node.get_our_node_id(), &route_params, network_graph,
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer,
).unwrap();
use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber};
use bitcoin::util::bip143;
+ use bitcoin::bech32::u5;
use bitcoin::hashes::{Hash, HashEngine};
use bitcoin::hashes::sha256::HashEngine as Sha256State;
use bitcoin::hashes::sha256::Hash as Sha256;
use core::sync::atomic::{AtomicUsize, Ordering};
use io::{self, Error};
use ln::msgs::{DecodeError, MAX_VALUE_MSAT};
+ use util::invoice::construct_invoice_preimage;
/// Used as initial key material, to be expanded into multiple secret keys (but not to be used
/// directly). This is used within LDK to encrypt/decrypt inbound payment data.
/// 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
+ /// Sign an invoice.
+ /// By parameterizing by the raw invoice bytes 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, ()>;
+ /// The hrp is ascii bytes, while the invoice data is base32.
+ fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result<RecoverableSignature, ()>;
/// Get secret key material as bytes for use in encrypting and decrypting inbound payment data.
///
/// described by descriptor, returning the witness stack for the input.
///
/// Returns an Err if the input at input_idx does not exist, has a non-empty script_sig,
- /// or is not spending the outpoint described by `descriptor.outpoint`.
+ /// is not spending the outpoint described by `descriptor.outpoint`,
+ /// or if an output descriptor script_pubkey does not match the one we can spend.
pub fn sign_counterparty_payment_input<C: Signing>(&self, spend_tx: &Transaction, input_idx: usize, descriptor: &StaticPaymentOutputDescriptor, secp_ctx: &Secp256k1<C>) -> Result<Vec<Vec<u8>>, ()> {
// TODO: We really should be taking the SigHashCache as a parameter here instead of
// spend_tx, but ideally the SigHashCache would expose the transaction's inputs read-only
let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Testnet).script_pubkey();
let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]);
let remotesig = secp_ctx.sign(&sighash, &self.payment_key);
+ let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey();
+
+ if payment_script != descriptor.output.script_pubkey { return Err(()); }
let mut witness = Vec::with_capacity(2);
witness.push(remotesig.serialize_der().to_vec());
/// described by descriptor, returning the witness stack for the input.
///
/// Returns an Err if the input at input_idx does not exist, has a non-empty script_sig,
- /// is not spending the outpoint described by `descriptor.outpoint`, or does not have a
- /// sequence set to `descriptor.to_self_delay`.
+ /// is not spending the outpoint described by `descriptor.outpoint`, does not have a
+ /// sequence set to `descriptor.to_self_delay`, or if an output descriptor
+ /// script_pubkey does not match the one we can spend.
pub fn sign_dynamic_p2wsh_input<C: Signing>(&self, spend_tx: &Transaction, input_idx: usize, descriptor: &DelayedPaymentOutputDescriptor, secp_ctx: &Secp256k1<C>) -> Result<Vec<Vec<u8>>, ()> {
// TODO: We really should be taking the SigHashCache as a parameter here instead of
// spend_tx, but ideally the SigHashCache would expose the transaction's inputs read-only
let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey);
let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]);
let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key);
+ let payment_script = bitcoin::Address::p2wsh(&witness_script, Network::Bitcoin).script_pubkey();
+
+ if descriptor.output.script_pubkey != payment_script { return Err(()); }
let mut witness = Vec::with_capacity(3);
witness.push(local_delayedsig.serialize_der().to_vec());
/// output to the given change destination (if sufficient change value remains). The
/// transaction will have a feerate, at least, of the given value.
///
- /// Returns `Err(())` if the output value is greater than the input value minus required fee or
- /// if a descriptor was duplicated.
+ /// Returns `Err(())` if the output value is greater than the input value minus required fee,
+ /// if a descriptor was duplicated, or if an output descriptor script_pubkey
+ /// does not match the one we can spend.
///
/// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
///
self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id),
descriptor.channel_keys_id));
}
- spend_tx.input[input_idx].witness = keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&spend_tx, input_idx, &descriptor, &secp_ctx).unwrap();
+ spend_tx.input[input_idx].witness = keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?;
},
SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id {
self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id),
descriptor.channel_keys_id));
}
- spend_tx.input[input_idx].witness = keys_cache.as_ref().unwrap().0.sign_dynamic_p2wsh_input(&spend_tx, input_idx, &descriptor, &secp_ctx).unwrap();
+ spend_tx.input[input_idx].witness = keys_cache.as_ref().unwrap().0.sign_dynamic_p2wsh_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?;
},
SpendableOutputDescriptor::StaticOutput { ref output, .. } => {
let derivation_idx = if output.script_pubkey == self.destination_script {
assert_eq!(pubkey.key, self.shutdown_pubkey);
}
let witness_script = bitcoin::Address::p2pkh(&pubkey, Network::Testnet).script_pubkey();
+ let payment_script = bitcoin::Address::p2wpkh(&pubkey, Network::Testnet).expect("uncompressed key found").script_pubkey();
+
+ if payment_script != output.script_pubkey { return Err(()); };
+
let sighash = hash_to_message!(&bip143::SigHashCache::new(&spend_tx).signature_hash(input_idx, &witness_script, output.value, SigHashType::All)[..]);
let sig = secp_ctx.sign(&sighash, &secret.private_key.key);
spend_tx.input[input_idx].witness.push(sig.serialize_der().to_vec());
InMemorySigner::read(&mut 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()))
+ fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result<RecoverableSignature, ()> {
+ let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data);
+ Ok(self.secp_ctx.sign_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &self.get_node_secret()))
}
}