mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 07:17:40 +01:00
inbound_payment: Add utility to get payment preimage given hash/secret
User-requested feature
This commit is contained in:
parent
d734ad814e
commit
41cfd833f1
2 changed files with 60 additions and 1 deletions
|
@ -73,12 +73,14 @@ use core::ops::Deref;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
mod inbound_payment {
|
mod inbound_payment {
|
||||||
|
use alloc::string::ToString;
|
||||||
use bitcoin::hashes::{Hash, HashEngine};
|
use bitcoin::hashes::{Hash, HashEngine};
|
||||||
use bitcoin::hashes::cmp::fixed_time_eq;
|
use bitcoin::hashes::cmp::fixed_time_eq;
|
||||||
use bitcoin::hashes::hmac::{Hmac, HmacEngine};
|
use bitcoin::hashes::hmac::{Hmac, HmacEngine};
|
||||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||||
use chain::keysinterface::{KeyMaterial, KeysInterface, Sign};
|
use chain::keysinterface::{KeyMaterial, KeysInterface, Sign};
|
||||||
use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
|
use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
|
||||||
|
use ln::channelmanager::APIError;
|
||||||
use ln::msgs;
|
use ln::msgs;
|
||||||
use ln::msgs::MAX_VALUE_MSAT;
|
use ln::msgs::MAX_VALUE_MSAT;
|
||||||
use util::chacha20::ChaCha20;
|
use util::chacha20::ChaCha20;
|
||||||
|
@ -288,6 +290,23 @@ mod inbound_payment {
|
||||||
Ok(payment_preimage)
|
Ok(payment_preimage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_payment_preimage(payment_hash: PaymentHash, payment_secret: PaymentSecret, keys: &ExpandedKey) -> Result<PaymentPreimage, APIError> {
|
||||||
|
let (iv_bytes, metadata_bytes) = decrypt_metadata(payment_secret, keys);
|
||||||
|
|
||||||
|
match Method::from_bits((metadata_bytes[0] & 0b1110_0000) >> METHOD_TYPE_OFFSET) {
|
||||||
|
Ok(Method::LdkPaymentHash) => {
|
||||||
|
derive_ldk_payment_preimage(payment_hash, &iv_bytes, &metadata_bytes, keys)
|
||||||
|
.map_err(|bad_preimage_bytes| APIError::APIMisuseError {
|
||||||
|
err: format!("Payment hash {} did not match decoded preimage {}", log_bytes!(payment_hash.0), log_bytes!(bad_preimage_bytes))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Ok(Method::UserPaymentHash) => Err(APIError::APIMisuseError {
|
||||||
|
err: "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash".to_string()
|
||||||
|
}),
|
||||||
|
Err(other) => Err(APIError::APIMisuseError { err: format!("Unknown payment type: {}", other) }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn decrypt_metadata(payment_secret: PaymentSecret, keys: &ExpandedKey) -> ([u8; IV_LEN], [u8; METADATA_LEN]) {
|
fn decrypt_metadata(payment_secret: PaymentSecret, keys: &ExpandedKey) -> ([u8; IV_LEN], [u8; METADATA_LEN]) {
|
||||||
let mut iv_bytes = [0; IV_LEN];
|
let mut iv_bytes = [0; IV_LEN];
|
||||||
let (iv_slice, encrypted_metadata_bytes) = payment_secret.0.split_at(IV_LEN);
|
let (iv_slice, encrypted_metadata_bytes) = payment_secret.0.split_at(IV_LEN);
|
||||||
|
@ -5097,6 +5116,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
|
||||||
self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs)
|
self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets an LDK-generated payment preimage from a payment hash and payment secret that were
|
||||||
|
/// previously returned from [`create_inbound_payment`].
|
||||||
|
///
|
||||||
|
/// [`create_inbound_payment`]: Self::create_inbound_payment
|
||||||
|
pub fn get_payment_preimage(&self, payment_hash: PaymentHash, payment_secret: PaymentSecret) -> Result<PaymentPreimage, APIError> {
|
||||||
|
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
|
#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
|
||||||
pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
|
pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
|
||||||
let events = core::cell::RefCell::new(Vec::new());
|
let events = core::cell::RefCell::new(Vec::new());
|
||||||
|
|
|
@ -15,9 +15,10 @@ use chain::{ChannelMonitorUpdateErr, Confirm, Listen, Watch};
|
||||||
use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS};
|
use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS};
|
||||||
use chain::transaction::OutPoint;
|
use chain::transaction::OutPoint;
|
||||||
use ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, PaymentId, PaymentSendFailure};
|
use ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, PaymentId, PaymentSendFailure};
|
||||||
use ln::features::InitFeatures;
|
use ln::features::{InitFeatures, InvoiceFeatures};
|
||||||
use ln::msgs;
|
use ln::msgs;
|
||||||
use ln::msgs::ChannelMessageHandler;
|
use ln::msgs::ChannelMessageHandler;
|
||||||
|
use routing::router::{Payee, get_route};
|
||||||
use util::events::{ClosureReason, Event, MessageSendEvent, MessageSendEventsProvider};
|
use util::events::{ClosureReason, Event, MessageSendEvent, MessageSendEventsProvider};
|
||||||
use util::test_utils;
|
use util::test_utils;
|
||||||
use util::errors::APIError;
|
use util::errors::APIError;
|
||||||
|
@ -706,3 +707,34 @@ fn test_fulfill_restart_failure() {
|
||||||
// it had already considered the payment fulfilled, and now they just got free money.
|
// it had already considered the payment fulfilled, and now they just got free money.
|
||||||
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
|
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_ldk_payment_preimage() {
|
||||||
|
// Ensure that `ChannelManager::get_payment_preimage` can successfully be used to claim a payment.
|
||||||
|
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 mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
|
||||||
|
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
|
||||||
|
|
||||||
|
let amt_msat = 60_000;
|
||||||
|
let expiry_secs = 60 * 60;
|
||||||
|
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(amt_msat), expiry_secs).unwrap();
|
||||||
|
|
||||||
|
let payee = Payee::from_node_id(nodes[1].node.get_our_node_id())
|
||||||
|
.with_features(InvoiceFeatures::known());
|
||||||
|
let scorer = test_utils::TestScorer::with_fixed_penalty(0);
|
||||||
|
let route = get_route(
|
||||||
|
&nodes[0].node.get_our_node_id(), &payee, &nodes[0].network_graph,
|
||||||
|
Some(&nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
|
||||||
|
amt_msat, TEST_FINAL_CLTV, nodes[0].logger, &scorer).unwrap();
|
||||||
|
let _payment_id = nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
|
||||||
|
check_added_monitors!(nodes[0], 1);
|
||||||
|
|
||||||
|
// Make sure to use `get_payment_preimage`
|
||||||
|
let payment_preimage = nodes[1].node.get_payment_preimage(payment_hash, payment_secret).unwrap();
|
||||||
|
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
|
||||||
|
assert_eq!(events.len(), 1);
|
||||||
|
pass_along_path(&nodes[0], &[&nodes[1]], amt_msat, payment_hash, Some(payment_secret), events.pop().unwrap(), true, Some(payment_preimage));
|
||||||
|
claim_payment_along_route(&nodes[0], &[&[&nodes[1]]], false, payment_preimage);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue