Skip to content

Commit dc61c98

Browse files
yuntaiTheBlueMatt
authored andcommitted
Partially implement more onion error handling for sent payments
Also refactor out onion error handling into a function instead of in update_fail_htlc. Cache the initial htlc_msat that we sent instead of recalculating it to check validity of the error returned.
1 parent d3ca7da commit dc61c98

File tree

1 file changed

+211
-57
lines changed

1 file changed

+211
-57
lines changed

src/ln/channelmanager.rs

Lines changed: 211 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ mod channel_held_info {
105105
OutboundRoute {
106106
route: Route,
107107
session_priv: SecretKey,
108+
/// Technically we can recalculate this from the route, but we cache it here to avoid
109+
/// doing a double-pass on route when we get a failure back
110+
first_hop_htlc_msat: u64,
108111
},
109112
}
110113
#[cfg(test)]
@@ -113,6 +116,7 @@ mod channel_held_info {
113116
HTLCSource::OutboundRoute {
114117
route: Route { hops: Vec::new() },
115118
session_priv: SecretKey::from_slice(&::secp256k1::Secp256k1::without_caps(), &[1; 32]).unwrap(),
119+
first_hop_htlc_msat: 0,
116120
}
117121
}
118122
}
@@ -1112,6 +1116,7 @@ impl ChannelManager {
11121116
chan.send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
11131117
route: route.clone(),
11141118
session_priv: session_priv.clone(),
1119+
first_hop_htlc_msat: htlc_msat,
11151120
}, onion_packet).map_err(|he| APIError::ChannelUnavailable{err: he.err})?
11161121
};
11171122

@@ -1794,6 +1799,203 @@ impl ChannelManager {
17941799
Ok(())
17951800
}
17961801

