Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

fn do_encoding_open_channel(random_bit: bool, shutdown: bool) {
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Routing improvements by naumenkogs · Pull Request #651 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

fn do_encoding_open_channel(random_bit: bool, shutdown: bool) {
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Routing improvements by naumenkogs · Pull Request #651 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

fn do_encoding_open_channel(random_bit: bool, shutdown: bool) {
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Routing improvements by naumenkogs · Pull Request #651 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

fn do_encoding_open_channel(random_bit: bool, shutdown: bool) {
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Routing improvements by naumenkogs · Pull Request #651 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

fn do_encoding_open_channel(random_bit: bool, shutdown: bool) {
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Routing improvements by naumenkogs · Pull Request #651 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/bin/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,12 +31,12 @@ GEN_TEST msg_update_fee msg_targets::
GEN_TEST msg_update_fulfill_htlc msg_targets::

GEN_TEST msg_channel_announcement msg_targets::
GEN_TEST msg_channel_update msg_targets::
GEN_TEST msg_node_announcement msg_targets::

GEN_TEST msg_update_add_htlc msg_targets::
GEN_TEST msg_error_message msg_targets::
GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_channel_update msg_targets::

GEN_TEST msg_onion_hop_data msg_targets::
GEN_TEST msg_ping msg_targets::
GEN_TEST msg_pong msg_targets::
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/gen_target.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,11 +29,11 @@ GEN_TEST UpdateFee test_msg ""
GEN_TEST UpdateFulfillHTLC test_msg ""

GEN_TEST ChannelAnnouncement test_msg_exact ""
GEN_TEST ChannelUpdate test_msg_exact ""
GEN_TEST NodeAnnouncement test_msg_exact ""

GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
GEN_TEST ChannelUpdate test_msg_hole ", 108, 1"

GEN_TEST Init test_msg_simple ""
GEN_TEST OnionHopData test_msg_simple ""
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/msg_targets/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,10 +16,10 @@ pub mod msg_update_fail_malformed_htlc;
pub mod msg_update_fee;
pub mod msg_update_fulfill_htlc;
pub mod msg_channel_announcement;
pub mod msg_channel_update;
pub mod msg_node_announcement;
pub mod msg_update_add_htlc;
pub mod msg_error_message;
pub mod msg_channel_update;
pub mod msg_init;
pub mod msg_onion_hop_data;
pub mod msg_ping;
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/msg_channel_update.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,11 +8,11 @@ use utils::test_logger;

#[inline]
pub fn msg_channel_update_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}

#[no_mangle]
pub extern "C" fn msg_channel_update_run(data: *const u8, datalen: usize) {
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
test_msg_exact!(msgs::ChannelUpdate, data);
test_msg_hole!(msgs::ChannelUpdate, data, 108, 1);
}
4 changes: 2 additions & 2 deletions fuzz/src/msg_targets/utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -78,8 +78,8 @@ macro_rules! test_msg_exact {
}
}

// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
// re-serialization.
// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to
// any value on re-serialization.
#[macro_export]
macro_rules! test_msg_hole {
($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/router.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -172,12 +172,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let _ = net_graph_msg_handler.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
},
2 => {
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
let _ = net_graph_msg_handler.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 136));
},
3 => {
match get_slice!(1)[0] {
0 => {
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
net_graph_msg_handler.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 136)});
},
1 => {
let short_channel_id = slice_to_be64(get_slice!(8));
Expand Down
2 changes: 1 addition & 1 deletion fuzz/targets.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,10 +22,10 @@ void msg_update_fail_malformed_htlc_run(const unsigned char* data, size_t data_l
void msg_update_fee_run(const unsigned char* data, size_t data_len);
void msg_update_fulfill_htlc_run(const unsigned char* data, size_t data_len);
void msg_channel_announcement_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_node_announcement_run(const unsigned char* data, size_t data_len);
void msg_update_add_htlc_run(const unsigned char* data, size_t data_len);
void msg_error_message_run(const unsigned char* data, size_t data_len);
void msg_channel_update_run(const unsigned char* data, size_t data_len);
void msg_onion_hop_data_run(const unsigned char* data, size_t data_len);
void msg_ping_run(const unsigned char* data, size_t data_len);
void msg_pong_run(const unsigned char* data, size_t data_len);
12 changes: 12 additions & 0 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -3135,6 +3135,18 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
self.our_htlc_minimum_msat
}

/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts
// to use full capacity. This is an effort to reduce routing failures, because in many cases
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 9 / 10,

Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
);
}

