From 46d6c037403d89a7f77f48315d532b23a0048d4e Mon Sep 17 00:00:00 2001
From: zzz <zzz@i2pmail.org>
Date: Fri, 22 Oct 2021 16:51:07 -0400
Subject: [PATCH] prop. 159 ack/nack

---
 i2p2www/spec/proposals/159-ssu2.rst | 161 +++++++++++++++++++---------
 1 file changed, 110 insertions(+), 51 deletions(-)

diff --git a/i2p2www/spec/proposals/159-ssu2.rst b/i2p2www/spec/proposals/159-ssu2.rst
index 97d66a343..7008335f6 100644
--- a/i2p2www/spec/proposals/159-ssu2.rst
+++ b/i2p2www/spec/proposals/159-ssu2.rst
@@ -3811,8 +3811,7 @@ For 1500 MTU: Max payload is 1440 (IPv4) or 1420 (IPv6)
 
 Starting with the 2nd part of Session Confirmed, all messages are inside
 an authenticated and encrypted ChaChaPoly payload.
-with a prepended two-byte obfuscated length.
-All padding is inside the frame.
+All padding is inside the message.
 Inside the payload is a standard format with zero or more "blocks".
 Each block has a one-byte type and a two-byte length.
 Types include date/time, I2NP message, options, termination, and padding.
@@ -4092,8 +4091,8 @@ Relay Intro                                 9           TBD
 Peer Test                                  10           TBD
 Next Nonce                                 11           TBD
 ACK                                        12         varies 
-Partial ACK                                13         varies 
-NACK                                       14         varies 
+xxxxxxxxxxxxx                              13         varies 
+xxxxxxxxxxxxx                              14         varies 
 Relay Tag Request                          15            3      
 Relay Tag                                  16            7      
 New Token                                  17           15
@@ -4672,67 +4671,48 @@ NextNonce
 
 Ack
 ``````````````
-- 4 byte ack through
-- one byte negative offset from ack through
-- bitfield of nacks from (ack through) - offset
+4 byte ack through, followed by an ack count
+and nack/ack ranges
 
 .. raw:: html
 
   {% highlight lang='dataspec' %}
 +----+----+----+----+----+----+----+----+
-  | 12 |  size   |      TBD               |
-  +----+----+----+                        +
-  |                                       |
-  ~               .   .   .               ~
-  |                                       |
+  | 12 |  size   |    Ack Through    |acnt|
   +----+----+----+----+----+----+----+----+
-
-  blk :: 12
-  size :: 2 bytes, big endian, size of data to follow
-
-{% endhighlight %}
-
-
-Partial Ack
-``````````````
-TODO Not required if we're acking packets, not I2NP messages?
-
-.. raw:: html
-
-  {% highlight lang='dataspec' %}
-+----+----+----+----+----+----+----+----+
-  | 13 |  size   |      TBD               |
-  +----+----+----+                        +
-  |                                       |
+  |  range  |  range  |     .   .   .     |
+  +----+----+----+----+                   +
   ~               .   .   .               ~
   |                                       |
   +----+----+----+----+----+----+----+----+
 
-  blk :: 13
+  blk :: 12
   size :: 2 bytes, big endian, size of data to follow
+  ack through :: highest packet number acked
+  acnt :: number of acks lower than ack through also acked,
+          0-255
+  range :: 0 or more two-byte fields. Each is a
+           1 byte nack count followed by 1 byte ack count,
+           0-255 each
 
 {% endhighlight %}
 
+Example: ACK 10 9 8 6 5 2 1 0, NACK 7 4 3
 
-Nack
-``````````````
-TODO Not required, put in ack block?
-
-.. raw:: html
+- Ack Through: 10
+- acnt: 2 (ack 9 8)
+- range: 1 2 (nack 7, ack 6 5)
+- range: 2 3 (nack 4 3, ack 2 1 0)
 
-  {% highlight lang='dataspec' %}
-+----+----+----+----+----+----+----+----+
-  | 14 |  size   |      TBD               |
-  +----+----+----+                        +
-  |                                       |
-  ~               .   .   .               ~
-  |                                       |
-  +----+----+----+----+----+----+----+----+
+Range nack may be zero if acking more than 255 consecutive packets.
+Range ack may be zero if nacking more than 255 consecutive packets.
+Range nack and ack may not both be zero.
 
-  blk :: 14
-  size :: 2 bytes, big endian, size of data to follow
+After the last range, packets are neither acked nor nacked.
+Length of the ack block and how old acks/nacks are handled
+is up to the sender of the ack block.
+See ack sections below for discussion.
 
-{% endhighlight %}
 
 
 Relay Tag Request
@@ -5153,7 +5133,7 @@ load generated by a receiver that sends an ACK block in response to
 every ack-eliciting packet.  The guidance offered below seeks to
 strike this balance.
 
-The following frames are ack-eliciting:
+The following blocks are ack-eliciting:
 
 - I2NP message
 - First fragment
@@ -5206,7 +5186,7 @@ when the endpoint sends an ACK block in response to other events.
 An endpoint that is only sending ACK blocks will not receive
 acknowledgments from its peer unless those acknowledgments are
 included in packets with ack-eliciting blocks.  An endpoint should