1802+
// Process failure we got back from upstream on a payment we sent. Returns update and a boolean
1803+
// indicating that the payment itself failed
1804+
fn process_onion_failure(&self, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<msgs::HTLCFailChannelUpdate>, bool) {
1805+
if let &HTLCSource::OutboundRoute { ref route, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
1806+
macro_rules! onion_failure_log {
1807+
( $error_code_textual: expr, $error_code: expr, $reported_name: expr, $reported_value: expr ) => {
1808+
log_trace!(self, "{}({:#x}) {}({})", $error_code_textual, $error_code, $reported_name, $reported_value);
1809+
};
1810+
( $error_code_textual: expr, $error_code: expr ) => {
1811+
log_trace!(self, "{}({})", $error_code_textual, $error_code);
1812+
};
1813+
}
1814+
1815+
const BADONION: u16 = 0x8000;
1816+
const PERM: u16 = 0x4000;
1817+
const UPDATE: u16 = 0x1000;
1818+
1819+
let mut res = None;
1820+
let mut htlc_msat = *first_hop_htlc_msat;
1821+
1822+
// Handle packed channel/node updates for passing back for the route handler
1823+
Self::construct_onion_keys_callback(&self.secp_ctx, route, session_priv, |shared_secret, _, _, route_hop| {
1824+
if res.is_some() { return; }
1825+
1826+
let incoming_htlc_msat = htlc_msat;
1827+
let amt_to_forward = htlc_msat - route_hop.fee_msat;
1828+
htlc_msat = amt_to_forward;
1829+
1830+
let ammag = ChannelManager::gen_ammag_from_shared_secret(&shared_secret);
1831+
1832+
let mut decryption_tmp = Vec::with_capacity(packet_decrypted.len());
1833+
decryption_tmp.resize(packet_decrypted.len(), 0);
1834+
let mut chacha = ChaCha20::new(&ammag, &[0u8; 8]);
1835+
chacha.process(&packet_decrypted, &mut decryption_tmp[..]);
1836+
packet_decrypted = decryption_tmp;
1837+
1838+
let is_from_final_node = route.hops.last().unwrap().pubkey == route_hop.pubkey;
1839+
1840+
if let Ok(err_packet) = msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(&packet_decrypted)) {
1841+
let um = ChannelManager::gen_um_from_shared_secret(&shared_secret);
1842+
let mut hmac = Hmac::new(Sha256::new(), &um);
1843+
hmac.input(&err_packet.encode()[32..]);
1844+
let mut calc_tag = [0u8; 32];
1845+
hmac.raw_result(&mut calc_tag);
1846+
1847+
if crypto::util::fixed_time_eq(&calc_tag, &err_packet.hmac) {
1848+
if err_packet.failuremsg.len() < 2 {
1849+
// Useless packet that we can't use but it passed HMAC, so it
1850+
// definitely came from the peer in question
1851+
res = Some((None, !is_from_final_node));
1852+
} else {
1853+
let error_code = byte_utils::slice_to_be16(&err_packet.failuremsg[0..2]);
1854+
1855+
match error_code & 0xff {
1856+
1|2|3 => {
1857+
// either from an intermediate or final node
1858+
// invalid_realm(PERM|1),
1859+
// temporary_node_failure(NODE|2)
1860+
// permanent_node_failure(PERM|NODE|2)
1861+
// required_node_feature_mssing(PERM|NODE|3)
1862+
res = Some((Some(msgs::HTLCFailChannelUpdate::NodeFailure {
1863+
node_id: route_hop.pubkey,
1864+
is_permanent: error_code & PERM == PERM,
1865+
}), !(error_code & PERM == PERM && is_from_final_node)));
1866+
// node returning invalid_realm is removed from network_map,
1867+
// although NODE flag is not set, TODO: or remove channel only?
1868+
// retry payment when removed node is not a final node
1869+
return;
1870+
},
1871+
_ => {}
1872+
}
1873+
1874+
if is_from_final_node {
1875+
let payment_retryable = match error_code {
1876+
c if c == PERM|15 => false, // unknown_payment_hash
1877+
c if c == PERM|16 => false, // incorrect_payment_amount
1878+
17 => true, // final_expiry_too_soon
1879+
18 if err_packet.failuremsg.len() == 6 => { // final_incorrect_cltv_expiry
1880+
let _reported_cltv_expiry = byte_utils::slice_to_be32(&err_packet.failuremsg[2..2+4]);
1881+
true
1882+
},
1883+
19 if err_packet.failuremsg.len() == 10 => { // final_incorrect_htlc_amount
1884+
let _reported_incoming_htlc_msat = byte_utils::slice_to_be64(&err_packet.failuremsg[2..2+8]);
1885+
true
1886+
},
1887+
_ => {
1888+
// A final node has sent us either an invalid code or an error_code that
1889+
// MUST be sent from the processing node, or the formmat of failuremsg
1890+
// does not coform to the spec.
1891+
// Remove it from the network map and don't may retry payment
1892+
res = Some((Some(msgs::HTLCFailChannelUpdate::NodeFailure {
1893+
node_id: route_hop.pubkey,
1894+
is_permanent: true,
1895+
}), false));
1896+
return;
1897+
}
1898+
};
1899+
res = Some((None, payment_retryable));
1900+
return;
1901+
}
1902+
1903+
// now, error_code should be only from the intermediate nodes
1904+
match error_code {
1905+
_c if error_code & PERM == PERM => {
1906+
res = Some((Some(msgs::HTLCFailChannelUpdate::ChannelClosed {
1907+
short_channel_id: route_hop.short_channel_id,
1908+
is_permanent: true,
1909+
}), false));
1910+
},
1911+
_c if error_code & UPDATE == UPDATE => {
1912+
let offset = match error_code {
1913+
c if c == UPDATE|7 => 0, // temporary_channel_failure
1914+
c if c == UPDATE|11 => 8, // amount_below_minimum
1915+
c if c == UPDATE|12 => 8, // fee_insufficient
1916+
c if c == UPDATE|13 => 4, // incorrect_cltv_expiry
1917+
c if c == UPDATE|14 => 0, // expiry_too_soon
1918+
c if c == UPDATE|20 => 2, // channel_disabled
1919+
_ => {
1920+
// node sending unknown code
1921+
res = Some((Some(msgs::HTLCFailChannelUpdate::NodeFailure {
1922+
node_id: route_hop.pubkey,
1923+
is_permanent: true,
1924+
}), false));
1925+
return;
1926+
}
1927+
};
1928+
1929+
if err_packet.failuremsg.len() >= offset + 2 {
1930+
let update_len = byte_utils::slice_to_be16(&err_packet.failuremsg[offset+2..offset+4]) as usize;
1931+
if err_packet.failuremsg.len() >= offset + 4 + update_len {
1932+
if let Ok(chan_update) = msgs::ChannelUpdate::read(&mut Cursor::new(&err_packet.failuremsg[offset + 4..offset + 4 + update_len])) {
1933+
// if channel_update should NOT have caused the failure:
1934+
// MAY treat the channel_update as invalid.
1935+
let is_chan_update_invalid = match error_code {
1936+
c if c == UPDATE|7 => { // temporary_channel_failure
1937+
false
1938+
},
1939+
c if c == UPDATE|11 => { // amount_below_minimum
1940+
let reported_htlc_msat = byte_utils::slice_to_be64(&err_packet.failuremsg[2..2+8]);
1941+
onion_failure_log!("amount_below_minimum", UPDATE|11, "htlc_msat", reported_htlc_msat);
1942+
incoming_htlc_msat > chan_update.contents.htlc_minimum_msat
1943+
},
1944+
c if c == UPDATE|12 => { // fee_insufficient
1945+
let reported_htlc_msat = byte_utils::slice_to_be64(&err_packet.failuremsg[2..2+8]);
1946+
let new_fee = amt_to_forward.checked_mul(chan_update.contents.fee_proportional_millionths as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan_update.contents.fee_base_msat as u64) });
1947+
onion_failure_log!("fee_insufficient", UPDATE|12, "htlc_msat", reported_htlc_msat);
1948+
new_fee.is_none() || incoming_htlc_msat >= new_fee.unwrap() && incoming_htlc_msat >= amt_to_forward + new_fee.unwrap()
1949+
}
1950+
c if c == UPDATE|13 => { // incorrect_cltv_expiry
1951+
let reported_cltv_expiry = byte_utils::slice_to_be32(&err_packet.failuremsg[2..2+4]);
1952+
onion_failure_log!("incorrect_cltv_expiry", UPDATE|13, "cltv_expiry", reported_cltv_expiry);
1953+
route_hop.cltv_expiry_delta as u16 >= chan_update.contents.cltv_expiry_delta
1954+
},
1955+
c if c == UPDATE|20 => { // channel_disabled
1956+
let reported_flags = byte_utils::slice_to_be16(&err_packet.failuremsg[2..2+2]);
1957+
onion_failure_log!("channel_disabled", UPDATE|20, "flags", reported_flags);
1958+
chan_update.contents.flags & 0x01 == 0x01
1959+
},
1960+
c if c == UPDATE|21 => true, // expiry_too_far
1961+
_ => { unreachable!(); },
1962+
};
1963+
1964+
let msg = if is_chan_update_invalid { None } else {
1965+
Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {
1966+
msg: chan_update,
1967+
})
1968+
};
1969+
res = Some((msg, true));
1970+
return;
1971+
}
1972+
}
1973+
}
1974+
},
1975+
_c if error_code & BADONION == BADONION => {
1976+
//TODO
1977+
},
1978+
14 => { // expiry_too_soon
1979+
res = Some((None, true));
1980+
return;
1981+
}
1982+
_ => {
1983+
// node sending unknown code
1984+
res = Some((Some(msgs::HTLCFailChannelUpdate::NodeFailure {
1985+
node_id: route_hop.pubkey,
1986+
is_permanent: true,
1987+
}), false));
1988+
return;
1989+
}
1990+
}
1991+
}
1992+
}
1993+
}
1994+
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
1995+
res.unwrap_or((None, true))
1996+
} else { ((None, true)) }
1997+
}
1998+
17971999
fn internal_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) -> Result<Option<msgs::HTLCFailChannelUpdate>, MsgHandleErrInternal> {
17982000
let mut channel_state = self.channel_state.lock().unwrap();
17992001
let htlc_source = match channel_state.by_id.get_mut(&msg.channel_id) {
@@ -1808,63 +2010,15 @@ impl ChannelManager {
18082010
None => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel", msg.channel_id))
18092011
}?;
18102012

1811-
match htlc_source {
1812-
&HTLCSource::OutboundRoute { ref route, ref session_priv, .. } => {
1813-
// Handle packed channel/node updates for passing back for the route handler
1814-
let mut packet_decrypted = msg.reason.data.clone();
1815-
let mut res = None;
1816-
Self::construct_onion_keys_callback(&self.secp_ctx, &route, &session_priv, |shared_secret, _, _, route_hop| {
1817-
if res.is_some() { return; }
1818-
1819-
let ammag = ChannelManager::gen_ammag_from_shared_secret(&shared_secret);
1820-
1821-
let mut decryption_tmp = Vec::with_capacity(packet_decrypted.len());
1822-
decryption_tmp.resize(packet_decrypted.len(), 0);
1823-
let mut chacha = ChaCha20::new(&ammag, &[0u8; 8]);
1824-
chacha.process(&packet_decrypted, &mut decryption_tmp[..]);
1825-
packet_decrypted = decryption_tmp;
1826-
1827-
if let Ok(err_packet) = msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(&packet_decrypted)) {
1828-
if err_packet.failuremsg.len() >= 2 {
1829-
let um = ChannelManager::gen_um_from_shared_secret(&shared_secret);
1830-
1831-
let mut hmac = Hmac::new(Sha256::new(), &um);
1832-
hmac.input(&err_packet.encode()[32..]);
1833-
let mut calc_tag = [0u8; 32];
1834-
hmac.raw_result(&mut calc_tag);
1835-
if crypto::util::fixed_time_eq(&calc_tag, &err_packet.hmac) {
1836-
const UNKNOWN_CHAN: u16 = 0x4000|10;
1837-
const TEMP_CHAN_FAILURE: u16 = 0x4000|7;
1838-
match byte_utils::slice_to_be16(&err_packet.failuremsg[0..2]) {
1839-
TEMP_CHAN_FAILURE => {
1840-
if err_packet.failuremsg.len() >= 4 {
1841-
let update_len = byte_utils::slice_to_be16(&err_packet.failuremsg[2..4]) as usize;
1842-
if err_packet.failuremsg.len() >= 4 + update_len {
1843-
if let Ok(chan_update) = msgs::ChannelUpdate::read(&mut Cursor::new(&err_packet.failuremsg[4..4 + update_len])) {
1844-
res = Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {
1845-
msg: chan_update,
1846-
});
1847-
}
1848-
}
1849-
}
1850-
},
1851-
UNKNOWN_CHAN => {
1852-
// No such next-hop. We know this came from the
1853-
// current node as the HMAC validated.
1854-
res = Some(msgs::HTLCFailChannelUpdate::ChannelClosed {
1855-
short_channel_id: route_hop.short_channel_id,
1856-
is_permanent: true,
1857-
});
1858-
},
1859-
_ => {}, //TODO: Enumerate all of these!
1860-
}
1861-
}
1862-
}
1863-
}
1864-
}).unwrap();
1865-
Ok(res)
1866-
},
1867-
_ => { Ok(None) },
2013+
// we are the origin node and update route information
2014+
// also determine if the payment is retryable
2015+
if let &HTLCSource::OutboundRoute { .. } = htlc_source {
2016+
let (channel_update, _payment_retry) = self.process_onion_failure(htlc_source, msg.reason.data.clone());
2017+
Ok(channel_update)
2018+
// TODO: include pyament_retry info in PaymentFailed event that will be
2019+
// fired when receiving revoke_and_ack
2020+
} else {
2021+
Ok(None)
18682022
}
18692023
}
18702024

0 commit comments

Comments
 (0)