Christian Decker [ARCHIVE] on Nostr: 📅 Original date posted:2018-02-09 📝 Original message: Rusty Russell <rusty at ...
📅 Original date posted:2018-02-09
📝 Original message:
Rusty Russell <rusty at rustcorp.com.au> writes:
> Finally catching up. I prefer the simplicity of the timestamp
> mechanism, with a more ambitious mechanism TBA.
Fabrice and I had a short chat a few days ago and decided that we'll
simulate both approaches and see what consumes less bandwidth. With
zombie channels and the chances for missing channels during a weak form
of synchronization, it's not that clear to us which one has the better
tradeoff. With some numbers behind it it may become easier to decide :-)
> Deployment suggestions:
>
> 1. This should be a feature bit pair. As usual, even == 'support this or
> disconnect', and odd == 'ok even if you don't understand'.
If we add the timestamp to the end of the `init` message, instead of
introducing a new message altogether, we are forced to use the required
bit, otherwise we just made any future field appended to the `init`
message unparseable to non-supporting nodes. Let's say we add another
field to it later, that the peer supports, but it follows the timestamp
which the peer does not. The peer doesn't know how many bytes to skip
(if any) for the timestamp bit he doesn't understand, to get to the
bytes he does know how to parse. I'm slowly getting to like the extra
message more, since it also allows a number of cute tricks later.
> 2. This `timestamp_routing_sync`? feature overrides `initial_routing_sync`.
> That lets you decide what old nodes do, using the older
> `initial_routing_sync` option. Similarly, a future `fancy_sync` would
> override `timestamp_routing_sync`.
So you'd set both bits, and if the peer knows `timestamp_routing_sync`
that then force-sets the `initial_routing_sync`? Sounds ok, if we allow
optional implementations, even though I'd like to avoid feature
interactions as much as possible.
> 3. We can append an optional 4 byte `routing_sync_timestamp` field to to
> `init` without issues, since all lengths in there are explicit. If you
> don't offer the `timestamp_sync` feature, this Must Be Zero (for appending
> more stuff in future).
That'd still require the peer to know that it has to skip 4 bytes to get
any future fields, which is why I am convinced that either forcing it to
be mandatory, or adding a new message is the better way to go, even if
now everybody implements it correctly.
> Now, as to the proposal specifics.
>
> I dislike the re-transmission of all old channel_announcement and
> node_announcement messages, just because there's been a recent
> channel_update. Simpler to just say 'send anything >=
> routing_sync_timestamp`.
I'm afraid we can't really omit the `channel_announcement` since a
`channel_update` that isn't preceded by a `channel_announcement` is
invalid and will be dropped by peers (especially because the
`channel_update` doesn't contain the necessary information for
validation).
> Background: c-lightning internally keeps an tree of gossip in the order
> we received them, keeping a 'current' pointer for each peer. This is
> very efficient (though we don't remember if a peer sent us a gossip msg
> already, so uses twice the bandwidth it could).
We can solve that by keeping a filter of the messages we received from
the peer, it's more of an optimization than anything, other than the
bandwidth cost, it doesn't hurt.
> But this isn't *quite* the same as timestamp order, so we can't just set
> the 'current' pointer based on the first entry >=
> `routing_sync_timestamp`; we need to actively filter. This is still a
> simple traverse, however, skipping over any entry less than
> routing_sync_timestamp.
>
> OTOH, if we need to retransmit announcements, when do we stop
> retransmitting them? If a new channel_update comes in during this time,
> are we still to dump the announcements? Do we have to remember which
> ones we've sent to each peer?
That's more of an implementation detail. In c-lightning we can just
remember the index at which the initial sync started, and send
announcements along until the index is larger than the initial sync
index.
A more general approach would be to have 2 timestamps, one highwater and
one lowwater mark. Anything inbetween these marks will be forwarded
together with all associated announcements (node / channel), anything
newer than that will only forward the update. The two timestamps
approach, combined with a new message, would also allow us to send
multiple `timestamp_routing_sync` messages, e.g., first sync the last
hour, then the last day, then the last week, etc. It gives the syncing
node control over what timewindow to send, inverting the current initial
sync.
Cheers,
Christian
📝 Original message:
Rusty Russell <rusty at rustcorp.com.au> writes:
> Finally catching up. I prefer the simplicity of the timestamp
> mechanism, with a more ambitious mechanism TBA.
Fabrice and I had a short chat a few days ago and decided that we'll
simulate both approaches and see what consumes less bandwidth. With
zombie channels and the chances for missing channels during a weak form
of synchronization, it's not that clear to us which one has the better
tradeoff. With some numbers behind it it may become easier to decide :-)
> Deployment suggestions:
>
> 1. This should be a feature bit pair. As usual, even == 'support this or
> disconnect', and odd == 'ok even if you don't understand'.
If we add the timestamp to the end of the `init` message, instead of
introducing a new message altogether, we are forced to use the required
bit, otherwise we just made any future field appended to the `init`
message unparseable to non-supporting nodes. Let's say we add another
field to it later, that the peer supports, but it follows the timestamp
which the peer does not. The peer doesn't know how many bytes to skip
(if any) for the timestamp bit he doesn't understand, to get to the
bytes he does know how to parse. I'm slowly getting to like the extra
message more, since it also allows a number of cute tricks later.
> 2. This `timestamp_routing_sync`? feature overrides `initial_routing_sync`.
> That lets you decide what old nodes do, using the older
> `initial_routing_sync` option. Similarly, a future `fancy_sync` would
> override `timestamp_routing_sync`.
So you'd set both bits, and if the peer knows `timestamp_routing_sync`
that then force-sets the `initial_routing_sync`? Sounds ok, if we allow
optional implementations, even though I'd like to avoid feature
interactions as much as possible.
> 3. We can append an optional 4 byte `routing_sync_timestamp` field to to
> `init` without issues, since all lengths in there are explicit. If you
> don't offer the `timestamp_sync` feature, this Must Be Zero (for appending
> more stuff in future).
That'd still require the peer to know that it has to skip 4 bytes to get
any future fields, which is why I am convinced that either forcing it to
be mandatory, or adding a new message is the better way to go, even if
now everybody implements it correctly.
> Now, as to the proposal specifics.
>
> I dislike the re-transmission of all old channel_announcement and
> node_announcement messages, just because there's been a recent
> channel_update. Simpler to just say 'send anything >=
> routing_sync_timestamp`.
I'm afraid we can't really omit the `channel_announcement` since a
`channel_update` that isn't preceded by a `channel_announcement` is
invalid and will be dropped by peers (especially because the
`channel_update` doesn't contain the necessary information for
validation).
> Background: c-lightning internally keeps an tree of gossip in the order
> we received them, keeping a 'current' pointer for each peer. This is
> very efficient (though we don't remember if a peer sent us a gossip msg
> already, so uses twice the bandwidth it could).
We can solve that by keeping a filter of the messages we received from
the peer, it's more of an optimization than anything, other than the
bandwidth cost, it doesn't hurt.
> But this isn't *quite* the same as timestamp order, so we can't just set
> the 'current' pointer based on the first entry >=
> `routing_sync_timestamp`; we need to actively filter. This is still a
> simple traverse, however, skipping over any entry less than
> routing_sync_timestamp.
>
> OTOH, if we need to retransmit announcements, when do we stop
> retransmitting them? If a new channel_update comes in during this time,
> are we still to dump the announcements? Do we have to remember which
> ones we've sent to each peer?
That's more of an implementation detail. In c-lightning we can just
remember the index at which the initial sync started, and send
announcements along until the index is larger than the initial sync
index.
A more general approach would be to have 2 timestamps, one highwater and
one lowwater mark. Anything inbetween these marks will be forwarded
together with all associated announcements (node / channel), anything
newer than that will only forward the update. The two timestamps
approach, combined with a new message, would also allow us to send
multiple `timestamp_routing_sync` messages, e.g., first sync the last
hour, then the last day, then the last week, etc. It gives the syncing
node control over what timewindow to send, inverting the current initial
sync.
Cheers,
Christian