Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Include height to incorrect_or_unknown_payment_details failure - #596

Merged
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content
Apr 20, 2020
Merged

Include height to incorrect_or_unknown_payment_details failure#596
TheBlueMatt merged 2 commits into
lightningdevkit:masterfrom
D4nte:586-update-htlc-error-code-content

Conversation

@D4nte

@D4nteD4nte commented Apr 19, 2020

Copy link
Copy Markdown
Contributor

Resolves#586.

To prepare the work on this PR, I reviewed all the instantiations of HTLCFailReason::Reason against the latest BOLT spec and checked whether it includes the spec'd data.

I have not reviewed in details whether or not the failure message was instantiated against the right conditions as the issue only mentioned content.

Edit: I intend to leverage type safety with a follow-up PR as per Matt's comment.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR. As for a test, the following patch adds a test for this:

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index cec173e5e..03db866ad 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -1851,9 +1851,9 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
match &onion_error {
&HTLCFailReason::LightningError { ref err } => {
#[cfg(test)]
- let (channel_update, payment_retryable, onion_error_code) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
#[cfg(not(test))]
- let (channel_update, payment_retryable, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
+ let (channel_update, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
// TODO: If we decided to blame ourselves (or one of our channels) in
// process_onion_failure we should close that channel as it implies our
// next-hop is needlessly blaming us!
@@ -1869,13 +1869,17 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
payment_hash: payment_hash.clone(),
rejected_by_dest: !payment_retryable,
#[cfg(test)]
- error_code: onion_error_code
+ error_code: onion_error_code,
+#[cfg(test)]
+ error_data: onion_error_data
}
);
},
&HTLCFailReason::Reason {
#[cfg(test)]
ref failure_code,
+#[cfg(test)]
+ ref data,
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a PaymentFailureNetworkUpdate for temporary
@@ -1890,6 +1894,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
rejected_by_dest: path.len() == 1,
#[cfg(test)]
error_code: Some(*failure_code),
+#[cfg(test)]
+ error_data: Some(data.clone()),
}
);
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 1be967d93..21d868603 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -5326,7 +5326,7 @@ fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case:
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] {
assert_eq!(*rejected_by_dest, !expected_retryable);
assert_eq!(*error_code, expected_error_code);
} else {
@@ -6914,9 +6914,20 @@ fn test_check_htlc_underpaying() {
let events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
-	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code } = &events[0] {
+	if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, ref error_data } = &events[0] {
assert_eq!(*rejected_by_dest, true);
assert_eq!(error_code.unwrap(), 0x4000|15);
+ // 10_000 msat as u64, followed by a height of 99 as u32
+ assert_eq!(&error_data.as_ref().unwrap()[..], &[
+ ((10_000u64 >> 7*8) & 0xff) as u8,
+ ((10_000u64 >> 6*8) & 0xff) as u8,
+ ((10_000u64 >> 5*8) & 0xff) as u8,
+ ((10_000u64 >> 4*8) & 0xff) as u8,
+ ((10_000u64 >> 3*8) & 0xff) as u8,
+ ((10_000u64 >> 2*8) & 0xff) as u8,
+ ((10_000u64 >> 1*8) & 0xff) as u8,
+ ((10_000u64 >> 0*8) & 0xff) as u8,
+ 0, 0, 0, 99]);
} else {
panic!("Unexpected event");
}
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index ff89782be..dc3b2f902 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -317,11 +317,13 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
-pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>) {
+#[inline]
+pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, logger: &Arc<Logger>, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool, Option<u16>, Option<Vec<u8>>) {
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
let mut res = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
+ let mut error_packet_ret = None;
let mut next_route_hop_ix = 0;
let mut is_from_final_node = false;
@@ -356,6 +358,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
let error_code = byte_utils::slice_to_be16(&error_code_slice);
error_code_ret = Some(error_code);
+ error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
@@ -456,11 +459,11 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
if let Some((channel_update, payment_retryable)) = res {
- (channel_update, payment_retryable, error_code_ret)
+ (channel_update, payment_retryable, error_code_ret, error_packet_ret)
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
- (None, !is_from_final_node, None)
+ (None, !is_from_final_node, None, None)
}
} else { unreachable!(); }
}
diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs
index 2c00a1335..8f3460567 100644
--- a/lightning/src/util/events.rs
+++ b/lightning/src/util/events.rs
@@ -96,6 +96,8 @@ pub enum Event {
rejected_by_dest: bool,
#[cfg(test)]
error_code: Option<u16>,
+#[cfg(test)]
+ error_data: Option<Vec<u8>>,
},
/// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a
/// time in the future.
@@ -142,12 +144,16 @@ impl Writeable for Event {
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
ref error_code,
+ #[cfg(test)]
+ ref error_data,
} => {
4u8.write(writer)?;
payment_hash.write(writer)?;
rejected_by_dest.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
+ #[cfg(test)]
+ error_data.write(writer)?;
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
5u8.write(writer)?;
@@ -186,6 +192,8 @@ impl MaybeReadable for Event {
rejected_by_dest: Readable::read(reader)?,
#[cfg(test)]
error_code: Readable::read(reader)?,
+ #[cfg(test)]
+ error_data: Readable::read(reader)?,
})),
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Yea, in the future we should probably have structs in onion_utils which ensure that we are always passing the right data for each possible error type instead of the ad-hoc stuff right now. Certainly thats a lot more work, so should probably be a separate PR.

Yes it's what I thought. I'll aim to do a follow-up PR that does it. Thanks for the test.

@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch 2 times, most recently from a4d1080 to d55738cCompareApril 19, 2020 20:46
D4nte added 2 commits April 20, 2020 08:30
`incorrect_or_unknown_payment_details` failure message,
`0x4000 (PERM) | 15`, should include the following data:
- [u64:htlc_msat]
- [u32:height]
This patches ensure that the height is included in all
the occurrences of this failure message.
Ensure that the best know blockchain height is included in the
data of `incorrect_or_unknown_payment_details` message failure.
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from d55738c to 6e2c9b1CompareApril 19, 2020 22:33
@D4nteD4nte mentioned this pull request Apr 19, 2020
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Comment threadlightning/src/ln/channelmanager.rs
@D4nte
D4nteforce-pushed the 586-update-htlc-error-code-content branch from 6e2c9b1 to 236887dCompareApril 19, 2020 23:40
@D4nte

Copy link
Copy Markdown
ContributorAuthor

Hmm, please drop the formatting commit. We'll probably want to do that all in one go (#425), its someone needless churn to do it as we go.

Done!

@TheBlueMatt
TheBlueMatt merged commit 900d900 into lightningdevkit:masterApr 20, 2020
@D4nte
D4nte deleted the 586-update-htlc-error-code-content branch April 20, 2020 06:56
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 20, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this pull request Apr 24, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update HTLC error code contents

2 participants

@D4nte@TheBlueMatt