Re: [Lightning-dev] [RFC] Lightning gossip alternative
Hi Rusty, > Timestamps are replaced with block heights. This is a conceptually small change, but would actually make things like rate limiting updates for implementations easier and more uniform. A simple rule would be only allowing an update per block, which cuts down a lot on potential chatter traffic, but maybe it's _too_ restrictive? Based on my network observations, these days some many power user nodes more aggressively update their fee schedules in response to liquidity imbalances or as an attempt to incentive usage of some channels vs others. > 1. Nodes send out weekly node_announcement_v2, proving they own some > UTXOs. If a node doesn't send out this announcement, then will others start to ignore their "channels"? > 3. This uses UTXOs for anti-spam, but doesn't tie them to channels > directly. As I hinted a bit in prior discussion, and also my recent ML [1] post outlining a possible "do most of the same things" stop gap, this has the potentially undesirable effect of allowing parties on the network to utilize _existing_ outputs to advertise false channels and inflate the "total network capacity" metric. We'd effectively be moving away from "Alice and Bob have N BTC of bound capacity between them to", "Bob has N BTC he can use for signing these proofs". Also while we're at it, why not add a merkle proof here (independent of which direction we go with) which makes it possible for constrained/mobile nodes to more easily verify gossip data (could be an optional query flag). > FIXME: what about tapscripts? Yeah, one side effect of moving to nodes advertising how much BTC they can sign w/ vs the _actual_ BTC they have in "channels", is that to extend validation here, the verifiers would need to fully verify possible script path spends (assuming a scenario where a NUMs point is used as the internal key). > Legacy proofs are two signatures, similar to the existing > channel_announcement. Why not musig2? We'd be able to get away with just a single sig with this modified `node_announcement_v2` and if we go the `channel_announcement2` route, we'd be able to compress those 4 sigs into one. > - If two node_announcement_v2 claim the same UTXO, use the first seen, > discard any others. So then this would mean that nodes that _actually_ have a channel between them can't _individually_ claim the capacity? > - node_announcement_v2 are discarded after a week (1000 blocks). - Nodes > do not need to monitor existence of UTXOs after initial check (since they > will automatically prune them after a week). A side effect of this would be _continual_ gossip churn in order to keep channels alive. Today we do have the 2 week `channel_update` heart beat, but channel updates are relatively small compared to this `node_announcement_v2` message. > - The total proved utxo value (not counting any utxos which are spent) is > multiplied by 10 to give the "announcable_channel_capacity" for that node. I don't see how this is at all useful in practice. We'd end up with inflated numbers for the total node capacity, and path finding would be more difficult as it isn't clear exactly how large an HTLC I can send over the "channel". Sure there's the existence of max_htlc, but in that case why add this "leverage" factor in the first place? > 1. type: 273 (`channel_update_v2`) This seems to allow the advertisement of channels which aren't actually anchored in the chain, which I *think* is a cool thing to have? On the other hand, the graph at the _edge_ level would be far more dynamic than it is today (Bob can advertise an entirely distinct topology from one day to another). Would need to think about the implications here for path finding algorithms and nodes that want to maintain an update to date view of the network... > - `channel_id_and_claimant` is a 31-bit per-node channel_id which can be > used in onion_messages, and a one bit stolen for the `claim` flag. Where would this `channel_id` be derived from? FWIW, using this value in the onion means we get a form of pubkey based routing [3] depending on how these are derived. > This simplifies gossip, requiring only two messages instead of three, > and reducing the UTXO validation requirements to per-node instead of > per-channel. I'm not sure this would actually _simplify_ gossip in practice, given that we'd be moving to a channel graph that isn't entirely based in the reality of what's routable, and would be far more dynamic than it is today. > We can use a convention that a channel_update_v2 with no `capacity` is a > permanent close. On the neutrino side, we tried to do something where if we see both channels be disabled, then we'd mark the channel as closed. But in practice if you're not syncing _every_ channel update every transmitted, then you'll end up actually missing them. > It also allows "leasing" of UTXOs: you could pay someone to sign their > UTXO for your node_announcement, with some level of trust. I'm not sure this is entirely a *good* thing, as the
[Lightning-dev] Taproot-aware Channel Announcements + Proof Verification
Hi y'all, On the lnd side we've nearly finished fully integrating taproot into the codebase [1] (which includes the btcsuite set of libraries and also full btcwallet support), scheduled to ship in 0.15 (~April), which will enable existing users of lnd's on-chain wallet and APIs to start getting taprooty wit it. As any flavor of taproot will mean a different on-chain funding output, the _existing_ gossip layer needs some sort of modification, as the BOLTs today don't define how to validate that a given output is actually a taproot channel. Discussions during the prior spec meetings seem to have centered in on two possible paths: 1. Use this as an opportunity to entirely redesign the channel validation portion of the gossip layer (ring sigs? zkps? less validation? better privacy?). 2. Defer the above, and instead go with a more minimal mostly the same channel_announcement-like message for taproot channels. In this mail, I want to explore the second option in detail, as Rusty has already started a thread on what option #1 may look like [2]. ## A new taproot-aware `channel_announcement2` message A simple `channel_announcement2` message that was taproot aware could look something like: 1. type: xxx (`channel_announcement2`) 2. data: * [`signature`:`announcement_sig`] * [`u16`:`len`] * [`len*byte`:`features`] * [`chain_hash`:`chain_hash`] * [`short_channel_id`:`short_channel_id`] * [`point`:`node_id_1`] * [`point`:`node_id_2`] * [`point`:`bitcoin_key_1`] * [`point`:`bitcoin_key_2`] (can assume it'll be just native TLV prob also) This is pretty much the same as the _existing_ `channel_announcement` message but instead of us carrying around 4 signatures, we'd use musig2 to generate a _single_ signature under the aggregate public key (`node_id_1`+`node_id_2`+`bitcoin_key_1`+`bitcoin_key_2`). While were here, similar to what's been proposed in [2], it likely makes sense to add an optional (?) merkle proof here to make channel validation more feasible for constrained/mobile clients (they don't need to fetch all those blocks any longer). The tradeoff here is that the merkle proof would potentially be the largest part of the message, which means more on-chain data needed to store the full channel graph. Alternatively, we could make this into another gossip query option, with nodes only fetching the proofs if they actually need it (full nodes with a txindex and just fetch the transaction). ### Should the proof+verification strongly bind to the LN context? As far as on-chain output validation, the main difference would be how nodes actually validate the Bitcoin output (referenced by the `short_channel_id`) on chain. Today, nodes use the two bitcoin keys and construct a p2wsh multi-sig script and then verify that the script matches what has been confirmed on chain. With taproot, the output is actually just a single key. So if we want to maintain the same level of binding (which makes it harder to advertise fake channels using just a change output have or something), then we'd specify that nodes reconstruct the aggregated bitcoin public key (Q = a_1*B_1 + a_2*_B_2, where a_i is a blinding factor derived using the target key and every other key in the signing set) and assert that this matches the pkScript on chain. By verifying that this output key is just an aggregated key, then we can also ensure that there's no actual committed script root (a la BIP 86 [3]) which binds the output to our context further. However maybe we want to also include a `tapscript_root` field as well (so use the musig2 key as the internal key and then apply the tweaking operations and verify things match up), which would enable more elaborate unlocking/multi-sig functionality for the normal funding output. Alternatively, if we decided that this strong binding isn't as desirable (starting to get into option 1 territory), then we'd specify just a single Bitcoin key and look for that directly in the on chain script. IMO, if we're going the route of something that very closely resembles what we have today, then we shouldn't drop the strong binding, and fully verify that the key is indeed a musig2 aggregated public key. ## `announcement_signatures2` and musig2 awareness The `announcement_signatures` message would also need to change as we'd only be sending a single signature across the wire: the musig2 _partial_ signature. 1. type: xxx (`announcement_signatures2`) 2. data: * [`channel_id`:`channel_id`] * [`short_channel_id`:`short_channel_id`] * [`signature`:`partial_chan_proof_sig`] Once both sides exchange this, as normal either party can generate the `channel_announcement` message to broadcast to the network. The addition of musig2 carries with it an additional dependency: before these signatures can be generated, both sides need to exchange their public nonce (in practice it's two nonces points R_1 and R_2), which is then used to generate the aggregated nonce using for sign
Re: [Lightning-dev] A Proposal for Adding Bandwidth Metered Payment to Onion Messages
Hi Rusty, > AMP seems to be a Lightning Labs proprietary extension. You mean keysend, > which at least has a draft spec? I'm confused: the keyspend specification lives today as a very succinct bLIP [1] (use this record that contains the preimage settle the payment), and the AMP spec has had an open PR [2] (which admittedly needs to be mega-rebased) for sometime now and is amongst the oldest PRs in the BOLT tracker. Your definition of a "proprietary extension" here would seem to cover just about every open BOLT pull request that hasn't yet been widely adopted by multiple implementations. With that aside, AMP is used here instead of keysend as each payment split uses a different payment hash, which makes it harder to correlate payment splits as both the amount and hash will differ. Also given that the e2e payment needs to drop off additional fees (to pay for the forwarding pass) to each hop, the receiver doesn't actually know how much to expect as total payment (no invoice exists in this scenario). With keysend, it's possible the receiver accidentally pulls early, with the funds irrevocably sent, while no true onion messaging session has been constructed. With AMP the sender is the one that controls _when_ all the funds can be pulled, which eliminates such edge cases. > Sure, let's keep encouraging people to use HTLCs for free to send data? I > can certainly implement that if you prefer! I think the difference here is that HTLCs aren't that great for sending data: any space you allocate to arbitrary data takes away from the total route length. Also given the existence of the max_htlc parameters in channel updates, nodes can increase this value which allows them to discourage certain classes of behavior, as the HTLC that transmits the data serves effectively as an ephemeral bond, meaning that HTLC data transfer attempts incur an opportunity cost w.r.t the capital locked up. As a result, what's deployed in the wild today that uses HTLCs to send data (importantly at no additional marginal cost, since you sling 1.3KB across the wire anyway for normal payments), imo is mostly cases that only need a smaller amount of data, or use it mainly as a signalling layer. In contrast, onion messaging would allow users to send 32 KB (and beyond?), which makes certain classes of applications more feasible. > I suggest naively limiting to 10/sec for peers with channels, and 1/sec > for peers without for now. Curious to see what a fleshed out version of this would look like. IMO if this rate limiting event doesn't somehow make it back to the sender, then it isn't clear exactly why they're unable to even fetch an invoice to _attempt_ a payment. I think one issue with defaulting to always fetching invoices in a multi-hop manner is that a node failure may mean that a user can't even obtain an invoice, compared to just hitting an API or scanning a QR code that encodes one (pretty much 99% chance of success). (I think there's also a side discussion here w.r.t if tightly coupling an invoice/offer to a single node is compatible with the multi-node receive architectures that some services are beginning to develop/deploy, but we can make another thread for that.) > You mean: > 1. Don't use an even TLV field. I don't see why one _wouldn't_ use an even field here: if the node doesn't know what this means, then I want them to reject the payment, as otherwise they aren't able to properly do the bandwidth metering. Even assuming a feature bit, I think an even field would make sense, but ofc I'm open to further reasoning. > I think it's a premature optimization? Make standard duration 2016 > blocks; then they can request multiples if they want? Reduces > node_announcement size. Hmm, potentially but if I just need this to ask a node about their latest ephemeral onion service, do I really need the session to persist for 2016 blocks? At just 8 bytes here, it's smaller than a tor v3 onion address and even most feature bit distributions. Also there's nothing stopping someone from advertising optional feature bit 12,324 which means that nodes need to lug around and store all those extra bytes. > I'd be tempted to use 16 bytes? Collisions here are not really a thing > since you'd need a network packet per probe, and you're time limited. Yeah if the 32 bytes for each hop ends up eating too much into the total route length, then most use cases can get by with 16 bytes. > AFAICT this is easy to implement on top of onion_messages as they stand > today (if you don't want to fwd free onion messages at all, don't set > that bit?). Correct! The idea is to give nodes that don't want to forward for free an option to charge for forwarding and supplement their existing routing node revenue. On Twitter, Lisa brought up that as the data forwarding and payment aren't "atomic", you're reliant on the nodes to actually "do the thing" once the payment has been completed. This is correct, and imo can be mitigated mainly via a "tit for tat approac