-send an ACK block with other frames when there are new ack-eliciting
+send an ACK block with other blocks when there are new ack-eliciting
 packets to acknowledge.  When only non-ack-eliciting packets need to
 be acknowledged, an endpoint MAY choose not to send an ACK block with
 outgoing blocks until an ack-eliciting packet has been received.
@@ -5219,7 +5199,7 @@ packets that would otherwise be non-ack-eliciting, to avoid an
 infinite feedback loop of acknowledgments.
 
 In order to assist loss detection at the sender, an endpoint should
-generate and send an ACK frame without delay when it receives an ack-
+generate and send an ACK block without delay when it receives an ack-
 eliciting packet either:
 
 *  when the received packet has a packet number less than another
@@ -5271,6 +5251,85 @@ A receiver may process multiple available packets before determining
 whether to send an ACK block in response.
 
 
+Sending ACK Ranges
+--------------------
+
+When an ACK block is sent, one or more ranges of acknowledged packets
+are included.  Including acknowledgments for older packets reduces
+the chance of spurious retransmissions caused by losing previously
+sent ACK blocks, at the cost of larger ACK blocks.
+
+ACK blocks should always acknowledge the most recently received
+packets, and the more out of order the packets are, the more
+important it is to send an updated ACK block quickly, to prevent the
+peer from declaring a packet as lost and spuriously retransmitting
+the blocks it contains.  An ACK block must fit within a
+single packet.  If it does not, then older ranges (those with
+the smallest packet numbers) are omitted.
+
+A receiver limits the number of ACK Ranges it
+remembers and sends in ACK blocks, both to limit the size of ACK
+blocks and to avoid resource exhaustion.  After receiving
+acknowledgments for an ACK block, the receiver should stop tracking
+those acknowledged ACK Ranges.  Senders can expect acknowledgments
+for most packets, but this protocol does not guarantee receipt of an
+acknowledgment for every packet that the receiver processes.
+
+It is possible that retaining many ACK Ranges could cause an ACK
+block to become too large.  A receiver can discard unacknowledged ACK
+Ranges to limit ACK block size, at the cost of increased
+retransmissions from the sender.  This is necessary if an ACK block
+would be too large to fit in a packet.  Receivers MAY also limit ACK
+block size further to preserve space for other blocks or to limit the
+capacity that acknowledgments consume.
+
+A receiver MUST retain an ACK Range unless it can ensure that it will
+not subsequently accept packets with numbers in that range.
+Maintaining a minimum packet number that increases as ranges are
+discarded is one way to achieve this with minimal state.
+
+Receivers can discard all ACK Ranges, but they MUST retain the
+largest packet number that has been successfully processed, as that
+is used to recover packet numbers from subsequent packets.
+
+A receiver should include an ACK Range containing the largest
+received packet number in every ACK block.  The Largest Acknowledged
+field is used in ECN validation at a sender, and including a lower
+value than what was included in a previous ACK block could cause ECN
+to be unnecessarily disabled.
+
+The following section describes an exemplary approach for determining what
+packets to acknowledge in each ACK block.  Though the goal of this
+algorithm is to generate an acknowledgment for every packet that is
+processed, it is still possible for acknowledgments to be lost.
+
+Limiting Ranges by Tracking ACK Blocks
+-------------------------------------------
+
+When a packet containing an ACK block is sent, the Largest
+Acknowledged field in that block can be saved.  When a packet
+containing an ACK block is acknowledged, the receiver can stop
+acknowledging packets less than or equal to the Largest Acknowledged
+field in the sent ACK block.
+
+A receiver that sends only non-ack-eliciting packets, such as ACK
+blocks, might not receive an acknowledgment for a long period of
+time.  This could cause the receiver to maintain state for a large
+number of ACK blocks for a long period of time, and ACK blocks it
+sends could be unnecessarily large.  In such a case, a receiver could
+send a PING or other small ack-eliciting block occasionally, such as
+once per round trip, to elicit an ACK from the peer.
+
+In cases without ACK block loss, this algorithm allows for a minimum
+of 1 RTT of reordering.  In cases with ACK block loss and reordering,
+this approach does not guarantee that every acknowledgment is seen by
+the sender before it is no longer included in the ACK block.  Packets
+could be received out of order, and all subsequent ACK blocks
+containing them could be lost.  In this case, the loss recovery
+algorithm could cause spurious retransmissions, but the sender will
+continue making forward progress.
+
+
 Congestion
 ----------
 
@@ -5384,7 +5443,7 @@ TBD
 Path Message Min Size
 -------------------------
 
-QUIC requires that messages containing PATH_CHALLENGE or PATH_RESPONSE frames be at least 1200 bytes,
+QUIC requires that messages containing PATH_CHALLENGE or PATH_RESPONSE blocks be at least 1200 bytes,
 to prevent amplification attacks. and ensure the PMTU supports it in both directions.
 
 We could require this as well, at substantial cost in bandwidth.
-- 
GitLab