The peer eltoo channel protocol has three phases: establishment, normal operation, and closing.
- Channel
- Authors
Same as BOLT02 definition
When option_eltoo
is negotiated, this message contains information about
a node and indicates its desire to set up a new eltoo channel. This is the first
step toward creating the funding transaction and the initial update transaction.
-
type: 32778 (
open_channel_eltoo
) -
data:
- [
chain_hash
:chain_hash
] - [
32*byte
:temporary_channel_id
] - [
u64
:funding_satoshis
] - [
u64
:push_msat
] - [
u64
:max_htlc_value_in_flight_msat
] - [
u64
:htlc_minimum_msat
] - [
u16
:shared_delay
] - [
u16
:max_accepted_htlcs
] - [
point
:funding_pubkey
] - [
point
:htlc_pubkey
] - [
point
:settlement_pubkey
] - [
byte
:channel_flags
] - [
nonce
:next_nonce
] - [
open_channel_eltoo_tlvs
:tlvs
]
- [
-
tlv_stream
:open_channel_eltoo_tlvs
-
types:
- type: 0 (
upfront_shutdown_script
) - data:
- [
...*byte
:shutdown_scriptpubkey
]
- [
- type: 1 (
channel_type
) - data:
- [
...*byte
:type
]
- [
- type: 0 (
Changed fields from open_channel
:
to_self_delay
is replaced with a symmetricalshared_delay
which must be agreed upon by nodes. This is currently set by the opener.dust_limit_satoshis
is removed in favor of a static limit of 330 satoshis to support taproot outputs.- there is no
revocation_basepoint
as the security of the eltoo design does not rely on penalty transactions - there is no
delayed_payment_basepoint
, as there are no second-stage HTLC transactions to be pre-signed payment_basepoint
is replaced with a staticsettlement_pubkey
- no
feerate_per_kw
as there is no up-front negotiated fee for update or settlement transactions first_per_commitment_point
is removed- there is no
channel_reserve_satoshis
next_nonce
Sending node:
- SHOULD set
shared_delay
to a reasonable number
A receiving node:
- MUST either accept the
shared_delay
given by the sender, of fail the channel - if
next_nonce
is not a valid BIP-musig2 public nonce- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- otherwise MUST store and apply
next_nonce
to the associatedfunding_created
transaction, unless channel reestablishment occurs, in which the nonces must be discarded
The symmetrical transaction state among all peers means that we can simplify some aspects while requiring additional range negotiation in others.
Reserve requirements are removed as there are no penalty transactions.
The currently defined types are:
- FIXME option_scid_alias and option_zeroconf now exist, support them
- no features (no bits set)
This message contains information about a node and indicates its
acceptance of the new eltoo channel initiated by open_channel_eltoo
. This
is the second step toward creating the funding, update, and settlement
transactions.
-
type: 32769 (
accept_channel_eltoo
) -
data:
- [
32*byte
:temporary_channel_id
] - [
u64
:max_htlc_value_in_flight_msat
] - [
u64
:htlc_minimum_msat
] - [
u32
:minimum_depth
] - [
u16
:shared_delay
] - [
u16
:max_accepted_htlcs
] - [
point
:funding_pubkey
] - [
point
:htlc_pubkey
] - [
point
:settlement_pubkey
] - [
nonce
:next_nonce
] - [
accept_channel_eltoo_tlvs
:tlvs
]
- [
-
tlv_stream
:accept_channel_eltoo_tlvs
-
types:
- type: 0 (
upfront_shutdown_script
) - data:
- [
...*byte
:shutdown_scriptpubkey
]
- [
- type: 1 (
channel_type
) - data:
- [
...*byte
:type
]
- [
- type: 0 (
The same requirements as accept_channel
, except a few redundant fields removed.
Sending node:
-
MUST set
shared_delay
to the same value as received inopen_channel
-
if
next_nonce
is not a valid BIP-musig2 public nonce- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
-
otherwise MUST store and apply
next_nonce
to the associatedfunding_signed_eltoo
partial signature, unless channel reestablishment occurs, in which the nonce must be discarded
Symmetrical state means fewer parameters are required compared to accept_channel
channel type.
This message describes the outpoint which the funder has created for
the initial update and settlement transactions. After receiving the peer's
signature, via funding_signed_eltoo
, it will broadcast the funding transaction.
- type: 32770 (
funding_created_eltoo
) - data:
- [
32*byte
:temporary_channel_id
] - [
sha256
:funding_txid
] - [
u16
:funding_output_index
] - [
partial_sig
:update_psig
] - [
nonce
:next_nonce
]
- [
Requirements are identical to funding_created
except:
There is no signature
field sent, or required.
The sender MUST set:
update_psig
to the valid partial signature using itsfunding_pubkey
for the initial update transaction and the previously sentnonce
s fromopen_channel_eltoo
andaccept_channel_eltoo
messages, as defined in BOLT #???.next_nonce
to a valid BIP-musig2 nonce to be used for the next channel update during the same connection
The recipient:
- if
update_psig
is not a valid BIP-musig2 partial signature for the update transaction:- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- if
next_nonce
is not a valid BIP-musig2 nonce- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- otherwise MUST store and apply
next_nonce
to the next channel update, unless channel reestablishment occurs, in which the nonces must be discarded
This message gives the funder the remote partial signature it needs for the first
update transaction, so it can broadcast the transaction knowing that funds
can be redeemed, if need be. It is sent in response to funding_created_eltoo
.
This message introduces the channel_id
to identify the channel. It's derived from the funding transaction by combining the funding_txid
and the funding_output_index
, using big-endian exclusive-OR (i.e. funding_output_index
alters the last 2 bytes).
- type: 32771 (
funding_signed_eltoo
) - data:
- [
channel_id
:channel_id
] - [
partial_sig
:update_psig
] - [
nonce
:next_nonce
]
- [
Both peers:
- if
channel_type
was present in bothopen_channel
andaccept_channel
and is not empty(no bits set):- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- otherwise:
- the
channel_type
is empty
- the
- MUST use that
channel_type
for all transactions.
The sender MUST set:
channel_id
by exclusive-OR of thefunding_txid
and thefunding_output_index
from thefunding_created_eltoo
message.update_psig
to the valid BIP-musig2 partial signature, using itsfunding_pubkey
for the initial update transaction, and the previously sentnonce
s fromopen_channel_eltoo
andaccept_channel_eltoo
messages as defined in BOLT #??.next_nonce
to a valid BIP-musig2 nonce to be used for the next channel update during the same connection
The recipient:
- if
update_psig
is an invalida partial signature for the corresponding update transaction:- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- MUST NOT broadcast the funding transaction before receipt of a valid
funding_signed_eltoo
. - on receipt of a valid
funding_signed_eltoo
:- SHOULD broadcast the funding transaction.
- if
next_nonce
is not a valid BIP-musig2 nonce- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- otherwise MUST store and apply
next_nonce
to the next channel update, unless channel reestablishment occurs, in which the nonces must be discarded
The same implications as channel_ready
, but for an eltoo channel.
- type: 32772 (
channel_ready_eltoo
) - data:
- [
channel_id
:channel_id
]
- [
The sender MUST:
- NOT send
channel_ready_eltoo
unless outpoint of given byfunding_txid
andfunding_output_index
in thefunding_created_eltoo
message pays exactlyfunding_satoshis
to the scriptpubkey specified in BOLT #3. - wait until the funding transaction has reached
minimum_depth
before sending this message.
A non-funding node (fundee):
- SHOULD forget the channel if it does not see the correct funding transaction after a timeout of 2016 blocks.
From the point of waiting for channel_ready_eltoo
onward, either node MAY
send an error
and fail the channel if it does not receive a required response from the
other node after a reasonable timeout.
Same rationale as channel_ready
.
Closing happens in two stages:
-
one side indicates it wants to clear the channel (and thus will accept no new HTLCs)
-
once all HTLCs are resolved, the final channel close negotiation begins.
+-------+ +-------+ | |--(1)----- shutdown_eltoo -------->| | | |<-(2)----- shutdown_eltoo ---------| | | | | | | | <complete all pending HTLCs> | | | A | ... | B | | | | | | |--(3)-- closing_signed_eltoo F1--->| | | |<-(4)-- closing_signed_eltoo F2----| | | | ... | | | |--(?)-- closing_signed_eltoo Fn--->| | | |<-(?)-- closing_signed_eltoo Fn----| | +-------+ +-------+
Either node (or both) can send a shutdown_eltoo
message to initiate closing,
along with the scriptpubkey
it wants to be paid to.
- type: 32773 (
shutdown_eltoo
) - data:
- [
channel_id
:channel_id
] - [
u16
:len
] - [
len*byte
:scriptpubkey
] - [
nonce
:nonce
]
- [
Same requirements as shutdown
, but with corresponding _eltoo
messages.
In addition:
A sending node:
- MUST set the
nonce
to a valid bip-musig2 public nonce.
A receiving node:
- MUST verify that the
nonce
value is a valid bip-musig2 public nonce.
Nonces are pre-shared here to allow closing transaction partial
signatures to be sent immediately via closing_signed_eltoo
,
as described below.
The eltoo-variant of closing_signed
which is sent in the same situation,
but for eltoo channels.
Fee negotiation is done in an identical manner as closing_signed
.
-
type: 32774 (
closing_signed_eltoo
) -
data:
- [
channel_id
:channel_id
] - [
u64
:fee_satoshis
] - [
closing_signed_eltoo_tlvs
:tlvs
]
- [
-
tlv_stream
:closing_signed_eltoo_tlvs
-
types:
- type: 1 (
fee_range
) - data:
- [
u64
:min_fee_satoshis
] - [
u64
:max_fee_satoshis
]
- [
- type: 2 (
nonces
) - data:
- [
nonce
:nonce
]
- [
- type: 3 (
partial_sig
) - data:
- [
partial_sig
:partial_sig
]
- [
- type: 1 (
A sending node:
- MUST include
closing_signed_eltoo_tlvs
. - MUST include a tlv for
nonces
. - MUST set
nonce
to valid MuSig2 nonce with secure randomness, to be used for the nextclosing_signed_eltoo
round of fee negotiation. - MUST include a tlv for
partial_sig
:- The partial signature must be generated by using the combined public nonces exchanged last by
shutdown_eltoo
messages orclosing_signed_eltoo
messages, and the private nonce generated by the signing node, as per BIPMuSig2.
- The partial signature must be generated by using the combined public nonces exchanged last by
A node receiving the first messaging round:
- If message does not include
closing_signed_eltoo_tlvs
:- MUST fail the channel.
- If a tlv for
nonces
is not included or is not a valid MuSig2 public nonce as per BIPMuSig2:- MUST fail the channel.
- Otherwise, the
nonce
will be used to generated the aggregated nonce for the next closing transaction signing, if any. - If a tlv for
partial_sig
is not included, not valid, or when combined through BIPMuSig2 does not result in a valid BIP340 signature for the closing transaction:- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
Fee negotiation is followed as required in parallel.
We use MuSig2 multisignature algorithm to close eltoo channels. This allows a healthy operating channel to appear to be a single pubkey output even after being spent, reducing fees in the common case and increasing the anonymity set.
It's critically important that nonces are never re-used; the recommendation that the nonces be wiped in between sessions is paramount for security of funds.
If open_channel_eltoo
was used to initiate the channel, a simple turn-taking approach
is taken for channel updates.
+-------+ +-------+
| |--(1)---- update_add_htlc ---------->| |
| |--(2)---- update_add_htlc ---------->| |
| |--(3)--- update_signed ------------->| |
| A |<--(4)--- update_signed_ack ---------| B |
| | | |
| |<-(5)---- update_add_htlc -----------| |
| |<-(6)--- update_signed --------------| |
| |--(7)-- update_signed_ack ---------->| |
| | | |
+-------+ +-------+
Note that once the recipient of an HTLC offer receives a
update_signed
message, the new offers may be forwarded immediately
as the update and settlement transactions can be finalized locally and broadcasted at any point.
The recipient would be able to take this latest state on-chain if necessary, even if older state is broadcast.
-
type: 129 (
update_noop
) (option_simplified_update
) -
data:
- [
channel_id
:channel_id
]
- [
-
type: 138 (
yield
) (option_simplified_update
) -
data:
- [
channel_id
:channel_id
]
- [
A node:
- MUST NOT send
yield
unlessoption_simplified_update
is negotiated. - MUST track whose turn it is, starting on channel creation with the peer with the lesser SEC1-encoded node_id.
- MUST give up its turn when:
- sending
update_signed
- sending a
yield
- sending
- MUST accept its turn when:
- receiving
update_signed
- receiving a
yield
- receiving
- During this node's turn:
- if it receives an update message or
update_signed
:- if it has sent its own update or
update_signed
:- MUST ignore the message
- otherwise:
- MUST reply with
yield
and process the message.
- MUST reply with
- if it has sent its own update or
- if it received
update_noop
:- MUST otherwise ignore the message
- if it receives an update message or
- During the other node's turn:
- if it has not received an update message or
update_signed
:- MAY send one or more update message or
update_signed
:- MUST NOT include those changes if it receives an update message or
update_signed
in reply. - MUST include those changes if it receives a
yield
in reply.
- MUST NOT include those changes if it receives an update message or
- MAY send one or more update message or
- if it has not received an update message or
and channel reestablishment, defined by channel_reestablish_eltoo
A simple implementation can send an update message out-of-turn and
wait for a yield
before sending update_signed
: this ensures
that there only ever one commitment state at any time, at cost of
round-trip latency for any out-of-turn changes.
For simplicity, an update_noop
can be used to prompt a yield
with
no other effects.
A more complex implementation can optimistically send a complete set
of updates and commitment_signed
, but must handle the possibility of
that commitment being spent on-chain even if the peer does not yield.
FIXME: Nonces currently do not support this, since you MUST NOT reuse
nonces ever. This means we need a nonce for every version of the state.
Each stored nonce is "assigned" to a turn taker, so to speak.
Note that the reconnection logic is similarly simplified for an
implementation which always waits for yield
: both nodes cannot have
a commitment in flight simultanously, so if messages are lost due to
disconnection that is detectable and it simply replays its turn. If
an implementation optimistically sends commitment_signed
, then it
assumes was either lost and does not apply, or the yield
reply was
lost and the next_commitment_number
test will correctly indicate its
turn.
Synchronous turn-taking allows for a simpler protocol, while still allowing for optimistic behavior to be implemented if higher transactional velocity is desired. Eltoo transactions are symmetrical, so they naturally fit this paradigm.
HTLC forwarding logic has been adapted to the symmetrical transaction state
case of eltoo but uses the same messages as BOLT02 aside from update_signed
and update_signed_ack
:.
The respective addition/removal of an HTLC is considered irrevocably committed when:
- The settlement transaction with/without it is committed to by the offering node by
the
update_signed
message. - The settlement transaction with/without it has been irreversibly committed to the blockchain.
A node:
- until an incoming HTLC has been irrevocably committed:
- MUST NOT offer the corresponding outgoing HTLC (
update_add_htlc
) in response to that incoming HTLC.
- MUST NOT offer the corresponding outgoing HTLC (
- until the removal of an outgoing HTLC is irrevocably committed, OR until the outgoing on-chain HTLC output has been spent (with sufficient depth):
- MUST NOT fail the incoming HTLC (
update_fail_htlc
) that corresponds to that outgoing HTLC.
- MUST NOT fail the incoming HTLC (
- once the
cltv_expiry
of an incoming HTLC has been reached, OR ifcltv_expiry
minuscurrent_height
is less thancltv_expiry_delta
for the corresponding outgoing HTLC:- MUST fail that incoming HTLC (
update_fail_htlc
).
- MUST fail that incoming HTLC (
- if an incoming HTLC's
cltv_expiry
is unreasonably far in the future:- SHOULD fail that incoming HTLC (
update_fail_htlc
).
- SHOULD fail that incoming HTLC (
- upon receiving an
update_fulfill_htlc
for an outgoing HTLC, OR upon discovering thepayment_preimage
from an on-chain HTLC spend:- MUST fulfill the incoming HTLC that corresponds to that outgoing HTLC.
Same rationale as BOLT02 except we do not have HTLC-Success and HTLC-Timeout second-stage transactions.
The shared_delay
should be picked up to allow a node to confirm a higher
state update transaction spending a currently confirmed lower state update transaction.
Delay should be lengthy enough to give enough margin to the node to react to
sudden network mempools congestion spikes. Historically, the default reaction
delays of LN node implementations have been as low as 6 and as high as 144 blocks.
With eltoo channels, the shared_delay
must be included in the cltv_expiry_delta
selection, and therefore should be considered as an offset in the worst-case of
on-chain timeout or fulfillement of HTLC outputs. While it offers more reaction
block time and increase the channel funds safety, higher cltv_expiry_delta
are
penalized by Lightning scoring algorithms. As such for a routing node operator,
there is a trade-off between safety and routing forwarding competitiveness.
Expiry of HTLCs in Eltoo must consider the shared_delay
parameter, as that is in the
critical path of resolving the contract.
One particular troublesome scenario:
- A node commits to a specific HTLC using
update_signed
message - Counterparty goes to chain with the penultimate state that was signed by both parties
- Counterparty waits
shared_delay
- 1 blocks, then submits the final state the node committed to.
This results in almost 2 times shared_delay
of HTLC resolutions possible.
cltv_expiry_delta
should take the above 2*shared_delay
and add it to
the value considered independently for timely inclusion once the settlement path
is spendable. See the considerations for BOLT02 for choosing this component of the value.
Same requirements as BOLT02
ame requirements as BOLT02
When a node has changes for the shared update for an eltoo channel, it can apply them,
sign the resulting transaction (as defined in BOLT #??), and send a
update_signed
message.
Once the recipient of update_signed
checks the partial signature and knows
it has a valid new update transaction, it replies with its own update_signed_ack
message over the same transactions and its own partial signature to ACK the updates and finalize
the state update.
- type: 32775 (
update_signed
) - data:
- [
channel_id
:channel_id
] - [
partial_sig
:update_psig
] - [
nonce
:next_nonce
]
- [
Separating update_signed
from update_signed_ack
allows for
slightly simpler logic and disambiguation of message intent.
A sending node:
- during their turn(or when attempting to cause the counter-party to yield):
- MUST NOT send a
update_signed
message that does not include any updates.
- MUST NOT send a
- otherwise:
- MUST NOT propose any changes
A receiving node:
- during another's turn:
- once all pending updates are applied:
- if
update_psig
is not valid for update transaction:- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- if
next_nonce
is not a valid BIP-musig2 nonce- MUST MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST MUST send a
- if
- otherwise MUST respond with a
update_signed_ack
message of their own. - MUST consider the transaction as committed by the sender
- once all pending updates are applied:
HTLCs outputs do not require signatures by the offerer, which is why only a single signature for update transactions is required at this stage. Settlement transactions use a covenant commitment, therefore they do not require another signature as well.
- type: 32776 (
update_signed_ack
) - data:
- [
channel_id
:channel_id
] - [
partial_sig
:update_psig
] - [
nonce
:next_nonce
]
- [
A sending node:
- MUST set
update_psig
to a valid partial signature for the update transaction as defined in BOLT #??. - MUST set
next_nonce
to a valid BIP-musig2 nonce.
A receiving node:
- during another's turn:
- if
update_psig
is not valid for update transaction:- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
- if
next_nonce
is not a valid BIP-musig2 nonce- MUST MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST MUST send a
- if
No fees are attached to update or settlement transactions and instead rely on ephemeral anchors for bringing fees, so this message is invalid.
A receiving node:
- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- type: 32777 (
channel_reestablish_eltoo
) - data:
- [
channel_id
:channel_id
] - [
u64
:last_update_number
] - [
partial_sig
:update_psig
] - [
nonce
:fresh_nonce
]
- [
Reestablishment of eltoo channels is handled similarly
to the penalty-based simplified update scheme with
the extraneous fields removed and using the _eltoo
based messages respectively.
A funding node:
- upon disconnection:
- if it has broadcast the funding transaction:
- MUST remember the channel for reconnection.
- otherwise:
- SHOULD NOT remember the channel for reconnection.
- if it has broadcast the funding transaction:
A non-funding node:
- upon disconnection:
- if it has sent the
funding_signed_eltoo
message:- MUST remember the channel for reconnection.
- otherwise:
- SHOULD NOT remember the channel for reconnection.
- if it has sent the
A node:
- MUST handle continuation of a previous channel on a new encrypted transport.
- upon disconnection:
- MUST reverse any uncommitted updates sent by the other side (i.e. all
messages beginning with
update_
for which noupdate_signed
has been received).- Note: a node MAY have already used the
payment_preimage
value from theupdate_fulfill_htlc
, so the effects ofupdate_fulfill_htlc
are not completely reversed.
- Note: a node MAY have already used the
- MUST discard any secret MuSig2 nonces for the channel
- MUST reverse any uncommitted updates sent by the other side (i.e. all
messages beginning with
- upon reconnection:
- if a channel is in an error state:
- SHOULD retransmit the error packet and ignore any other packets for that channel.
- otherwise:
- MUST transmit
channel_reestablish_eltoo
for each channel. - MUST wait to receive the other node's
channel_reestablish_eltoo
message before sending any other messages for that channel.
- MUST transmit
- if a channel is in an error state:
A sending node:
- MUST set
last_update_number
to the value of the channel state number of the last partial signature the node has sent to its peer. - If it has sent
update_signed
on the other peer's turn without receivingyield
:- MUST NOT consider that
update_signed
sent when settinglast_update_number
.
- MUST NOT consider that
- MUST set
update_psig
to thelast_update_number
channel state update transaction's partial signature created by the local node. - MUST set
fresh_nonce
to the newly generated nonce to be used for the next channel update partial signature.
A receiving node:
- ???
Upon reconnection when channel_reestablish_eltoo
is exchanged by all channel peers a node:
- If both local and remote
last_update_number
s are 0:- MUST retransmit
channel_ready
.
- MUST retransmit
- otherwise:
- MUST NOT retransmit
channel_ready
.
- MUST NOT retransmit
- MUST ignore any redundant
channel_ready
it receives. - If both local and remote
last_update_number
s are identical:- partial signature from the non-turn-taker can be applied to the turn-taker's
transaction if not previously received before disconnect
- If this final signature does not validate, MUST fail the channel
- a new turn then starts with the peer with the lesser SEC1-encoded node_id.
- partial signature from the non-turn-taker can be applied to the turn-taker's
transaction if not previously received before disconnect
- If the local and remote node's
last_update_number
is exactly one different:- The node with the higher update number retains its turn, retransmits
all updates and then a newly partially signed
update_signed
message using thefresh_nonce
s exchanged from each peer. - Nodes then continue normal channel operation
- The node with the higher update number retains its turn, retransmits
all updates and then a newly partially signed
- otherwise:
- ??? FIXME must be something we can do here to be nice to the peer that forgot stuff. Ahead node can just convince the peer of latest state and share the entire tx?
- If
next_nonce
is not a valid BIP-musig2 nonce- MUST send a
warning
and close the connection, or send anerror
and fail the channel.
- MUST send a
A node:
- MUST NOT assume that previously-transmitted messages were lost,
- if it has sent a previous
update_signed
message:- MUST handle the case where the corresponding update transaction is
broadcast at any time by the other side,
- Note: this is particularly important if the node does not simply
retransmit the exact
update_
messages as previously sent.
- Note: this is particularly important if the node does not simply
retransmit the exact
- MUST handle the case where the corresponding update transaction is
broadcast at any time by the other side,
- if it has sent a previous
- upon reconnection:
- if it has sent a previous
shutdown
:- MUST retransmit
shutdown
.
- MUST retransmit
- if it has sent a previous
Due to symmetry and lack of penalty transactions, we only need to communicate to the remote node which state we are on, which should match the number they send as well. If they don't match, this indicates an unfinished turn or error.
This assumes that HTLCs are not fast-forwarded until after a update_signed_ack
has been sent back to the offerer(and persisted). This allows for more reliable forwarding
during reconnects without requiring extensive retransmission.
Greg Sanders gsanders87@gmail.com
This work is licensed under a Creative Commons Attribution 4.0 International License.