+# 0.0.111 - Sep 12, 2022 - "Saturated with Messages"
+
+## API Updates
+ * Support for relaying onion messages has been added via a new
+ `OnionMessenger` struct when passed as the `OnionMessageHandler` to a
+ `PeerManager`. Pre-encoded onion messages can also be sent and received
+ (#1503, #1650, #1652, #1688).
+ * Rate-limiting of outbound gossip syncs has been rewritten to utilize less
+ buffering inside LDK. The new rate-limiting is also used for onion messages
+ to avoid delaying other messages (#1604. #1660, #1683).
+ * Rather than spawning a full OS thread, `lightning-background-processor` has
+ a new `process_events_async` method which takes the place of a
+ `BackgroundProcessor` for those using Rust's async (#1657).
+ * `ChannelManager::get_persistable_update_future` has been added to block on
+ a ChannelManager needing re-persistence in a Rust async environment (#1657).
+ * The `Filter::register_output` return value has been removed, as it was
+ very difficult to correctly implement (i.e., without blocking). Users
+ previously using it should instead pass dependent transactions in via
+ additional `chain::Confirm::transactions_confirmed` calls (#1663).
+ * `ChannelHandshakeConfig::their_channel_reserve_proportional_millionths` has
+ been added to allow configuring counterparty reserve values (#1619).
+ * `KeysInterface::ecdh` has been added as an ECDH oracle (#1503, #1658).
+ * The `rust-bitcoin` dependency has been updated 0.29 (#1658).
+ * The `bitcoin_hashes` dependency has been updated 0.11 (#1677).
+ * `ChannelManager::broadcast_node_announcement` has been moved to
+ `PeerManager` (#1699).
+ * `channel_` and `node_announcement`s are now rebroadcast automatically to all
+ new peers which connect (#1699).
+ * `{Init,Node}Features` sent to peers/broadcasted are now fetched via the
+ various `*MessageHandler` traits, rather than hard-coded (#1701, #1688).
+ * `Event::PaymentPathFailed::rejected_by_dest` has been renamed
+ `payment_failed_permanently` (#1702).
+ * `Invoice` now derives the std `Hash` trait (#1575).
+ * `{Signed,}RawInvoice::hash` have been renamed `signable_hash` (#1714).
+ * `chain::AccessError` now derives the std `Debug` trait (#1709).
+ * `ReadOnlyNetworkGraph::list_{channels,nodes}` have been added largely for
+ users of downstream bindings (#1651).
+ * `ChannelMonitor::get_counterparty_node_id` is now available (#1635).
+
+## Bug Fixes
+ * The script compared with that returned from `chain::Access` was incorrect
+ ~half of the time, causing spurious gossip rejection (#1666).
+ * Pending in-flight HTLCs are now considered when calculating new routes,
+ ensuring, e.g. MPP retries do not take known-saturated paths (#1643).
+ * Counterparty-revoked outputs are now included in `get_claimable_balance`
+ output via a new `Balance::CounterpartyRevokedOutputClaimable` (#1495).
+ * Inbound HTLCs for which we do not (yet) have a preimage are now included in
+ `get_claimable_balance` via a `Balance::MaybePreimageClaimableHTLC` (#1673).
+ * Probes that fail prior to being sent over their first hop are correctly
+ failed with a `Event::ProbeFailed` rather than a `PaymentPathFailed` (#1704).
+ * Pending `Event::HTLCHandlingFailed`s are no longer lost on restart (#1700).
+ * HTLCs that fail prior to being sent over their first hop are now marked as
+ retryable via `!PaymentPathFailed::payment_failed_permanently` (#1702).
+ * Dust HTLCs are now considered failed in the payment tracking logic after the
+ commitment transaction confirms, allowing retry on restart (#1691).
+ * On machines with buggy "monotonic" clocks, LDK will no longer panic if time
+ goes backwards (#1692).
+
+## Backwards Compatibility
+ * The new `current_time` argument to `PeerManager` constructors must be set to
+ a UNIX timestamp for upgraded nodes; new nodes may use a counter (#1699).
+ * `Balance::CounterpartyRevokedOutputClaimable` will never be generated for
+ channels that were observed to go on-chain with LDK versions prior to
+ 0.0.111 (#1495).
+ * `ChannelMonitor::get_counterparty_node_id` will return `None` for all
+ channels opened on a version of LDK prior to 0.0.110 (#1635).
+ * Setting `their_channel_reserve_proportional_millionths` to any value other
+ than the default will cause LDK versions prior to 0.0.104 to be unable to
+ read the serialized `ChannelManager` (#1619).
+
+## Security
+0.0.111 fixes a denial-of-service vulnerability which is reachable from
+untrusted input in deployments accepting 0conf channels, or via a race-condition
+in deployments creating outbound 0conf channels.
+
+ * LDK versions prior to 0.0.111 may spuriously panic when receiving a block if
+ they are awaiting the construction of a funding transaction for a 0-conf
+ channel (#1711). 0-conf support was added in LDK version 0.0.107.
+
+In total, this release features 84 files changed, 6306 insertions, 1960
+deletions in 121 commits from 11 authors, in alphabetical order:
+ * Arik Sosman
+ * Devrandom
+ * Duncan Dean
+ * Elias Rohrer
+ * Gursharan Singh
+ * Matt Corallo
+ * NicolaLS
+ * Valentine Wallace
+ * Viktor Tigerström
+ * jurvis
+ * ok300
+
+
# 0.0.110 - 2022-07-26 - "Routing, With a Vengeance"
## API Updates
};
loop {
if get_slice!(1)[0] == 0 {
- crypter.encrypt_message(get_slice!(slice_to_be16(get_slice!(2))));
+ crypter.encrypt_buffer(get_slice!(slice_to_be16(get_slice!(2))));
} else {
let len = match crypter.decrypt_length_header(get_slice!(16+2)) {
Ok(len) => len,
[package]
name = "lightning-background-processor"
-version = "0.0.110"
+version = "0.0.111"
authors = ["Valentine Wallace <vwallace@protonmail.com>"]
license = "MIT OR Apache-2.0"
repository = "http://github.com/lightningdevkit/rust-lightning"
[dependencies]
bitcoin = "0.29.0"
-lightning = { version = "0.0.110", path = "../lightning", features = ["std"] }
-lightning-rapid-gossip-sync = { version = "0.0.110", path = "../lightning-rapid-gossip-sync" }
+lightning = { version = "0.0.111", path = "../lightning", features = ["std"] }
+lightning-rapid-gossip-sync = { version = "0.0.111", path = "../lightning-rapid-gossip-sync" }
futures = { version = "0.3", optional = true }
[dev-dependencies]
-lightning = { version = "0.0.110", path = "../lightning", features = ["_test_utils"] }
-lightning-invoice = { version = "0.18.0", path = "../lightning-invoice" }
-lightning-persister = { version = "0.0.110", path = "../lightning-persister" }
+lightning = { version = "0.0.111", path = "../lightning", features = ["_test_utils"] }
+lightning-invoice = { version = "0.19.0", path = "../lightning-invoice" }
+lightning-persister = { version = "0.0.111", path = "../lightning-persister" }
[package]
name = "lightning-block-sync"
-version = "0.0.110"
+version = "0.0.111"
authors = ["Jeffrey Czyz", "Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "http://github.com/lightningdevkit/rust-lightning"
[dependencies]
bitcoin = "0.29.0"
-lightning = { version = "0.0.110", path = "../lightning" }
+lightning = { version = "0.0.111", path = "../lightning" }
futures = { version = "0.3" }
tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
[package]
name = "lightning-invoice"
description = "Data structures to parse and serialize BOLT11 lightning invoices"
-version = "0.18.0"
+version = "0.19.0"
authors = ["Sebastian Geisler <sgeisler@wh2.tu-dresden.de>"]
documentation = "https://docs.rs/lightning-invoice/"
license = "MIT OR Apache-2.0"
[dependencies]
bech32 = { version = "0.9.0", default-features = false }
-lightning = { version = "0.0.110", path = "../lightning", default-features = false }
+lightning = { version = "0.0.111", path = "../lightning", default-features = false }
secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"] }
num-traits = { version = "0.2.8", default-features = false }
bitcoin_hashes = { version = "0.11", default-features = false }
serde = { version = "1.0.118", optional = true }
[dev-dependencies]
-lightning = { version = "0.0.110", path = "../lightning", default-features = false, features = ["_test_utils"] }
+lightning = { version = "0.0.111", path = "../lightning", default-features = false, features = ["_test_utils"] }
hex = "0.4"
serde_json = { version = "1"}
}
/// The hash of the `RawInvoice` that was signed.
- pub fn hash(&self) -> &[u8; 32] {
+ pub fn signable_hash(&self) -> &[u8; 32] {
&self.hash
}
hash
}
- /// Calculate the hash of the encoded `RawInvoice`
- pub fn hash(&self) -> [u8; 32] {
+ /// Calculate the hash of the encoded `RawInvoice` which should be signed.
+ pub fn signable_hash(&self) -> [u8; 32] {
use bech32::ToBase32;
RawInvoice::hash_from_parts(
pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawInvoice, E>
where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
{
- let raw_hash = self.hash();
+ let raw_hash = self.signable_hash();
let hash = Message::from_slice(&raw_hash[..])
.expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
let signature = sign_method(&hash)?;
0xd5, 0x18, 0xe1, 0xc9
];
- assert_eq!(invoice.hash(), expected_hash)
+ assert_eq!(invoice.signable_hash(), expected_hash)
}
#[test]
[package]
name = "lightning-net-tokio"
-version = "0.0.110"
+version = "0.0.111"
authors = ["Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning/"
[dependencies]
bitcoin = "0.29.0"
-lightning = { version = "0.0.110", path = "../lightning" }
+lightning = { version = "0.0.111", path = "../lightning" }
tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] }
[dev-dependencies]
[package]
name = "lightning-persister"
-version = "0.0.110"
+version = "0.0.111"
authors = ["Valentine Wallace", "Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning/"
[dependencies]
bitcoin = "0.29.0"
-lightning = { version = "0.0.110", path = "../lightning" }
+lightning = { version = "0.0.111", path = "../lightning" }
libc = "0.2"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }
[dev-dependencies]
-lightning = { version = "0.0.110", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.111", path = "../lightning", features = ["_test_utils"] }
[package]
name = "lightning-rapid-gossip-sync"
-version = "0.0.110"
+version = "0.0.111"
authors = ["Arik Sosman <git@arik.io>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning"
_bench_unstable = []
[dependencies]
-lightning = { version = "0.0.110", path = "../lightning" }
+lightning = { version = "0.0.111", path = "../lightning" }
bitcoin = { version = "0.29.0", default-features = false }
[dev-dependencies]
-lightning = { version = "0.0.110", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.111", path = "../lightning", features = ["_test_utils"] }
[package]
name = "lightning"
-version = "0.0.110"
+version = "0.0.111"
authors = ["Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning/"
use ln::channel::{Channel, ChannelError};
use ln::{chan_utils, onion_utils};
use ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
-use routing::gossip::NetworkGraph;
+use routing::gossip::{NetworkGraph, NetworkUpdate};
use routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, find_route, get_route};
use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
use ln::msgs;
check_added_monitors!(nodes[1], 1);
}
+#[test]
+fn test_channel_failed_after_message_with_badonion_node_perm_bits_set() {
+ let chanmon_cfgs = create_chanmon_cfgs(3);
+ let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+ let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+ create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+
+ let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 100_000);
+
+ // First hop
+ let mut payment_event = {
+ nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
+ check_added_monitors!(nodes[0], 1);
+ SendEvent::from_node(&nodes[0])
+ };
+
+ nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
+ commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
+ expect_pending_htlcs_forwardable!(nodes[1]);
+ check_added_monitors!(nodes[1], 1);
+ payment_event = SendEvent::from_node(&nodes[1]);
+ assert_eq!(payment_event.msgs.len(), 1);
+
+ // Second Hop
+ payment_event.msgs[0].onion_routing_packet.version = 1; // Trigger an invalid_onion_version error
+ nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
+ check_added_monitors!(nodes[2], 0);
+ commitment_signed_dance!(nodes[2], nodes[1], payment_event.commitment_msg, false, true);
+
+ let events_3 = nodes[2].node.get_and_clear_pending_msg_events();
+ assert_eq!(events_3.len(), 1);
+ match events_3[0] {
+ MessageSendEvent::UpdateHTLCs { ref updates, .. } => {
+ let mut update_msg = updates.update_fail_malformed_htlcs[0].clone();
+ // Set the NODE bit (BADONION and PERM already set in invalid_onion_version error)
+ update_msg.failure_code |= 0x2000;
+
+ nodes[1].node.handle_update_fail_malformed_htlc(&nodes[2].node.get_our_node_id(), &update_msg);
+ commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false, true);
+ },
+ _ => panic!("Unexpected event"),
+ }
+
+ expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1],
+ vec![HTLCDestination::NextHopChannel {
+ node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_2.2 }]);
+ let events_4 = nodes[1].node.get_and_clear_pending_msg_events();
+ assert_eq!(events_4.len(), 1);
+ check_added_monitors!(nodes[1], 1);
+
+ match events_4[0] {
+ MessageSendEvent::UpdateHTLCs { ref updates, .. } => {
+ nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
+ commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false, true);
+ },
+ _ => panic!("Unexpected event"),
+ }
+
+ let events_5 = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events_5.len(), 1);
+
+ // Expect a PaymentPathFailed event with a ChannelFailure network update for the channel between
+ // the node originating the error to its next hop.
+ match events_5[0] {
+ Event::PaymentPathFailed { network_update:
+ Some(NetworkUpdate::ChannelFailure { short_channel_id, is_permanent }), error_code, ..
+ } => {
+ assert_eq!(short_channel_id, chan_2.0.contents.short_channel_id);
+ assert!(is_permanent);
+ assert_eq!(error_code, Some(0x8000|0x4000|0x2000|4));
+ },
+ _ => panic!("Unexpected event"),
+ }
+
+ // TODO: Test actual removal of channel from NetworkGraph when it's implemented.
+}
+
fn do_test_failure_delay_dust_htlc_local_commitment(announce_latest: bool) {
// Dust-HTLC failure updates must be delayed until failure-trigger tx (in this case local commitment) reach ANTI_REORG_DELAY
// We can have at most two valid local commitment tx, so both cases must be covered, and both txs must be checked to get them all as
if fixed_time_eq(&Hmac::from_engine(hmac).into_inner(), &err_packet.hmac) {
if let Some(error_code_slice) = err_packet.failuremsg.get(0..2) {
+ const BADONION: u16 = 0x8000;
const PERM: u16 = 0x4000;
const NODE: u16 = 0x2000;
const UPDATE: u16 = 0x1000;
let mut network_update = None;
let mut short_channel_id = None;
- if error_code & NODE == NODE {
+ if error_code & BADONION == BADONION {
+ // If the error code has the BADONION bit set, always blame the channel
+ // from the node "originating" the error to its next hop. The
+ // "originator" is ultimately actually claiming that its counterparty
+ // is the one who is failing the HTLC.
+ // If the "originator" here isn't lying we should really mark the
+ // next-hop node as failed entirely, but we can't be confident in that,
+ // as it would allow any node to get us to completely ban one of its
+ // counterparties. Instead, we simply remove the channel in question.
+ network_update = Some(NetworkUpdate::ChannelFailure {
+ short_channel_id: failing_route_hop.short_channel_id,
+ is_permanent: true,
+ });
+ } else if error_code & NODE == NODE {
let is_permanent = error_code & PERM == PERM;
network_update = Some(NetworkUpdate::NodeFailure { node_id: route_hop.pubkey, is_permanent });
short_channel_id = Some(route_hop.short_channel_id);
- }
- else if error_code & PERM == PERM {
+ } else if error_code & PERM == PERM {
if !payment_failed {
network_update = Some(NetworkUpdate::ChannelFailure {
short_channel_id: failing_route_hop.short_channel_id,
});
short_channel_id = Some(failing_route_hop.short_channel_id);
}
- }
- else if error_code & UPDATE == UPDATE {
+ } else if error_code & UPDATE == UPDATE {
if let Some(update_len_slice) = err_packet.failuremsg.get(debug_field_size+2..debug_field_size+4) {
let update_len = u16::from_be_bytes(update_len_slice.try_into().expect("len is 2")) as usize;
if let Some(mut update_slice) = err_packet.failuremsg.get(debug_field_size + 4..debug_field_size + 4 + update_len) {
short_channel_id = Some(route_hop.short_channel_id);
}
- // TODO: Here (and a few other places) we assume that BADONION errors
- // are always "sourced" from the node previous to the one which failed
- // to decode the onion.
res = Some((network_update, short_channel_id, !(error_code & PERM == PERM && is_from_final_node)));
let (description, title) = errors::get_onion_error_description(error_code);
use ln::msgs::LightningError;
use ln::msgs;
+use ln::wire;
use bitcoin::hashes::{Hash, HashEngine};
use bitcoin::hashes::sha256::Hash as Sha256;
use util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
use util::crypto::hkdf_extract_expand_twice;
+use util::ser::VecWriter;
use bitcoin::hashes::hex::ToHex;
/// Maximum Lightning message data length according to
res[plaintext.len()..].copy_from_slice(&tag);
}
+ #[inline]
+ /// Encrypts the message in res[offset..] in-place and pushes a 16-byte tag onto the end of
+ /// res.
+ fn encrypt_in_place_with_ad(res: &mut Vec<u8>, offset: usize, n: u64, key: &[u8; 32], h: &[u8]) {
+ let mut nonce = [0; 12];
+ nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
+
+ let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h);
+ let mut tag = [0; 16];
+ chacha.encrypt_full_message_in_place(&mut res[offset..], &mut tag);
+ res.extend_from_slice(&tag);
+ }
+
#[inline]
fn decrypt_with_ad(res: &mut[u8], n: u64, key: &[u8; 32], h: &[u8], cyphertext: &[u8]) -> Result<(), LightningError> {
let mut nonce = [0; 12];
Ok(self.their_node_id.unwrap().clone())
}
- /// Encrypts the given message, returning the encrypted version
+ /// Encrypts the given pre-serialized message, returning the encrypted version.
/// panics if msg.len() > 65535 or Noise handshake has not finished.
- pub fn encrypt_message(&mut self, msg: &[u8]) -> Vec<u8> {
+ pub fn encrypt_buffer(&mut self, msg: &[u8]) -> Vec<u8> {
if msg.len() > LN_MAX_MSG_LEN {
panic!("Attempted to encrypt message longer than 65535 bytes!");
}
res
}
+ /// Encrypts the given message, returning the encrypted version.
+ /// panics if the length of `message`, once encoded, is greater than 65535 or if the Noise
+ /// handshake has not finished.
+ pub fn encrypt_message<M: wire::Type>(&mut self, message: &M) -> Vec<u8> {
+ // Allocate a buffer with 2KB, fitting most common messages. Reserve the first 16+2 bytes
+ // for the 2-byte message type prefix and its MAC.
+ let mut res = VecWriter(Vec::with_capacity(2048));
+ res.0.resize(16 + 2, 0);
+ wire::write(message, &mut res).expect("In-memory messages must never fail to serialize");
+
+ let msg_len = res.0.len() - 16 - 2;
+ if msg_len > LN_MAX_MSG_LEN {
+ panic!("Attempted to encrypt message longer than 65535 bytes!");
+ }
+
+ match self.noise_state {
+ NoiseState::Finished { ref mut sk, ref mut sn, ref mut sck, rk: _, rn: _, rck: _ } => {
+ if *sn >= 1000 {
+ let (new_sck, new_sk) = hkdf_extract_expand_twice(sck, sk);
+ *sck = new_sck;
+ *sk = new_sk;
+ *sn = 0;
+ }
+
+ Self::encrypt_with_ad(&mut res.0[0..16+2], *sn, sk, &[0; 0], &(msg_len as u16).to_be_bytes());
+ *sn += 1;
+
+ Self::encrypt_in_place_with_ad(&mut res.0, 16+2, *sn, sk, &[0; 0]);
+ *sn += 1;
+ },
+ _ => panic!("Tried to encrypt a message prior to noise handshake completion"),
+ }
+
+ res.0
+ }
+
/// Decrypts a message length header from the remote peer.
/// panics if noise handshake has not yet finished or msg.len() != 18
pub fn decrypt_length_header(&mut self, msg: &[u8]) -> Result<u16, LightningError> {
for i in 0..1005 {
let msg = [0x68, 0x65, 0x6c, 0x6c, 0x6f];
- let res = outbound_peer.encrypt_message(&msg);
+ let res = outbound_peer.encrypt_buffer(&msg);
assert_eq!(res.len(), 5 + 2*16 + 2);
let len_header = res[0..2+16].to_vec();
fn max_message_len_encryption() {
let mut outbound_peer = get_outbound_peer_for_initiator_test_vectors();
let msg = [4u8; LN_MAX_MSG_LEN + 1];
- outbound_peer.encrypt_message(&msg);
+ outbound_peer.encrypt_buffer(&msg);
}
#[test]
use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
use ln::wire;
use ln::wire::Encode;
+use onion_message::{SimpleArcOnionMessenger, SimpleRefOnionMessenger};
use routing::gossip::{NetworkGraph, P2PGossipSync};
use util::atomic_counter::AtomicCounter;
use util::crypto::sign;
pending_outbound_buffer: LinkedList<Vec<u8>>,
pending_outbound_buffer_first_msg_offset: usize,
- // Queue gossip broadcasts separately from `pending_outbound_buffer` so we can easily prioritize
- // channel messages over them.
+ /// Queue gossip broadcasts separately from `pending_outbound_buffer` so we can easily
+ /// prioritize channel messages over them.
+ ///
+ /// Note that these messages are *not* encrypted/MAC'd, and are only serialized.
gossip_broadcast_buffer: LinkedList<Vec<u8>>,
awaiting_write_event: bool,
/// SimpleRefPeerManager is the more appropriate type. Defining these type aliases prevents
/// issues such as overly long function definitions.
///
-/// (C-not exported) as Arcs don't make sense in bindings
-pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<SD, Arc<SimpleArcChannelManager<M, T, F, L>>, Arc<P2PGossipSync<Arc<NetworkGraph<Arc<L>>>, Arc<C>, Arc<L>>>, IgnoringMessageHandler, Arc<L>, Arc<IgnoringMessageHandler>>;
+/// (C-not exported) as `Arc`s don't make sense in bindings.
+pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<SD, Arc<SimpleArcChannelManager<M, T, F, L>>, Arc<P2PGossipSync<Arc<NetworkGraph<Arc<L>>>, Arc<C>, Arc<L>>>, Arc<SimpleArcOnionMessenger<L>>, Arc<L>, IgnoringMessageHandler>;
/// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference
/// counterpart to the SimpleArcPeerManager type alias. Use this type by default when you don't
/// But if this is not necessary, using a reference is more efficient. Defining these type aliases
/// helps with issues such as long function definitions.
///
-/// (C-not exported) as Arcs don't make sense in bindings
-pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, SD, M, T, F, C, L> = PeerManager<SD, SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L>, &'e P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, IgnoringMessageHandler, &'f L, IgnoringMessageHandler>;
+/// (C-not exported) as general type aliases don't make sense in bindings.
+pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, SD, M, T, F, C, L> = PeerManager<SD, SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L>, &'e P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, &'i SimpleRefOnionMessenger<'j, 'k, L>, &'f L, IgnoringMessageHandler>;
/// A PeerManager manages a set of peers, described by their [`SocketDescriptor`] and marshalls
/// socket events into messages which it passes on to its [`MessageHandler`].
}
if peer.should_buffer_gossip_broadcast() {
if let Some(msg) = peer.gossip_broadcast_buffer.pop_front() {
- peer.pending_outbound_buffer.push_back(msg);
+ peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_buffer(&msg[..]));
}
}
if peer.should_buffer_gossip_backfill() {
/// Append a message to a peer's pending outbound/write buffer
fn enqueue_message<M: wire::Type>(&self, peer: &mut Peer, message: &M) {
- let mut buffer = VecWriter(Vec::with_capacity(2048));
- wire::write(message, &mut buffer).unwrap(); // crash if the write failed
-
if is_gossip_msg(message.type_id()) {
log_gossip!(self.logger, "Enqueueing message {:?} to {}", message, log_pubkey!(peer.their_node_id.unwrap()));
} else {
log_trace!(self.logger, "Enqueueing message {:?} to {}", message, log_pubkey!(peer.their_node_id.unwrap()))
}
peer.msgs_sent_since_pong += 1;
- peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&buffer.0[..]));
+ peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(message));
}
/// Append a message to a peer's pending outbound/write gossip broadcast buffer
- fn enqueue_encoded_gossip_broadcast(&self, peer: &mut Peer, encoded_message: &Vec<u8>) {
+ fn enqueue_encoded_gossip_broadcast(&self, peer: &mut Peer, encoded_message: Vec<u8>) {
peer.msgs_sent_since_pong += 1;
- peer.gossip_broadcast_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_message[..]));
+ peer.gossip_broadcast_buffer.push_back(encoded_message);
}
fn do_read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8]) -> Result<bool, PeerHandleError> {
}
(_, Some(ty)) if is_gossip_msg(ty) => {
log_gossip!(self.logger, "Got an invalid value while deserializing a gossip message");
- self.enqueue_message(peer, &msgs::WarningMessage { channel_id: [0; 32], data: "Unreadable/bogus gossip message".to_owned() });
+ self.enqueue_message(peer, &msgs::WarningMessage {
+ channel_id: [0; 32],
+ data: format!("Unreadable/bogus gossip message of type {}", ty),
+ });
continue;
}
(msgs::DecodeError::UnknownRequiredFeature, ty) => {
if except_node.is_some() && peer.their_node_id.as_ref() == except_node {
continue;
}
- self.enqueue_encoded_gossip_broadcast(&mut *peer, &encoded_msg);
+ self.enqueue_encoded_gossip_broadcast(&mut *peer, encoded_msg.clone());
}
},
wire::Message::NodeAnnouncement(ref msg) => {
if except_node.is_some() && peer.their_node_id.as_ref() == except_node {
continue;
}
- self.enqueue_encoded_gossip_broadcast(&mut *peer, &encoded_msg);
+ self.enqueue_encoded_gossip_broadcast(&mut *peer, encoded_msg.clone());
}
},
wire::Message::ChannelUpdate(ref msg) => {
if except_node.is_some() && peer.their_node_id.as_ref() == except_node {
continue;
}
- self.enqueue_encoded_gossip_broadcast(&mut *peer, &encoded_msg);
+ self.enqueue_encoded_gossip_broadcast(&mut *peer, encoded_msg.clone());
}
},
_ => debug_assert!(false, "We shouldn't attempt to forward anything but gossip messages"),
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
-use chain::keysinterface::{KeysInterface, Sign};
+use chain::keysinterface::KeysInterface;
use super::utils;
use ln::msgs::DecodeError;
use util::chacha20poly1305rfc::ChaChaPolyWriteAdapter;
///
/// Errors if less than two hops are provided or if `node_pk`(s) are invalid.
// TODO: make all payloads the same size with padding + add dummy hops
- pub fn new<Signer: Sign, K: KeysInterface, T: secp256k1::Signing + secp256k1::Verification>
+ pub fn new<K: KeysInterface, T: secp256k1::Signing + secp256k1::Verification>
(node_pks: &[PublicKey], keys_manager: &K, secp_ctx: &Secp256k1<T>) -> Result<Self, ()>
{
if node_pks.len() < 2 { return Err(()) }
let nodes = create_nodes(5);
let secp_ctx = Secp256k1::new();
- let blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap();
+ let blinded_route = BlindedRoute::new(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap();
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedRoute(blinded_route), None).unwrap();
pass_along_path(&nodes, None);
let nodes = create_nodes(4);
let secp_ctx = Secp256k1::new();
- let blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
+ let blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap();
pass_along_path(&nodes, None);
// 0 hops
let secp_ctx = Secp256k1::new();
- let mut blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
+ let mut blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
blinded_route.blinded_hops.clear();
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
assert_eq!(err, SendError::TooFewBlindedHops);
// 1 hop
- let mut blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
+ let mut blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
blinded_route.blinded_hops.remove(0);
assert_eq!(blinded_route.blinded_hops.len(), 1);
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
let secp_ctx = Secp256k1::new();
// Destination::Node
- let reply_path = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
+ let reply_path = BlindedRoute::new(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), Some(reply_path)).unwrap();
pass_along_path(&nodes, None);
// Make sure the last node successfully decoded the reply path.
format!("Received an onion message with path_id: None and reply_path").to_string(), 1);
// Destination::BlindedRoute
- let blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
- let reply_path = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
+ let blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
+ let reply_path = BlindedRoute::new(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), Some(reply_path)).unwrap();
pass_along_path(&nodes, None);
/// // Create a blinded route to yourself, for someone to send an onion message to.
/// # let your_node_id = hop_node_id1;
/// let hops = [hop_node_id3, hop_node_id4, your_node_id];
-/// let blinded_route = BlindedRoute::new::<InMemorySigner, _, _>(&hops, &keys_manager, &secp_ctx).unwrap();
+/// let blinded_route = BlindedRoute::new(&hops, &keys_manager, &secp_ctx).unwrap();
///
/// // Send an empty onion message to a blinded route.
/// # let intermediate_hops = [hop_node_id1, hop_node_id2];
/// Useful for simplifying the parameters of [`SimpleArcChannelManager`] and
/// [`SimpleArcPeerManager`]. See their docs for more details.
///
-///[`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager
-///[`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager
+/// (C-not exported) as `Arc`s don't make sense in bindings.
+///
+/// [`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager
+/// [`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager
pub type SimpleArcOnionMessenger<L> = OnionMessenger<InMemorySigner, Arc<KeysManager>, Arc<L>>;
/// Useful for simplifying the parameters of [`SimpleRefChannelManager`] and
/// [`SimpleRefPeerManager`]. See their docs for more details.
///
-///[`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager
-///[`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager
+/// (C-not exported) as general type aliases don't make sense in bindings.
+///
+/// [`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager
+/// [`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager
pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger<InMemorySigner, &'a KeysManager, &'b L>;
/// Construct onion packet payloads and keys for sending an onion message along the given
/// use the Persister to persist it.
pub trait WriteableScore<'a>: LockableScore<'a> + Writeable {}
+#[cfg(not(c_bindings))]
impl<'a, T> WriteableScore<'a> for T where T: LockableScore<'a> + Writeable {}
/// (C-not exported)
self.mac.raw_result(out_tag);
}
+ pub fn encrypt_full_message_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {
+ self.encrypt_in_place(input_output);
+ self.finish_and_get_tag(out_tag);
+ }
+
// Encrypt `input_output` in-place. To finish and calculate the tag, use `finish_and_get_tag`
// below.
pub(super) fn encrypt_in_place(&mut self, input_output: &mut [u8]) {
self.finished = true;
}
+ pub fn encrypt_full_message_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {
+ self.encrypt_in_place(input_output);
+ self.finish_and_get_tag(out_tag);
+ }
+
pub(super) fn encrypt_in_place(&mut self, _input_output: &mut [u8]) {
assert!(self.finished == false);
}
}
/// Trait that handles persisting a [`ChannelManager`], [`NetworkGraph`], and [`WriteableScore`] to disk.
-pub trait Persister<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref, S>
+pub trait Persister<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref, S: WriteableScore<'a>>
where M::Target: 'static + chain::Watch<Signer>,
T::Target: 'static + BroadcasterInterface,
K::Target: 'static + KeysInterface<Signer = Signer>,
F::Target: 'static + FeeEstimator,
L::Target: 'static + Logger,
- S: WriteableScore<'a>,
{
/// Persist the given ['ChannelManager'] to disk, returning an error if persistence failed.
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), io::Error>;
fn persist_scorer(&self, scorer: &S) -> Result<(), io::Error>;
}
-impl<'a, A: KVStorePersister, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref, S> Persister<'a, Signer, M, T, K, F, L, S> for A
+impl<'a, A: KVStorePersister, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref, S: WriteableScore<'a>> Persister<'a, Signer, M, T, K, F, L, S> for A
where M::Target: 'static + chain::Watch<Signer>,
T::Target: 'static + BroadcasterInterface,
K::Target: 'static + KeysInterface<Signer = Signer>,
F::Target: 'static + FeeEstimator,
L::Target: 'static + Logger,
- S: WriteableScore<'a>,
{
/// Persist the given ['ChannelManager'] to disk with the name "manager", returning an error if persistence failed.
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), io::Error> {
+++ /dev/null
-`broadcast_node_announcement` has been moved to `PeerManager` from `ChannelManager`.
-`PeerManager::new`'s new `current_time` argument must be set to a UNIX timestamp, not a persistent counter, for any existing nodes that upgrade.