/// Allowed in any state (including after shutdown)
pub fn get_their_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
Expand Down
11 changes: 7 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,7 @@ use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
use ln::msgs;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
use chain::keysinterface::{ChannelKeys, KeysInterface, KeysManager, InMemoryChannelKeys};
use util::config::UserConfig;
use util::{byte_utils, events};
Expand DownExpand Up@@ -1186,7 +1186,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry));
}
else if code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(chan_update.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&chan_update.encode_with_len()[..]);
}
Expand All@@ -1212,9 +1213,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
chain_hash: self.genesis_hash,
short_channel_id: short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u16 | ((!chan.is_live() as u16) << 1),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_our_fee_base_msat(&self.fee_estimator),
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
excess_data: Vec::new(),
Expand DownExpand Up@@ -2494,7 +2496,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
let reason = if let Ok(upd) = self.get_channel_update(chan) {
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
let mut res = Vec::with_capacity(8 + 128);
res.extend_from_slice(&byte_utils::be16_to_array(upd.contents.flags));
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len()[..]);
res
}[..])
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ use ln::{chan_utils, onion_utils};
use routing::router::{Route, RouteHop, get_route};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::{byte_utils, test_utils};
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
Expand DownExpand Up@@ -6058,6 +6058,7 @@ impl msgs::ChannelUpdate {
flags: 0,
cltv_expiry_delta: 0,
htlc_minimum_msat: 0,
htlc_maximum_msat: OptionalField::Absent,
fee_base_msat: 0,
fee_proportional_millionths: 0,
excess_data: vec![],
Expand Down
71 changes: 58 additions & 13 deletions lightning/src/ln/msgs.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,9 +427,10 @@ pub(crate) struct UnsignedChannelUpdate {
pub(crate) chain_hash: BlockHash,
pub(crate) short_channel_id: u64,
pub(crate) timestamp: u32,
pub(crate) flags: u16,
pub(crate) flags: u8,
pub(crate) cltv_expiry_delta: u16,
pub(crate) htlc_minimum_msat: u64,
pub(crate) htlc_maximum_msat: OptionalField<u64>,
Comment thread
naumenkogs marked this conversation as resolved.
pub(crate) fee_base_msat: u32,
pub(crate) fee_proportional_millionths: u32,
pub(crate) excess_data: Vec<u8>,
Expand DownExpand Up@@ -517,7 +518,7 @@ pub enum HTLCFailChannelUpdate {
/// As we wish to serialize these differently from Option<T>s (Options get a tag byte, but
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
Expand DownExpand Up@@ -742,6 +743,26 @@ impl Readable for OptionalField<Script> {
}
}

impl Writeable for OptionalField<u64> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
match *self {
OptionalField::Present(ref value) => {
value.write(w)?;
},
OptionalField::Absent => {}
}
Ok(())
}
}

impl Readable for OptionalField<u64> {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let value: u64 = Readable::read(r)?;
Comment thread
naumenkogs marked this conversation as resolved.
Ok(OptionalField::Present(value))
}
}


impl_writeable_len_match!(AcceptChannel, {
{AcceptChannel{ shutdown_scriptpubkey: OptionalField::Present(ref script), .. }, 270 + 2 + script.len()},
{_, 270}
Expand DownExpand Up@@ -1180,31 +1201,46 @@ impl_writeable_len_match!(ChannelAnnouncement, {

impl Writeable for UnsignedChannelUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
w.size_hint(64 + self.excess_data.len());
let mut size = 64 + self.excess_data.len();
let mut message_flags: u8 = 0;
if let OptionalField::Present(_) = self.htlc_maximum_msat {
size += 8;
message_flags = 1;
}
w.size_hint(size);
self.chain_hash.write(w)?;
self.short_channel_id.write(w)?;
self.timestamp.write(w)?;
self.flags.write(w)?;
let all_flags = self.flags as u16 | ((message_flags as u16) << 8);
all_flags.write(w)?;
self.cltv_expiry_delta.write(w)?;
self.htlc_minimum_msat.write(w)?;
self.fee_base_msat.write(w)?;
self.fee_proportional_millionths.write(w)?;
self.htlc_maximum_msat.write(w)?;
w.write_all(&self.excess_data[..])?;
Ok(())
}
}

impl Readable for UnsignedChannelUpdate {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let has_htlc_maximum_msat;
Ok(Self {
chain_hash: Readable::read(r)?,
short_channel_id: Readable::read(r)?,
timestamp: Readable::read(r)?,
flags: Readable::read(r)?,
flags: {
let flags: u16 = Readable::read(r)?;
let message_flags = flags >> 8;
has_htlc_maximum_msat = (message_flags as i32 & 1) == 1;
flags as u8
},
cltv_expiry_delta: Readable::read(r)?,
htlc_minimum_msat: Readable::read(r)?,
fee_base_msat: Readable::read(r)?,
fee_proportional_millionths: Readable::read(r)?,
htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent },
excess_data: {
let mut excess_data = vec![];
r.read_to_end(&mut excess_data)?;
Expand DownExpand Up@@ -1597,20 +1633,21 @@ mod tests {
do_encoding_node_announcement(false, false, true, false, true, false, false);
}

fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool) {
fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) {
let secp_ctx = Secp256k1::new();
let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
let unsigned_channel_update = msgs::UnsignedChannelUpdate {
chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
short_channel_id: 2316138423780173,
timestamp: 20190119,
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 } | if htlc_maximum_msat { 1 << 8 } else { 0 },
flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent },
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: if htlc_maximum_msat { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() }
};
let channel_update = msgs::ChannelUpdate {
signature: sig_1,
Expand All@@ -1636,18 +1673,26 @@ mod tests {
}
target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap());
if htlc_maximum_msat {
target_value.append(&mut hex::decode("0000777788889999").unwrap());
}
if excess_data {
target_value.append(&mut hex::decode("000000003b9aca00").unwrap());
}
assert_eq!(encoded_value, target_value);
}

#[test]
fn encoding_channel_update() {
do_encoding_channel_update(false, false, false);
do_encoding_channel_update(true, false, false);
do_encoding_channel_update(false, true, false);
do_encoding_channel_update(false, false, true);
do_encoding_channel_update(true, true, true);
do_encoding_channel_update(false, false, false, false);
do_encoding_channel_update(false, false, false, true);
do_encoding_channel_update(true, false, false, false);
do_encoding_channel_update(true, false, false, true);
do_encoding_channel_update(false, true, false, false);
do_encoding_channel_update(false, true, false, true);
do_encoding_channel_update(false, false, true, false);
do_encoding_channel_update(false, false, true, true);
do_encoding_channel_update(true, true, true, false);
do_encoding_channel_update(true, true, true, true);
}

fn do_encoding_open_channel(random_bit: bool, shutdown: bool) {
Expand Down
Loading