From: Matt Corallo Date: Tue, 27 Apr 2021 01:29:39 +0000 (+0000) Subject: Add a `user_payment_id` to `get_payment_secret`+`PaymentReceived` X-Git-Tag: v0.0.14~12^2~7 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=210b887d7c31a2a6e1c9a770218a99155eb18ab7;p=rust-lightning Add a `user_payment_id` to `get_payment_secret`+`PaymentReceived` This allows users to store metadata about an invoice at invoice-generation time and then index into that storage with a general-purpose id when they call `get_payment_secret`. They will then be provided the same index when the payment has been received. --- diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index bdd8b4e95..8ff741c72 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -266,7 +266,7 @@ fn get_payment_secret_hash(dest: &ChanMan, payment_id: &mut u8) -> Option<(Payme let mut payment_hash; for _ in 0..256 { payment_hash = PaymentHash(Sha256::hash(&[*payment_id; 1]).into_inner()); - if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 7200) { + if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 7200, 0) { return Some((payment_secret, payment_hash)); } *payment_id = payment_id.wrapping_add(1); @@ -687,7 +687,7 @@ pub fn do_test(data: &[u8], out: Out) { let had_events = !events.is_empty(); for event in events.drain(..) { match event { - events::Event::PaymentReceived { payment_hash, payment_secret, amt } => { + events::Event::PaymentReceived { payment_hash, payment_secret, amt, user_payment_id: _ } => { if claim_set.insert(payment_hash.0) { if $fail { assert!(nodes[$node].fail_htlc_backwards(&payment_hash, &payment_secret)); diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 8543555c1..be9294c1d 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -497,7 +497,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { let payment_hash = PaymentHash(Sha256::from_engine(sha).into_inner()); // Note that this may fail - our hashes may collide and we'll end up trying to // double-register the same payment_hash. - let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1); + let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1, 0); }, 9 => { for (payment, payment_secret, _) in payments_received.drain(..) { @@ -580,7 +580,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { Event::FundingGenerationReady { temporary_channel_id, channel_value_satoshis, output_script, .. } => { pending_funding_generation.push((temporary_channel_id, channel_value_satoshis, output_script)); }, - Event::PaymentReceived { payment_hash, payment_secret, amt } => { + Event::PaymentReceived { payment_hash, payment_secret, amt, user_payment_id: _ } => { //TODO: enhance by fetching random amounts from fuzz input? payments_received.push((payment_hash, payment_secret, amt)); }, diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index 3563e463b..1994cf1d6 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -206,7 +206,7 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool, persister_fail let events_3 = nodes[1].node.get_and_clear_pending_events(); assert_eq!(events_3.len(), 1); match events_3[0] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt, user_payment_id: _ } => { assert_eq!(payment_hash_1, *payment_hash); assert_eq!(Some(payment_secret_1), *payment_secret); assert_eq!(amt, 1000000); @@ -574,7 +574,7 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) { let events_5 = nodes[1].node.get_and_clear_pending_events(); assert_eq!(events_5.len(), 1); match events_5[0] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt, user_payment_id: _ } => { assert_eq!(payment_hash_2, *payment_hash); assert_eq!(Some(payment_secret_2), *payment_secret); assert_eq!(amt, 1000000); @@ -688,7 +688,7 @@ fn test_monitor_update_fail_cs() { let events = nodes[1].node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::PaymentReceived { payment_hash, payment_secret, amt } => { + Event::PaymentReceived { payment_hash, payment_secret, amt, user_payment_id: _ } => { assert_eq!(payment_hash, our_payment_hash); assert_eq!(Some(our_payment_secret), payment_secret); assert_eq!(amt, 1000000); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 672cc2205..bfe7ee39e 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -362,6 +362,8 @@ struct PendingInboundPayment { /// Time at which this HTLC expires - blocks with a header time above this value will result in /// this payment being removed. expiry_time: u64, + /// Arbitrary identifier the user specifies (or not) + user_payment_id: u64, // Other required attributes of the payment, optionally enforced: payment_preimage: Option, min_value_msat: Option, @@ -2024,6 +2026,7 @@ impl ChannelMana payment_hash, payment_secret: Some(payment_data.payment_secret), amt: total_value, + user_payment_id: inbound_payment.get().user_payment_id, }); // Only ever generate at most one PaymentReceived // per registered payment_hash, even if it isn't @@ -3377,7 +3380,7 @@ impl ChannelMana } } - fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { + fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option, min_value_msat: Option, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result { assert!(invoice_expiry_delta_secs <= 60*60*24*365); // Sadly bitcoin timestamps are u32s, so panic before 2106 let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes()); @@ -3387,7 +3390,7 @@ impl ChannelMana match payment_secrets.entry(payment_hash) { hash_map::Entry::Vacant(e) => { e.insert(PendingInboundPayment { - payment_secret, min_value_msat, payment_preimage, + payment_secret, min_value_msat, user_payment_id, payment_preimage, // We assume that highest_seen_timestamp is pretty close to the current time - // its updated when we receive a new block with the maximum time we've seen in // a header. It should never be more than two hours in the future. @@ -3412,12 +3415,12 @@ impl ChannelMana /// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements. /// /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash - pub fn create_inbound_payment(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> (PaymentHash, PaymentSecret) { + pub fn create_inbound_payment(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> (PaymentHash, PaymentSecret) { let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes()); let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); (payment_hash, - self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs) + self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs, user_payment_id) .expect("RNG Generated Duplicate PaymentHash")) } @@ -3431,6 +3434,12 @@ impl ChannelMana /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) must be globally unique. This /// method may return an Err if another payment with the same payment_hash is still pending. /// + /// `user_payment_id` will be provided back in [`PaymentReceived::user_payment_id`] events to + /// allow tracking of which events correspond with which calls to this and + /// [`create_inbound_payment`]. `user_payment_id` has no meaning inside of LDK, it is simply + /// copied to events and otherwise ignored. It may be used to correlate PaymentReceived events + /// with invoice metadata stored elsewhere. + /// /// `min_value_msat` should be set if the invoice being generated contains a value. Any payment /// received for the returned [`PaymentHash`] will be required to be at least `min_value_msat` /// before a [`PaymentReceived`] event will be generated, ensuring that we do not provide the @@ -3452,8 +3461,9 @@ impl ChannelMana /// /// [`create_inbound_payment`]: Self::create_inbound_payment /// [`PaymentReceived`]: events::Event::PaymentReceived - pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { - self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs) + /// [`PaymentReceived::user_payment_id`]: events::Event::PaymentReceived::user_payment_id + pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result { + self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs, user_payment_id) } } @@ -4280,6 +4290,7 @@ impl Readable for HTLCForwardInfo { impl_writeable!(PendingInboundPayment, 0, { payment_secret, expiry_time, + user_payment_id, payment_preimage, min_value_msat }); @@ -4824,7 +4835,7 @@ pub mod bench { payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes()); payment_count += 1; let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()); - let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200).unwrap(); + let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, 0).unwrap(); $node_a.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap(); let payment_event = SendEvent::from_event($node_a.get_and_clear_pending_msg_events().pop().unwrap()); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index a76c3fd5a..5b79cba05 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -899,7 +899,7 @@ macro_rules! get_payment_preimage_hash { let payment_preimage = PaymentPreimage([*$dest_node.network_payment_count.borrow(); 32]); *$dest_node.network_payment_count.borrow_mut() += 1; let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()); - let payment_secret = $dest_node.node.create_inbound_payment_for_hash(payment_hash, None, 7200).unwrap(); + let payment_secret = $dest_node.node.create_inbound_payment_for_hash(payment_hash, None, 7200, 0).unwrap(); (payment_preimage, payment_hash, payment_secret) } } @@ -941,7 +941,7 @@ macro_rules! expect_payment_received { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt, user_payment_id: _ } => { assert_eq!($expected_payment_hash, *payment_hash); assert_eq!(Some($expected_payment_secret), *payment_secret); assert_eq!($expected_recv_value, amt); @@ -1009,7 +1009,7 @@ pub fn pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path if payment_received_expected { assert_eq!(events_2.len(), 1); match events_2[0] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt, user_payment_id: _ } => { assert_eq!(our_payment_hash, *payment_hash); assert_eq!(Some(our_payment_secret), *payment_secret); assert_eq!(amt, recv_value); diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 0e3e3f01e..1f5dcb8fe 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -1470,7 +1470,7 @@ fn test_duplicate_htlc_different_direction_onchain() { let net_graph_msg_handler = &nodes[1].net_graph_msg_handler; let route = get_route(&nodes[1].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[0].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 800_000, TEST_FINAL_CLTV, &logger).unwrap(); - let node_a_payment_secret = nodes[0].node.create_inbound_payment_for_hash(payment_hash, None, 7200).unwrap(); + let node_a_payment_secret = nodes[0].node.create_inbound_payment_for_hash(payment_hash, None, 7200, 0).unwrap(); send_along_route_with_secret(&nodes[1], route, &[&[&nodes[0]]], 800_000, payment_hash, node_a_payment_secret); // Provide preimage to node 0 by claiming payment @@ -2070,7 +2070,7 @@ fn test_channel_reserve_holding_cell_htlcs() { let events = nodes[2].node.get_and_clear_pending_events(); assert_eq!(events.len(), 2); match events[0] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt, user_payment_id: _ } => { assert_eq!(our_payment_hash_21, *payment_hash); assert_eq!(Some(our_payment_secret_21), *payment_secret); assert_eq!(recv_value_21, amt); @@ -2078,7 +2078,7 @@ fn test_channel_reserve_holding_cell_htlcs() { _ => panic!("Unexpected event"), } match events[1] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt, user_payment_id: _ } => { assert_eq!(our_payment_hash_22, *payment_hash); assert_eq!(Some(our_payment_secret_22), *payment_secret); assert_eq!(recv_value_22, amt); @@ -3646,7 +3646,7 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8) { let events_2 = nodes[1].node.get_and_clear_pending_events(); assert_eq!(events_2.len(), 1); match events_2[0] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt, user_payment_id: _ } => { assert_eq!(payment_hash_1, *payment_hash); assert_eq!(Some(payment_secret_1), *payment_secret); assert_eq!(amt, 1000000); @@ -3983,7 +3983,7 @@ fn test_drop_messages_peer_disconnect_dual_htlc() { let events_5 = nodes[1].node.get_and_clear_pending_events(); assert_eq!(events_5.len(), 1); match events_5[0] { - Event::PaymentReceived { ref payment_hash, ref payment_secret, amt: _ } => { + Event::PaymentReceived { ref payment_hash, ref payment_secret, amt: _, user_payment_id: _ } => { assert_eq!(payment_hash_2, *payment_hash); assert_eq!(Some(payment_secret_2), *payment_secret); }, @@ -5113,7 +5113,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() { let (our_payment_preimage, duplicate_payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 900000); - let payment_secret = nodes[3].node.create_inbound_payment_for_hash(duplicate_payment_hash, None, 7200).unwrap(); + let payment_secret = nodes[3].node.create_inbound_payment_for_hash(duplicate_payment_hash, None, 7200, 0).unwrap(); let route = get_route(&nodes[0].node.get_our_node_id(), &nodes[0].net_graph_msg_handler.network_graph.read().unwrap(), &nodes[3].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 900000, TEST_FINAL_CLTV, nodes[0].logger).unwrap(); send_along_route_with_secret(&nodes[0], route, &[&[&nodes[1], &nodes[2], &nodes[3]]], 900000, duplicate_payment_hash, payment_secret); @@ -5307,30 +5307,30 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno let our_node_id = &nodes[1].node.get_our_node_id(); let route = get_route(our_node_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[5].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), ds_dust_limit*1000, TEST_FINAL_CLTV, &logger).unwrap(); // 2nd HTLC: - send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_1, nodes[5].node.create_inbound_payment_for_hash(payment_hash_1, None, 7200).unwrap()); // not added < dust limit + HTLC tx fee + send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_1, nodes[5].node.create_inbound_payment_for_hash(payment_hash_1, None, 7200, 0).unwrap()); // not added < dust limit + HTLC tx fee // 3rd HTLC: - send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_2, nodes[5].node.create_inbound_payment_for_hash(payment_hash_2, None, 7200).unwrap()); // not added < dust limit + HTLC tx fee + send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_2, nodes[5].node.create_inbound_payment_for_hash(payment_hash_2, None, 7200, 0).unwrap()); // not added < dust limit + HTLC tx fee // 4th HTLC: let (_, payment_hash_3, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 1000000); // 5th HTLC: let (_, payment_hash_4, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 1000000); let route = get_route(our_node_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[5].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 1000000, TEST_FINAL_CLTV, &logger).unwrap(); // 6th HTLC: - send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_3, nodes[5].node.create_inbound_payment_for_hash(payment_hash_3, None, 7200).unwrap()); + send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_3, nodes[5].node.create_inbound_payment_for_hash(payment_hash_3, None, 7200, 0).unwrap()); // 7th HTLC: - send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_4, nodes[5].node.create_inbound_payment_for_hash(payment_hash_4, None, 7200).unwrap()); + send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_4, nodes[5].node.create_inbound_payment_for_hash(payment_hash_4, None, 7200, 0).unwrap()); // 8th HTLC: let (_, payment_hash_5, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 1000000); // 9th HTLC: let route = get_route(our_node_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[5].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), ds_dust_limit*1000, TEST_FINAL_CLTV, &logger).unwrap(); - send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_5, nodes[5].node.create_inbound_payment_for_hash(payment_hash_5, None, 7200).unwrap()); // not added < dust limit + HTLC tx fee + send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_5, nodes[5].node.create_inbound_payment_for_hash(payment_hash_5, None, 7200, 0).unwrap()); // not added < dust limit + HTLC tx fee // 10th HTLC: let (_, payment_hash_6, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], ds_dust_limit*1000); // not added < dust limit + HTLC tx fee // 11th HTLC: let route = get_route(our_node_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[5].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 1000000, TEST_FINAL_CLTV, &logger).unwrap(); - send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_6, nodes[5].node.create_inbound_payment_for_hash(payment_hash_6, None, 7200).unwrap()); + send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_6, nodes[5].node.create_inbound_payment_for_hash(payment_hash_6, None, 7200, 0).unwrap()); // Double-check that six of the new HTLC were added // We now have six HTLCs pending over the dust limit and six HTLCs under the dust limit (ie, diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index 8b8cc1230..4486d0510 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -75,6 +75,15 @@ pub enum Event { /// compare this to the expected value before accepting the payment (as otherwise you are /// providing proof-of-payment for less than the value you expected!). amt: u64, + /// This is the `user_payment_id` which was provided to + /// [`ChannelManager::create_inbound_payment_for_hash`] or + /// [`ChannelManager::create_inbound_payment`]. It has no meaning inside of LDK and is + /// simply copied here. It may be used to correlate PaymentReceived events with invoice + /// metadata stored elsewhere. + /// + /// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment + /// [`ChannelManager::create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash + user_payment_id: u64, }, /// Indicates an outbound payment we made succeeded (ie it made it all the way to its target /// and we got back the payment preimage for it). @@ -129,11 +138,12 @@ impl Writeable for Event { // We never write out FundingGenerationReady events as, upon disconnection, peers // drop any channels which have not yet exchanged funding_signed. }, - &Event::PaymentReceived { ref payment_hash, ref payment_secret, ref amt } => { + &Event::PaymentReceived { ref payment_hash, ref payment_secret, ref amt, ref user_payment_id } => { 1u8.write(writer)?; payment_hash.write(writer)?; payment_secret.write(writer)?; amt.write(writer)?; + user_payment_id.write(writer)?; }, &Event::PaymentSent { ref payment_preimage } => { 2u8.write(writer)?; @@ -177,6 +187,7 @@ impl MaybeReadable for Event { payment_hash: Readable::read(reader)?, payment_secret: Readable::read(reader)?, amt: Readable::read(reader)?, + user_payment_id: Readable::read(reader)?, })), 2u8 => Ok(Some(Event::PaymentSent { payment_preimage: Readable::read(reader)?,