Project import generated by Copybara.

PiperOrigin-RevId: 231652158
Change-Id: I80001699b542a5c823722d90d24fcdd014ef99e7
diff --git a/http2/hpack/decoder/hpack_entry_decoder.cc b/http2/hpack/decoder/hpack_entry_decoder.cc
index b227b18..96b9f06 100644
--- a/http2/hpack/decoder/hpack_entry_decoder.cc
+++ b/http2/hpack/decoder/hpack_entry_decoder.cc
@@ -192,7 +192,7 @@
 
 bool HpackEntryDecoder::DispatchOnType(HpackEntryDecoderListener* listener) {
   const HpackEntryType entry_type = entry_type_decoder_.entry_type();
-  const uint64_t varint = entry_type_decoder_.varint();
+  const uint32_t varint = static_cast<uint32_t>(entry_type_decoder_.varint());
   switch (entry_type) {
     case HpackEntryType::kIndexedHeader:
       // The entry consists solely of the entry type and varint. See:
diff --git a/http2/hpack/decoder/hpack_string_decoder.h b/http2/hpack/decoder/hpack_string_decoder.h
index 5e0d220..2128728 100644
--- a/http2/hpack/decoder/hpack_string_decoder.h
+++ b/http2/hpack/decoder/hpack_string_decoder.h
@@ -13,7 +13,6 @@
 
 #include <algorithm>
 #include <cstdint>
-#include <limits>
 
 #include "base/logging.h"
 #include "base/macros.h"
@@ -169,16 +168,8 @@
   // false otherwise, in which case status set.
   template <class Listener>
   void OnStringStart(Listener* cb, DecodeStatus* status) {
-    // HpackVarintDecoder::value() returns uint64_t.
-    const uint64_t value = length_decoder_.value();
-    // |remaining_| is size_t.  Check for truncation on 32-bit platforms.
-    // numeric_limits::max() is constexpr.  On platforms where size_t is at
-    // least 64 bit wide, the compiler should optimize away this branch.
-    if (value > std::numeric_limits<size_t>::max()) {
-      *status = DecodeStatus::kDecodeError;
-      return;
-    }
-    remaining_ = static_cast<size_t>(value);
+    // TODO(vasilvv): fail explicitly in case of truncation.
+    remaining_ = static_cast<size_t>(length_decoder_.value());
     // Make callback so consumer knows what is coming.
     cb->OnStringStart(huffman_encoded_, remaining_);
   }
diff --git a/http2/hpack/varint/hpack_varint_decoder.cc b/http2/hpack/varint/hpack_varint_decoder.cc
index dd64025..ac85247 100644
--- a/http2/hpack/varint/hpack_varint_decoder.cc
+++ b/http2/hpack/varint/hpack_varint_decoder.cc
@@ -4,7 +4,6 @@
 
 #include "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h"
 
-#include "net/third_party/quiche/src/http2/platform/api/http2_flag_utils.h"
 #include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
 
 namespace http2 {
@@ -43,96 +42,67 @@
 }
 
 DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) {
-  if (decode_64_bits_) {
-    HTTP2_RELOADABLE_FLAG_COUNT(http2_varint_decode_64_bits);
-    // There can be at most 10 continuation bytes.  Offset is zero for the
-    // first one and increases by 7 for each subsequent one.
-    const uint8_t kMaxOffset = 63;
-    CheckNotDone();
-
-    // Process most extension bytes without the need for overflow checking.
-    while (offset_ < kMaxOffset) {
-      if (db->Empty()) {
-        return DecodeStatus::kDecodeInProgress;
-      }
-
-      uint8_t byte = db->DecodeUInt8();
-      uint64_t summand = byte & 0x7f;
-
-      // Shifting a 7 bit value to the left by at most 56 places can never
-      // overflow on uint64_t.
-      DCHECK_LE(offset_, 56);
-      DCHECK_LE(summand, std::numeric_limits<uint64_t>::max() >> offset_);
-
-      summand <<= offset_;
-
-      // At this point,
-      // |value_| is at most (2^prefix_length - 1) + (2^49 - 1), and
-      // |summand| is at most 255 << 56 (which is smaller than 2^63),
-      // so adding them can never overflow on uint64_t.
-      DCHECK_LE(value_, std::numeric_limits<uint64_t>::max() - summand);
-
-      value_ += summand;
-
-      // Decoding ends if continuation flag is not set.
-      if ((byte & 0x80) == 0) {
-        MarkDone();
-        return DecodeStatus::kDecodeDone;
-      }
-
-      offset_ += 7;
-    }
-
-    if (db->Empty()) {
-      return DecodeStatus::kDecodeInProgress;
-    }
-
-    DCHECK_EQ(kMaxOffset, offset_);
-
-    uint8_t byte = db->DecodeUInt8();
-    // No more extension bytes are allowed after this.
-    if ((byte & 0x80) == 0) {
-      uint64_t summand = byte & 0x7f;
-      // Check for overflow in left shift.
-      if (summand <= std::numeric_limits<uint64_t>::max() >> offset_) {
-        summand <<= offset_;
-        // Check for overflow in addition.
-        if (value_ <= std::numeric_limits<uint64_t>::max() - summand) {
-          value_ += summand;
-          MarkDone();
-          return DecodeStatus::kDecodeDone;
-        }
-      }
-    }
-
-    // Signal error if value is too large or there are too many extension bytes.
-    DLOG(WARNING) << "Variable length int encoding is too large or too long. "
-                  << DebugString();
-    MarkDone();
-    return DecodeStatus::kDecodeError;
-  }
-
-  // Old code path.  TODO(bnc): remove.
-  DCHECK(!decode_64_bits_);
-  const uint8_t kMaxOffset = 28;
+  // There can be at most 10 continuation bytes.  Offset is zero for the
+  // first one and increases by 7 for each subsequent one.
+  const uint8_t kMaxOffset = 63;
   CheckNotDone();
-  do {
+
+  // Process most extension bytes without the need for overflow checking.
+  while (offset_ < kMaxOffset) {
     if (db->Empty()) {
       return DecodeStatus::kDecodeInProgress;
     }
+
     uint8_t byte = db->DecodeUInt8();
-    if (offset_ == kMaxOffset && byte != 0)
-      break;
-    DCHECK(offset_ <= kMaxOffset - 7 || byte == 0);
-    // Shifting a 7 bit value to the left by at most 21 places can never
-    // overflow on uint32_t.  Shifting 0 to the left cannot overflow either.
-    value_ += (byte & 0x7f) << offset_;
+    uint64_t summand = byte & 0x7f;
+
+    // Shifting a 7 bit value to the left by at most 56 places can never
+    // overflow on uint64_t.
+    DCHECK_LE(offset_, 56);
+    DCHECK_LE(summand, std::numeric_limits<uint64_t>::max() >> offset_);
+
+    summand <<= offset_;
+
+    // At this point,
+    // |value_| is at most (2^prefix_length - 1) + (2^49 - 1), and
+    // |summand| is at most 255 << 56 (which is smaller than 2^63),
+    // so adding them can never overflow on uint64_t.
+    DCHECK_LE(value_, std::numeric_limits<uint64_t>::max() - summand);
+
+    value_ += summand;
+
+    // Decoding ends if continuation flag is not set.
     if ((byte & 0x80) == 0) {
       MarkDone();
       return DecodeStatus::kDecodeDone;
     }
+
     offset_ += 7;
-  } while (offset_ <= kMaxOffset);
+  }
+
+  if (db->Empty()) {
+    return DecodeStatus::kDecodeInProgress;
+  }
+
+  DCHECK_EQ(kMaxOffset, offset_);
+
+  uint8_t byte = db->DecodeUInt8();
+  // No more extension bytes are allowed after this.
+  if ((byte & 0x80) == 0) {
+    uint64_t summand = byte & 0x7f;
+    // Check for overflow in left shift.
+    if (summand <= std::numeric_limits<uint64_t>::max() >> offset_) {
+      summand <<= offset_;
+      // Check for overflow in addition.
+      if (value_ <= std::numeric_limits<uint64_t>::max() - summand) {
+        value_ += summand;
+        MarkDone();
+        return DecodeStatus::kDecodeDone;
+      }
+    }
+  }
+
+  // Signal error if value is too large or there are too many extension bytes.
   DLOG(WARNING) << "Variable length int encoding is too large or too long. "
                 << DebugString();
   MarkDone();
diff --git a/http2/hpack/varint/hpack_varint_decoder.h b/http2/hpack/varint/hpack_varint_decoder.h
index c793500..5c99b5c 100644
--- a/http2/hpack/varint/hpack_varint_decoder.h
+++ b/http2/hpack/varint/hpack_varint_decoder.h
@@ -13,23 +13,16 @@
 // For details of the encoding, see:
 //        http://httpwg.org/specs/rfc7541.html#integer.representation
 //
-// If GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is true, then this
-// decoder supports decoding any integer that can be represented on uint64_t,
-// thereby exceeding the requirements for QPACK: "QPACK implementations MUST be
-// able to decode integers up to 62 bits long."  See
+// HpackVarintDecoder supports decoding any integer that can be represented on
+// uint64_t, thereby exceeding the requirements for QPACK: "QPACK
+// implementations MUST be able to decode integers up to 62 bits long."  See
 // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.1.1
 //
-// If GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is false, then this
-// decoder supports decoding integers up to 2^28 + 2^prefix_length - 2.
-//
 // This decoder supports at most 10 extension bytes (bytes following the prefix,
-// also called continuation bytes) if
-// GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is true, and at most 5
-// extension bytes if GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is
-// false.  An encoder is allowed to zero pad the encoded integer on the left,
-// thereby increasing the number of extension bytes.  If an encoder uses so much
-// padding that the number of extension bytes exceeds the limit, then this
-// decoder signals an error.
+// also called continuation bytes).  An encoder is allowed to zero pad the
+// encoded integer on the left, thereby increasing the number of extension
+// bytes.  If an encoder uses so much padding that the number of extension bytes
+// exceeds the limit, then this decoder signals an error.
 
 #ifndef QUICHE_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
 #define QUICHE_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
@@ -41,7 +34,6 @@
 #include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
 #include "net/third_party/quiche/src/http2/decoder/decode_status.h"
 #include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_flags.h"
 #include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
 
 namespace http2 {
@@ -119,12 +111,6 @@
 #endif
   }
 
-  // If true, decode integers up to 2^64 - 1, and accept at most 10 extension
-  // bytes (some of which might be padding).
-  // If false, decode integers up to 2^28 + 2^prefix_length - 2, and accept at
-  // most 5 extension bytes (some of which might be padding).
-  bool decode_64_bits_ = GetHttp2ReloadableFlag(http2_varint_decode_64_bits);
-
   // These fields are initialized just to keep ASAN happy about reading
   // them from DebugString().
 
diff --git a/http2/hpack/varint/hpack_varint_decoder_test.cc b/http2/hpack/varint/hpack_varint_decoder_test.cc
index e36ad07..32a4a30 100644
--- a/http2/hpack/varint/hpack_varint_decoder_test.cc
+++ b/http2/hpack/varint/hpack_varint_decoder_test.cc
@@ -22,32 +22,13 @@
 namespace test {
 namespace {
 
-// Save previous value of flag and restore on destruction.
-class FlagSaver {
- public:
-  FlagSaver() = delete;
-  explicit FlagSaver(bool decode_64_bits)
-      : saved_value_(GetHttp2ReloadableFlag(http2_varint_decode_64_bits)) {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, decode_64_bits);
-  }
-  ~FlagSaver() {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, saved_value_);
-  }
-
- private:
-  const bool saved_value_;
-};
-
-class HpackVarintDecoderTest
-    : public RandomDecoderTest,
-      public ::testing::WithParamInterface<
-          ::testing::tuple<bool, uint8_t, const char*>> {
+class HpackVarintDecoderTest : public RandomDecoderTest,
+                               public ::testing::WithParamInterface<
+                                   ::testing::tuple<uint8_t, const char*>> {
  protected:
   HpackVarintDecoderTest()
-      : decode_64_bits_(::testing::get<0>(GetParam())),
-        high_bits_(::testing::get<1>(GetParam())),
-        suffix_(Http2HexDecode(::testing::get<2>(GetParam()))),
-        flag_saver_(decode_64_bits_),
+      : high_bits_(::testing::get<0>(GetParam())),
+        suffix_(Http2HexDecode(::testing::get<1>(GetParam()))),
         prefix_length_(0) {}
 
   void DecodeExpectSuccess(Http2StringPiece data,
@@ -81,8 +62,6 @@
     EXPECT_TRUE(Decode(data, prefix_length, validator));
   }
 
-  bool decode_64_bits() const { return decode_64_bits_; }
-
  private:
   AssertionResult Decode(Http2StringPiece data,
                          uint32_t prefix_length,
@@ -119,16 +98,11 @@
     return decoder_.Resume(b);
   }
 
-  // Test new or old behavior.
-  const bool decode_64_bits_;
   // Bits of the first byte not part of the prefix.
   const uint8_t high_bits_;
   // Extra bytes appended to the input.
   const Http2String suffix_;
 
-  // |flag_saver_| must preceed |decoder_| so that the flag is already set when
-  // |decoder_| is constructed.
-  FlagSaver flag_saver_;
   HpackVarintDecoder decoder_;
   uint8_t prefix_length_;
 };
@@ -137,15 +111,11 @@
     HpackVarintDecoderTest,
     HpackVarintDecoderTest,
     ::testing::Combine(
-        // Test both the new version (supporting 64 bit integers) and the old
-        // one (only supporting up to 2^28 + 2^prefix_length - 2.
-        ::testing::Bool(),
         // Bits of the first byte not part of the prefix should be ignored.
         ::testing::Values(0b00000000, 0b11111111, 0b10101010),
         // Extra bytes appended to the input should be ignored.
         ::testing::Values("", "00", "666f6f")));
 
-// Test data used when decode_64_bits() == true.
 struct {
   const char* data;
   uint32_t prefix_length;
@@ -289,124 +259,14 @@
     {"1f9a0a", 5, 1337},
 };
 
-// Test data used when decode_64_bits() == false.
-struct {
-  const char* data;
-  uint32_t prefix_length;
-  uint64_t expected_value;
-} kSuccessTestDataOld[] = {
-    // Zero value with different prefix lengths.
-    {"00", 3, 0},
-    {"00", 4, 0},
-    {"00", 5, 0},
-    {"00", 6, 0},
-    {"00", 7, 0},
-    // Small values that fit in the prefix.
-    {"06", 3, 6},
-    {"0d", 4, 13},
-    {"10", 5, 16},
-    {"29", 6, 41},
-    {"56", 7, 86},
-    // Values of 2^n-1, which have an all-zero extension byte.
-    {"0700", 3, 7},
-    {"0f00", 4, 15},
-    {"1f00", 5, 31},
-    {"3f00", 6, 63},
-    {"7f00", 7, 127},
-    // Values of 2^n-1, plus one extra byte of padding.
-    {"078000", 3, 7},
-    {"0f8000", 4, 15},
-    {"1f8000", 5, 31},
-    {"3f8000", 6, 63},
-    {"7f8000", 7, 127},
-    // Values requiring one extension byte.
-    {"0760", 3, 103},
-    {"0f2a", 4, 57},
-    {"1f7f", 5, 158},
-    {"3f02", 6, 65},
-    {"7f49", 7, 200},
-    // Values requiring one extension byte, plus one byte of padding.
-    {"07e000", 3, 103},
-    {"0faa00", 4, 57},
-    {"1fff00", 5, 158},
-    {"3f8200", 6, 65},
-    {"7fc900", 7, 200},
-    // Values requiring one extension byte, plus two bytes of padding.
-    {"07e08000", 3, 103},
-    {"0faa8000", 4, 57},
-    {"1fff8000", 5, 158},
-    {"3f828000", 6, 65},
-    {"7fc98000", 7, 200},
-    // Values requiring one extension byte, plus the maximum amount of padding.
-    {"07e080808000", 3, 103},
-    {"0faa80808000", 4, 57},
-    {"1fff80808000", 5, 158},
-    {"3f8280808000", 6, 65},
-    {"7fc980808000", 7, 200},
-    // Values requiring two extension bytes.
-    {"07b260", 3, 12345},
-    {"0f8a2a", 4, 5401},
-    {"1fa87f", 5, 16327},
-    {"3fd002", 6, 399},
-    {"7fff49", 7, 9598},
-    // Values requiring two extension bytes, plus one byte of padding.
-    {"07b2e000", 3, 12345},
-    {"0f8aaa00", 4, 5401},
-    {"1fa8ff00", 5, 16327},
-    {"3fd08200", 6, 399},
-    {"7fffc900", 7, 9598},
-    // Values requiring two extension bytes, plus the maximum amount of padding.
-    {"07b2e0808000", 3, 12345},
-    {"0f8aaa808000", 4, 5401},
-    {"1fa8ff808000", 5, 16327},
-    {"3fd082808000", 6, 399},
-    {"7fffc9808000", 7, 9598},
-    // Values requiring three extension bytes.
-    {"078ab260", 3, 1579281},
-    {"0fc18a2a", 4, 689488},
-    {"1fada87f", 5, 2085964},
-    {"3fa0d002", 6, 43103},
-    {"7ffeff49", 7, 1212541},
-    // Values requiring three extension bytes, plus one byte of padding.
-    {"078ab2e000", 3, 1579281},
-    {"0fc18aaa00", 4, 689488},
-    {"1fada8ff00", 5, 2085964},
-    {"3fa0d08200", 6, 43103},
-    {"7ffeffc900", 7, 1212541},
-    // Values requiring four extension bytes.
-    {"079f8ab260", 3, 202147110},
-    {"0fa2c18a2a", 4, 88252593},
-    {"1fd0ada87f", 5, 266999535},
-    {"3ff9a0d002", 6, 5509304},
-    {"7f9efeff49", 7, 155189149},
-    // Values requiring four extension bytes, plus one byte of padding.
-    {"079f8ab2e000", 3, 202147110},
-    {"0fa2c18aaa00", 4, 88252593},
-    {"1fd0ada8ff00", 5, 266999535},
-    {"3ff9a0d08200", 6, 5509304},
-    {"7f9efeffc900", 7, 155189149},
-    // Examples from RFC7541 C.1.
-    {"0a", 5, 10},
-    {"1f9a0a", 5, 1337},
-};
-
 TEST_P(HpackVarintDecoderTest, Success) {
-  if (decode_64_bits()) {
     for (size_t i = 0; i < HTTP2_ARRAYSIZE(kSuccessTestData); ++i) {
       DecodeExpectSuccess(Http2HexDecode(kSuccessTestData[i].data),
                           kSuccessTestData[i].prefix_length,
                           kSuccessTestData[i].expected_value);
     }
-  } else {
-    for (size_t i = 0; i < HTTP2_ARRAYSIZE(kSuccessTestDataOld); ++i) {
-      DecodeExpectSuccess(Http2HexDecode(kSuccessTestDataOld[i].data),
-                          kSuccessTestDataOld[i].prefix_length,
-                          kSuccessTestDataOld[i].expected_value);
-    }
-  }
 }
 
-// Test data used when decode_64_bits() == true.
 struct {
   const char* data;
   uint32_t prefix_length;
@@ -440,45 +300,11 @@
     {"7f80ffffffffffffffff8100", 7},
     {"ff80feffffffffffffff8100", 8}};
 
-// Test data used when decode_64_bits() == false.
-// In this mode, HpackVarintDecoder allows at most five extension bytes,
-// and fifth extension byte must be zero.
-struct {
-  const char* data;
-  uint32_t prefix_length;
-} kErrorTestDataOld[] = {
-    // Maximum number of extension bytes but last byte is non-zero.
-    {"078080808001", 3},
-    {"0f8080808001", 4},
-    {"1f8080808001", 5},
-    {"3f8080808001", 6},
-    {"7f8080808001", 7},
-    // Too many extension bytes, all 0s (except for extension bit in each byte).
-    {"078080808080", 3},
-    {"0f8080808080", 4},
-    {"1f8080808080", 5},
-    {"3f8080808080", 6},
-    {"7f8080808080", 7},
-    // Too many extension bytes, all 1s.
-    {"07ffffffffff", 3},
-    {"0fffffffffff", 4},
-    {"1fffffffffff", 5},
-    {"3fffffffffff", 6},
-    {"7fffffffffff", 7},
-};
-
 TEST_P(HpackVarintDecoderTest, Error) {
-  if (decode_64_bits()) {
     for (size_t i = 0; i < HTTP2_ARRAYSIZE(kErrorTestData); ++i) {
       DecodeExpectError(Http2HexDecode(kErrorTestData[i].data),
                         kErrorTestData[i].prefix_length);
     }
-  } else {
-    for (size_t i = 0; i < HTTP2_ARRAYSIZE(kErrorTestDataOld); ++i) {
-      DecodeExpectError(Http2HexDecode(kErrorTestDataOld[i].data),
-                        kErrorTestDataOld[i].prefix_length);
-    }
-  }
 }
 
 }  // namespace
diff --git a/http2/hpack/varint/hpack_varint_round_trip_test.cc b/http2/hpack/varint/hpack_varint_round_trip_test.cc
index 3299d5e..cd26553 100644
--- a/http2/hpack/varint/hpack_varint_round_trip_test.cc
+++ b/http2/hpack/varint/hpack_varint_round_trip_test.cc
@@ -22,29 +22,11 @@
 
 using ::testing::AssertionFailure;
 using ::testing::AssertionSuccess;
-using ::testing::Bool;
-using ::testing::WithParamInterface;
 
 namespace http2 {
 namespace test {
 namespace {
 
-// Save previous value of flag and restore on destruction.
-class FlagSaver {
- public:
-  FlagSaver() = delete;
-  explicit FlagSaver(bool decode_64_bits)
-      : saved_value_(GetHttp2ReloadableFlag(http2_varint_decode_64_bits)) {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, decode_64_bits);
-  }
-  ~FlagSaver() {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, saved_value_);
-  }
-
- private:
-  const bool saved_value_;
-};
-
 // Returns the highest value with the specified number of extension bytes
 // and the specified prefix length (bits).
 uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
@@ -53,13 +35,9 @@
          (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
 }
 
-class HpackVarintRoundTripTest : public RandomDecoderTest,
-                                 public WithParamInterface<bool> {
+class HpackVarintRoundTripTest : public RandomDecoderTest {
  protected:
-  HpackVarintRoundTripTest()
-      : decode_64_bits_(GetParam()),
-        flag_saver_(decode_64_bits_),
-        prefix_length_(0) {}
+  HpackVarintRoundTripTest() : prefix_length_(0) {}
 
   DecodeStatus StartDecoding(DecodeBuffer* b) override {
     CHECK_LT(0u, b->Remaining());
@@ -260,22 +238,14 @@
     EncodeAndDecodeValues(values, prefix_length, expected_bytes);
   }
 
-  // |flag_saver_| must preceed |decoder_| so that the flag is already set when
-  // |decoder_| is constructed.
-  const bool decode_64_bits_;
-  FlagSaver flag_saver_;
   HpackVarintDecoder decoder_;
   Http2String buffer_;
   uint8_t prefix_length_;
 };
 
-INSTANTIATE_TEST_CASE_P(HpackVarintRoundTripTest,
-                        HpackVarintRoundTripTest,
-                        Bool());
-
 // To help me and future debuggers of varint encodings, this LOGs out the
 // transition points where a new extension byte is added.
-TEST_P(HpackVarintRoundTripTest, Encode) {
+TEST_F(HpackVarintRoundTripTest, Encode) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t a = HiValueOfExtensionBytes(0, prefix_length);
     const uint64_t b = HiValueOfExtensionBytes(1, prefix_length);
@@ -300,19 +270,13 @@
         b - 1, b, b + 1, b + 2, b + 3,  // Force line break.
         c - 1, c, c + 1, c + 2, c + 3,  // Force line break.
         d - 1, d, d + 1, d + 2, d + 3,  // Force line break.
-        e - 1, e, e + 1, e + 2, e + 3   // Force line break.
+        e - 1, e, e + 1, e + 2, e + 3,  // Force line break.
+        f - 1, f, f + 1, f + 2, f + 3,  // Force line break.
+        g - 1, g, g + 1, g + 2, g + 3,  // Force line break.
+        h - 1, h, h + 1, h + 2, h + 3,  // Force line break.
+        i - 1, i, i + 1, i + 2, i + 3,  // Force line break.
+        j - 1, j, j + 1, j + 2, j + 3,  // Force line break.
     };
-    if (decode_64_bits_) {
-      for (auto value : {
-               f - 1, f, f + 1, f + 2, f + 3,  // Force line break.
-               g - 1, g, g + 1, g + 2, g + 3,  // Force line break.
-               h - 1, h, h + 1, h + 2, h + 3,  // Force line break.
-               i - 1, i, i + 1, i + 2, i + 3,  // Force line break.
-               j - 1, j, j + 1, j + 2, j + 3,  // Force line break.
-           }) {
-        values.push_back(value);
-      }
-    }
 
     for (uint64_t value : values) {
       EncodeNoRandom(value, prefix_length);
@@ -323,7 +287,7 @@
   }
 }
 
-TEST_P(HpackVarintRoundTripTest, FromSpec1337) {
+TEST_F(HpackVarintRoundTripTest, FromSpec1337) {
   DecodeBuffer b(Http2StringPiece("\x1f\x9a\x0a"));
   uint32_t prefix_length = 5;
   uint8_t p = b.DecodeUInt8();
@@ -340,7 +304,7 @@
 }
 
 // Test all the values that fit into the prefix (one less than the mask).
-TEST_P(HpackVarintRoundTripTest, ValidatePrefixOnly) {
+TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint8_t prefix_mask = (1 << prefix_length) - 1;
     EncodeAndDecodeValuesInRange(0, prefix_mask, prefix_length, 1);
@@ -348,7 +312,7 @@
 }
 
 // Test all values that require exactly 1 extension byte.
-TEST_P(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
+TEST_F(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(0, prefix_length) + 1;
     EncodeAndDecodeValuesInRange(start, 128, prefix_length, 2);
@@ -356,7 +320,7 @@
 }
 
 // Test *some* values that require exactly 2 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
+TEST_F(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(1, prefix_length) + 1;
     const uint64_t range = 127 << 7;
@@ -366,7 +330,7 @@
 }
 
 // Test *some* values that require 3 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
+TEST_F(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(2, prefix_length) + 1;
     const uint64_t range = 127 << 14;
@@ -376,7 +340,7 @@
 }
 
 // Test *some* values that require 4 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
+TEST_F(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(3, prefix_length) + 1;
     const uint64_t range = 127 << 21;
@@ -386,11 +350,7 @@
 }
 
 // Test *some* values that require 5 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(4, prefix_length) + 1;
     const uint64_t range = 127llu << 28;
@@ -400,11 +360,7 @@
 }
 
 // Test *some* values that require 6 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(5, prefix_length) + 1;
     const uint64_t range = 127llu << 35;
@@ -414,11 +370,7 @@
 }
 
 // Test *some* values that require 7 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(6, prefix_length) + 1;
     const uint64_t range = 127llu << 42;
@@ -428,11 +380,7 @@
 }
 
 // Test *some* values that require 8 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(7, prefix_length) + 1;
     const uint64_t range = 127llu << 49;
@@ -442,11 +390,7 @@
 }
 
 // Test *some* values that require 9 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(8, prefix_length) + 1;
     const uint64_t range = 127llu << 56;
@@ -456,11 +400,7 @@
 }
 
 // Test *some* values that require 10 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(9, prefix_length) + 1;
     const uint64_t range = std::numeric_limits<uint64_t>::max() - start;
@@ -469,45 +409,6 @@
   }
 }
 
-// Test the value one larger than the largest that can be decoded.
-TEST_P(HpackVarintRoundTripTest, ValueTooLarge) {
-  // New implementation can decode any integer that HpackVarintEncoder can
-  // encode.
-  if (decode_64_bits_) {
-    return;
-  }
-
-  for (prefix_length_ = 3; prefix_length_ <= 8; ++prefix_length_) {
-    const uint64_t too_large = (1 << 28) + (1 << prefix_length_) - 1;
-    const uint32_t expected_offset = 6;
-    HpackBlockBuilder bb;
-    bb.AppendHighBitsAndVarint(0, prefix_length_, too_large);
-    buffer_ = bb.buffer();
-
-    // The validator is called after each of the several times that the input
-    // DecodeBuffer is decoded, each with a different segmentation of the input.
-    // Validate that decoder_.value() matches the expected value.
-    bool validated = false;
-    Validator validator = [&validated, expected_offset](
-                              const DecodeBuffer& db,
-                              DecodeStatus status) -> AssertionResult {
-      validated = true;
-      VERIFY_EQ(DecodeStatus::kDecodeError, status);
-      VERIFY_EQ(expected_offset, db.Offset());
-      return AssertionSuccess();
-    };
-
-    // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
-    // can call Start with the prefix byte.
-    bool return_non_zero_on_first = true;
-    DecodeBuffer b(buffer_);
-    EXPECT_TRUE(
-        DecodeAndValidateSeveralWays(&b, return_non_zero_on_first, validator));
-    EXPECT_EQ(expected_offset, b.Offset());
-    EXPECT_TRUE(validated);
-  }
-}
-
 }  // namespace
 }  // namespace test
 }  // namespace http2
diff --git a/quic/core/chlo_extractor_test.cc b/quic/core/chlo_extractor_test.cc
index b1c470c..d16050b 100644
--- a/quic/core/chlo_extractor_test.cc
+++ b/quic/core/chlo_extractor_test.cc
@@ -52,7 +52,7 @@
     header_.version = AllSupportedVersions().front();
     header_.reset_flag = false;
     header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
-    header_.packet_number = 1;
+    header_.packet_number = QuicPacketNumber(1);
   }
 
   void MakePacket(const QuicStreamFrame& stream_frame) {
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc
index 47d55d6..c60eaa2 100644
--- a/quic/core/congestion_control/bandwidth_sampler.cc
+++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -18,9 +18,7 @@
       total_bytes_sent_at_last_acked_packet_(0),
       last_acked_packet_sent_time_(QuicTime::Zero()),
       last_acked_packet_ack_time_(QuicTime::Zero()),
-      last_sent_packet_(0),
       is_app_limited_(false),
-      end_of_app_limited_phase_(0),
       connection_state_map_() {}
 
 BandwidthSampler::~BandwidthSampler() {}
diff --git a/quic/core/congestion_control/bandwidth_sampler_test.cc b/quic/core/congestion_control/bandwidth_sampler_test.cc
index 4203686..e9b74c7 100644
--- a/quic/core/congestion_control/bandwidth_sampler_test.cc
+++ b/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -40,54 +40,55 @@
   BandwidthSampler sampler_;
   QuicByteCount bytes_in_flight_;
 
-  void SendPacketInner(QuicPacketNumber packet_number,
+  void SendPacketInner(uint64_t packet_number,
                        QuicByteCount bytes,
                        HasRetransmittableData has_retransmittable_data) {
-    sampler_.OnPacketSent(clock_.Now(), packet_number, bytes, bytes_in_flight_,
-                          has_retransmittable_data);
+    sampler_.OnPacketSent(clock_.Now(), QuicPacketNumber(packet_number), bytes,
+                          bytes_in_flight_, has_retransmittable_data);
     if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA) {
       bytes_in_flight_ += bytes;
     }
   }
 
-  void SendPacket(QuicPacketNumber packet_number) {
+  void SendPacket(uint64_t packet_number) {
     SendPacketInner(packet_number, kRegularPacketSize,
                     HAS_RETRANSMITTABLE_DATA);
   }
 
-  BandwidthSample AckPacketInner(QuicPacketNumber packet_number) {
-    QuicByteCount size =
-        BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number);
+  BandwidthSample AckPacketInner(uint64_t packet_number) {
+    QuicByteCount size = BandwidthSamplerPeer::GetPacketSize(
+        sampler_, QuicPacketNumber(packet_number));
     bytes_in_flight_ -= size;
-    return sampler_.OnPacketAcknowledged(clock_.Now(), packet_number);
+    return sampler_.OnPacketAcknowledged(clock_.Now(),
+                                         QuicPacketNumber(packet_number));
   }
 
   // Acknowledge receipt of a packet and expect it to be not app-limited.
-  QuicBandwidth AckPacket(QuicPacketNumber packet_number) {
+  QuicBandwidth AckPacket(uint64_t packet_number) {
     BandwidthSample sample = AckPacketInner(packet_number);
     EXPECT_FALSE(sample.is_app_limited);
     return sample.bandwidth;
   }
 
-  void LosePacket(QuicPacketNumber packet_number) {
-    QuicByteCount size =
-        BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number);
+  void LosePacket(uint64_t packet_number) {
+    QuicByteCount size = BandwidthSamplerPeer::GetPacketSize(
+        sampler_, QuicPacketNumber(packet_number));
     bytes_in_flight_ -= size;
-    sampler_.OnPacketLost(packet_number);
+    sampler_.OnPacketLost(QuicPacketNumber(packet_number));
   }
 
   // Sends one packet and acks it.  Then, send 20 packets.  Finally, send
   // another 20 packets while acknowledging previous 20.
   void Send40PacketsAndAckFirst20(QuicTime::Delta time_between_packets) {
     // Send 20 packets at a constant inter-packet time.
-    for (QuicPacketNumber i = 1; i <= 20; i++) {
+    for (int i = 1; i <= 20; i++) {
       SendPacket(i);
       clock_.AdvanceTime(time_between_packets);
     }
 
     // Ack packets 1 to 20, while sending new packets at the same rate as
     // before.
-    for (QuicPacketNumber i = 1; i <= 20; i++) {
+    for (int i = 1; i <= 20; i++) {
       AckPacket(i);
       SendPacket(i + 20);
       clock_.AdvanceTime(time_between_packets);
@@ -102,7 +103,7 @@
       QuicBandwidth::FromBytesPerSecond(kRegularPacketSize * 100);
 
   // Send packets at the constant bandwidth.
-  for (QuicPacketNumber i = 1; i < 20; i++) {
+  for (int i = 1; i < 20; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
     QuicBandwidth current_sample = AckPacket(i);
@@ -110,7 +111,7 @@
   }
 
   // Send packets at the exponentially decreasing bandwidth.
-  for (QuicPacketNumber i = 20; i < 25; i++) {
+  for (int i = 20; i < 25; i++) {
     time_between_packets = time_between_packets * 2;
     expected_bandwidth = expected_bandwidth * 0.5;
 
@@ -135,7 +136,7 @@
 
   // Ack the packets 21 to 40, arriving at the correct bandwidth.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     last_bandwidth = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     clock_.AdvanceTime(time_between_packets);
@@ -152,14 +153,14 @@
       QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize) * 0.5;
 
   // Send 20 packets, each 1 ms apart.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
   }
 
   // Ack packets 1 to 20, losing every even-numbered packet, while sending new
   // packets at the same rate as before.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     if (i % 2 == 0) {
       AckPacket(i);
     } else {
@@ -171,7 +172,7 @@
 
   // Ack the packets 21 to 40 with the same loss pattern.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     if (i % 2 == 0) {
       last_bandwidth = AckPacket(i);
       EXPECT_EQ(expected_bandwidth, last_bandwidth);
@@ -196,7 +197,7 @@
 
   // Send 20 packets, each 1 ms apart. Every even packet is not congestion
   // controlled.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     SendPacketInner(
         i, kRegularPacketSize,
         i % 2 == 0 ? HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA);
@@ -208,7 +209,7 @@
 
   // Ack packets 2 to 21, ignoring every even-numbered packet, while sending new
   // packets at the same rate as before.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     if (i % 2 == 0) {
       AckPacket(i);
     }
@@ -220,7 +221,7 @@
 
   // Ack the packets 22 to 41 with the same congestion controlled pattern.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     if (i % 2 == 0) {
       last_bandwidth = AckPacket(i);
       EXPECT_EQ(expected_bandwidth, last_bandwidth);
@@ -251,7 +252,7 @@
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
   QuicTime::Delta ridiculously_small_time_delta =
       QuicTime::Delta::FromMicroseconds(20);
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     last_bandwidth = AckPacket(i);
     clock_.AdvanceTime(ridiculously_small_time_delta);
   }
@@ -272,7 +273,7 @@
   // Ack the packets 21 to 40 in the reverse order, while sending packets 41 to
   // 60.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 0; i < 20; i++) {
+  for (int i = 0; i < 20; i++) {
     last_bandwidth = AckPacket(40 - i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     SendPacket(41 + i);
@@ -280,7 +281,7 @@
   }
 
   // Ack the packets 41 to 60, now in the regular order.
-  for (QuicPacketNumber i = 41; i <= 60; i++) {
+  for (int i = 41; i <= 60; i++) {
     last_bandwidth = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     clock_.AdvanceTime(time_between_packets);
@@ -301,7 +302,7 @@
   // We are now app-limited. Ack 21 to 40 as usual, but do not send anything for
   // now.
   sampler_.OnAppLimited();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     QuicBandwidth current_sample = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, current_sample);
     clock_.AdvanceTime(time_between_packets);
@@ -311,14 +312,14 @@
   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
 
   // Send packets 41 to 60, all of which would be marked as app-limited.
-  for (QuicPacketNumber i = 41; i <= 60; i++) {
+  for (int i = 41; i <= 60; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
   }
 
   // Ack packets 41 to 60, while sending packets 61 to 80.  41 to 60 should be
   // app-limited and underestimate the bandwidth due to that.
-  for (QuicPacketNumber i = 41; i <= 60; i++) {
+  for (int i = 41; i <= 60; i++) {
     BandwidthSample sample = AckPacketInner(i);
     EXPECT_TRUE(sample.is_app_limited);
     EXPECT_LT(sample.bandwidth, 0.7f * expected_bandwidth);
@@ -329,7 +330,7 @@
 
   // Run out of packets, and then ack packet 61 to 80, all of which should have
   // correct non-app-limited samples.
-  for (QuicPacketNumber i = 61; i <= 80; i++) {
+  for (int i = 61; i <= 80; i++) {
     QuicBandwidth last_bandwidth = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     clock_.AdvanceTime(time_between_packets);
@@ -349,7 +350,7 @@
   const QuicBandwidth real_bandwidth =
       QuicBandwidth::FromBytesAndTimeDelta(num_bytes, rtt);
 
-  for (QuicPacketNumber i = 1; i <= 10; i++) {
+  for (int i = 1; i <= 10; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
   }
@@ -357,7 +358,7 @@
   clock_.AdvanceTime(rtt - num_packets * time_between_packets);
 
   QuicBandwidth last_sample = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 1; i <= 10; i++) {
+  for (int i = 1; i <= 10; i++) {
     QuicBandwidth sample = AckPacket(i);
     EXPECT_GT(sample, last_sample);
     last_sample = sample;
@@ -385,9 +386,9 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
 
   EXPECT_EQ(5u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
-  sampler_.RemoveObsoletePackets(4);
+  sampler_.RemoveObsoletePackets(QuicPacketNumber(4));
   EXPECT_EQ(2u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
-  sampler_.OnPacketLost(4);
+  sampler_.OnPacketLost(QuicPacketNumber(4));
   EXPECT_EQ(1u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
   AckPacket(5);
   EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc
index 81931a1..6a7fe2b 100644
--- a/quic/core/congestion_control/bbr_sender.cc
+++ b/quic/core/congestion_control/bbr_sender.cc
@@ -87,8 +87,6 @@
       random_(random),
       mode_(STARTUP),
       round_trip_count_(0),
-      last_sent_packet_(0),
-      current_round_trip_end_(0),
       max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0),
       max_ack_height_(kBandwidthWindowSize, 0, 0),
       aggregation_epoch_start_time_(QuicTime::Zero()),
@@ -122,14 +120,12 @@
       has_non_app_limited_sample_(false),
       flexible_app_limited_(false),
       recovery_state_(NOT_IN_RECOVERY),
-      end_recovery_at_(0),
       recovery_window_(max_congestion_window_),
       is_app_limited_recovery_(false),
       slower_startup_(false),
       rate_based_startup_(false),
       startup_rate_reduction_multiplier_(0),
       startup_bytes_lost_(0),
-      initial_conservation_in_startup_(CONSERVATION),
       enable_ack_aggregation_during_startup_(false),
       expire_ack_aggregation_in_startup_(false),
       drain_to_target_(false),
@@ -263,12 +259,6 @@
   if (config.HasClientRequestedIndependentOption(kBBS1, perspective)) {
     rate_based_startup_ = true;
   }
-  if (config.HasClientRequestedIndependentOption(kBBS2, perspective)) {
-    initial_conservation_in_startup_ = MEDIUM_GROWTH;
-  }
-  if (config.HasClientRequestedIndependentOption(kBBS3, perspective)) {
-    initial_conservation_in_startup_ = GROWTH;
-  }
   if (GetQuicReloadableFlag(quic_bbr_startup_rate_reduction) &&
       config.HasClientRequestedIndependentOption(kBBS4, perspective)) {
     rate_based_startup_ = true;
@@ -467,7 +457,8 @@
 }
 
 bool BbrSender::UpdateRoundTripCounter(QuicPacketNumber last_acked_packet) {
-  if (last_acked_packet > current_round_trip_end_) {
+  if (!current_round_trip_end_.IsInitialized() ||
+      last_acked_packet > current_round_trip_end_) {
     round_trip_count_++;
     current_round_trip_end_ = last_sent_packet_;
     return true;
@@ -677,9 +668,6 @@
       // Enter conservation on the first loss.
       if (has_losses) {
         recovery_state_ = CONSERVATION;
-        if (mode_ == STARTUP) {
-          recovery_state_ = initial_conservation_in_startup_;
-        }
         // This will cause the |recovery_window_| to be set to the correct
         // value in CalculateRecoveryWindow().
         recovery_window_ = 0;
@@ -695,7 +683,6 @@
       break;
 
     case CONSERVATION:
-    case MEDIUM_GROWTH:
       if (is_round_start) {
         recovery_state_ = GROWTH;
       }
@@ -759,7 +746,7 @@
     return;
   }
   // Slow the pacing rate in STARTUP once loss has ever been detected.
-  const bool has_ever_detected_loss = end_recovery_at_ > 0;
+  const bool has_ever_detected_loss = end_recovery_at_.IsInitialized();
   if (slower_startup_ && has_ever_detected_loss &&
       has_non_app_limited_sample_) {
     pacing_rate_ = kStartupAfterLossGain * BandwidthEstimate();
@@ -848,11 +835,8 @@
 
   // In CONSERVATION mode, just subtracting losses is sufficient.  In GROWTH,
   // release additional |bytes_acked| to achieve a slow-start-like behavior.
-  // In MEDIUM_GROWTH, release |bytes_acked| / 2 to split the difference.
   if (recovery_state_ == GROWTH) {
     recovery_window_ += bytes_acked;
-  } else if (recovery_state_ == MEDIUM_GROWTH) {
-    recovery_window_ += bytes_acked / 2;
   }
 
   // Sanity checks.  Ensure that we always allow to send at least an MSS or
diff --git a/quic/core/congestion_control/bbr_sender.h b/quic/core/congestion_control/bbr_sender.h
index 0ee730c..37e2695 100644
--- a/quic/core/congestion_control/bbr_sender.h
+++ b/quic/core/congestion_control/bbr_sender.h
@@ -58,8 +58,6 @@
     NOT_IN_RECOVERY,
     // Allow an extra outstanding byte for each byte acknowledged.
     CONSERVATION,
-    // Allow 1.5 extra outstanding bytes for each byte acknowledged.
-    MEDIUM_GROWTH,
     // Allow two extra outstanding bytes for each byte acknowledged (slow
     // start).
     GROWTH
@@ -265,7 +263,7 @@
   QuicPacketNumber last_sent_packet_;
   // Acknowledgement of any packet after |current_round_trip_end_| will cause
   // the round trip counter to advance.
-  QuicPacketCount current_round_trip_end_;
+  QuicPacketNumber current_round_trip_end_;
 
   // The filter that tracks the maximum bandwidth over the multiple recent
   // round-trips.
@@ -375,8 +373,6 @@
   // Sum of bytes lost in STARTUP.
   QuicByteCount startup_bytes_lost_;
 
-  // Used as the initial packet conservation mode when first entering recovery.
-  RecoveryState initial_conservation_in_startup_;
   // When true, add the most recent ack aggregation measurement during STARTUP.
   bool enable_ack_aggregation_during_startup_;
   // When true, expire the windowed ack aggregation values in STARTUP when
diff --git a/quic/core/congestion_control/bbr_sender_test.cc b/quic/core/congestion_control/bbr_sender_test.cc
index bc7fc76..e0d5867 100644
--- a/quic/core/congestion_control/bbr_sender_test.cc
+++ b/quic/core/congestion_control/bbr_sender_test.cc
@@ -515,97 +515,6 @@
   ASSERT_TRUE(simulator_result);
 }
 
-// Ensures the code transitions loss recovery states correctly when in STARTUP
-// and the BBS2 connection option is used.
-// (NOT_IN_RECOVERY -> CONSERVATION -> GROWTH -> NOT_IN_RECOVERY).
-TEST_F(BbrSenderTest, StartupMediumRecoveryStates) {
-  // Set seed to the position where the gain cycling causes the sender go
-  // into conservation upon entering PROBE_BW.
-  //
-  // TODO(vasilvv): there should be a better way to test this.
-  random_.set_seed(UINT64_C(14719894707049085006));
-
-  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
-  bool simulator_result;
-  CreateSmallBufferSetup();
-  SetConnectionOption(kBBS2);
-
-  bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state !=
-               BbrSender::NOT_IN_RECOVERY;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-  ASSERT_EQ(BbrSender::MEDIUM_GROWTH,
-            sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state !=
-               BbrSender::MEDIUM_GROWTH;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-  ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH;
-      },
-      timeout);
-
-  ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-  ASSERT_TRUE(simulator_result);
-}
-
-// Ensures the code transitions loss recovery states correctly when in STARTUP
-// and the BBS3 connection option is used.
-// (NOT_IN_RECOVERY -> GROWTH -> NOT_IN_RECOVERY).
-TEST_F(BbrSenderTest, StartupGrowthRecoveryStates) {
-  // Set seed to the position where the gain cycling causes the sender go
-  // into conservation upon entering PROBE_BW.
-  //
-  // TODO(vasilvv): there should be a better way to test this.
-  random_.set_seed(UINT64_C(14719894707049085006));
-
-  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
-  bool simulator_result;
-  CreateSmallBufferSetup();
-  SetConnectionOption(kBBS3);
-
-  bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state !=
-               BbrSender::NOT_IN_RECOVERY;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-  ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-
-  ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-  ASSERT_TRUE(simulator_result);
-}
-
 // Verify the behavior of the algorithm in the case when the connection sends
 // small bursts of data after sending continuously for a while.
 TEST_F(BbrSenderTest, ApplicationLimitedBursts) {
@@ -1185,7 +1094,7 @@
   QuicBandwidth pacing_rate = original_pacing_rate;
   const QuicByteCount original_cwnd = sender_->GetCongestionWindow();
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(0, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(), kMaxPacketSize));
   QuicPacketNumber largest_sent =
       bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket();
   for (QuicPacketNumber packet_number =
@@ -1235,7 +1144,7 @@
   QuicBandwidth pacing_rate = original_pacing_rate;
   const QuicByteCount original_cwnd = sender_->GetCongestionWindow();
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(0, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(), kMaxPacketSize));
   QuicPacketNumber largest_sent =
       bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket();
   for (QuicPacketNumber packet_number =
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc
index 7250940..27a3ab8 100644
--- a/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -31,7 +31,6 @@
 
 GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type)
     : loss_detection_timeout_(QuicTime::Zero()),
-      largest_lost_(0),
       least_in_flight_(1),
       faster_detect_loss_(GetQuicReloadableFlag(quic_faster_detect_loss)) {
   SetLossDetectionType(loss_type);
@@ -39,7 +38,7 @@
 
 void GeneralLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) {
   loss_detection_timeout_ = QuicTime::Zero();
-  largest_sent_on_spurious_retransmit_ = kInvalidPacketNumber;
+  largest_sent_on_spurious_retransmit_.Clear();
   loss_type_ = loss_type;
   reordering_shift_ = loss_type == kAdaptiveTime
                           ? kDefaultAdaptiveLossDelayShift
@@ -49,7 +48,7 @@
     QUIC_RELOADABLE_FLAG_COUNT(quic_eighth_rtt_loss_detection);
     reordering_shift_ = 3;
   }
-  largest_previously_acked_ = kInvalidPacketNumber;
+  largest_previously_acked_.Clear();
 }
 
 LossDetectionType GeneralLossAlgorithm::GetLossDetectionType() const {
@@ -91,7 +90,7 @@
   QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
   auto it = unacked_packets.begin();
   if (faster_detect_loss_) {
-    if (least_in_flight_ >= packet_number) {
+    if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) {
       if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) {
         QUIC_BUG << "least_in_flight: " << least_in_flight_
                  << " is greater than largest_sent_packet + 1: "
@@ -103,9 +102,9 @@
       }
     }
     // Clear least_in_flight_.
-    least_in_flight_ = kInvalidPacketNumber;
+    least_in_flight_.Clear();
   } else {
-    if (largest_lost_ >= packet_number) {
+    if (largest_lost_.IsInitialized() && largest_lost_ >= packet_number) {
       if (largest_lost_ > unacked_packets.largest_sent_packet()) {
         QUIC_BUG << "largest_lost: " << largest_lost_
                  << " is greater than largest_sent_packet: "
@@ -132,7 +131,8 @@
     } else if (loss_type_ == kLazyFack) {
       // Require two in order acks to invoke FACK, which avoids spuriously
       // retransmitting packets when one packet is reordered by a large amount.
-      if (largest_newly_acked > largest_previously_acked_ &&
+      if (largest_previously_acked_.IsInitialized() &&
+          largest_newly_acked > largest_previously_acked_ &&
           largest_previously_acked_ > packet_number &&
           largest_previously_acked_ - packet_number >=
               (kNumberOfNacksBeforeRetransmission - 1)) {
@@ -150,7 +150,7 @@
       QuicTime when_lost = it->sent_time + loss_delay;
       if (time < when_lost) {
         loss_detection_timeout_ = when_lost;
-        if (least_in_flight_ == kInvalidPacketNumber) {
+        if (!least_in_flight_.IsInitialized()) {
           // At this point, packet_number is in flight and not detected as lost.
           least_in_flight_ = packet_number;
         }
@@ -166,18 +166,19 @@
       packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
       continue;
     }
-    if (least_in_flight_ == kInvalidPacketNumber) {
+    if (!least_in_flight_.IsInitialized()) {
       // At this point, packet_number is in flight and not detected as lost.
       least_in_flight_ = packet_number;
     }
   }
-  if (least_in_flight_ == kInvalidPacketNumber) {
+  if (!least_in_flight_.IsInitialized()) {
     // There is no in flight packet.
     least_in_flight_ = largest_newly_acked + 1;
   }
   largest_previously_acked_ = largest_newly_acked;
   if (!packets_lost->empty()) {
-    DCHECK_LT(largest_lost_, packets_lost->back().packet_number);
+    DCHECK(!largest_lost_.IsInitialized() ||
+           largest_lost_ < packets_lost->back().packet_number);
     largest_lost_ = packets_lost->back().packet_number;
   }
 }
@@ -212,7 +213,8 @@
     return;
   }
 
-  if (spurious_retransmission <= largest_sent_on_spurious_retransmit_) {
+  if (largest_sent_on_spurious_retransmit_.IsInitialized() &&
+      spurious_retransmission <= largest_sent_on_spurious_retransmit_) {
     return;
   }
   largest_sent_on_spurious_retransmit_ = unacked_packets.largest_sent_packet();
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index 7a8ec67..2cd19a7 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -31,37 +31,43 @@
 
   ~GeneralLossAlgorithmTest() override {}
 
-  void SendDataPacket(QuicPacketNumber packet_number) {
+  void SendDataPacket(uint64_t packet_number) {
     QuicStreamFrame frame;
     frame.stream_id = QuicUtils::GetHeadersStreamId(
         CurrentSupportedVersions()[0].transport_version);
-    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr,
-                            kDefaultLength, false, false);
+    SerializedPacket packet(QuicPacketNumber(packet_number),
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            false, false);
     packet.retransmittable_frames.push_back(QuicFrame(frame));
-    unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
-                                   true);
+    unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                   NOT_RETRANSMISSION, clock_.Now(), true);
   }
 
-  void SendAckPacket(QuicPacketNumber packet_number) {
-    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr,
-                            kDefaultLength, true, false);
-    unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
-                                   false);
+  void SendAckPacket(uint64_t packet_number) {
+    SerializedPacket packet(QuicPacketNumber(packet_number),
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            true, false);
+    unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                   NOT_RETRANSMISSION, clock_.Now(), false);
   }
 
-  void VerifyLosses(QuicPacketNumber largest_newly_acked,
+  void VerifyLosses(uint64_t largest_newly_acked,
                     const AckedPacketVector& packets_acked,
-                    const std::vector<QuicPacketNumber>& losses_expected) {
-    if (largest_newly_acked > unacked_packets_.largest_acked()) {
-      unacked_packets_.IncreaseLargestAcked(largest_newly_acked);
+                    const std::vector<uint64_t>& losses_expected) {
+    if (!unacked_packets_.largest_acked().IsInitialized() ||
+        QuicPacketNumber(largest_newly_acked) >
+            unacked_packets_.largest_acked()) {
+      unacked_packets_.IncreaseLargestAcked(
+          QuicPacketNumber(largest_newly_acked));
     }
     LostPacketVector lost_packets;
     loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
-                                 largest_newly_acked, packets_acked,
-                                 &lost_packets);
+                                 QuicPacketNumber(largest_newly_acked),
+                                 packets_acked, &lost_packets);
     ASSERT_EQ(losses_expected.size(), lost_packets.size());
     for (size_t i = 0; i < losses_expected.size(); ++i) {
-      EXPECT_EQ(lost_packets[i].packet_number, losses_expected[i]);
+      EXPECT_EQ(lost_packets[i].packet_number,
+                QuicPacketNumber(losses_expected[i]));
     }
   }
 
@@ -79,18 +85,21 @@
   }
   AckedPacketVector packets_acked;
   // No loss on one ack.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // No loss on two acks.
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // Loss on three acks.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -105,12 +114,15 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in a single StretchAck.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -124,8 +136,9 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in an AckFrame with three missing packets.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -138,9 +151,10 @@
   }
   AckedPacketVector packets_acked;
   // Early retransmit when the final packet gets acked and the first is nacked.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
@@ -162,9 +176,9 @@
   AckedPacketVector packets_acked;
   // Early retransmit when the final packet gets acked and 1.25 RTTs have
   // elapsed since the packets were sent.
-  unacked_packets_.RemoveFromInFlight(kNumSentPackets);
-  packets_acked.push_back(
-      AckedPacket(kNumSentPackets, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(kNumSentPackets));
+  packets_acked.push_back(AckedPacket(QuicPacketNumber(kNumSentPackets),
+                                      kMaxPacketSize, QuicTime::Zero()));
   // This simulates a single ack following multiple missing packets with FACK.
   VerifyLosses(kNumSentPackets, packets_acked, {1, 2});
   packets_acked.clear();
@@ -190,14 +204,15 @@
   }
   AckedPacketVector packets_acked;
   // Neuter packet 1.
-  unacked_packets_.RemoveRetransmittability(1);
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(1));
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
 
   // Early retransmit when the final packet gets acked and the first is nacked.
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 }
@@ -211,10 +226,11 @@
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
 
   // Early retransmit when the final packet gets acked and the first is nacked.
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
@@ -237,9 +253,10 @@
   AckedPacketVector packets_acked;
   // Wait another RTT and ack 2.
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(2, packets_acked, {1});
 }
 
@@ -253,18 +270,21 @@
   }
   AckedPacketVector packets_acked;
   // No loss on one ack.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // No loss on two acks.
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // Loss on three acks.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -281,19 +301,23 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in a single StretchAck.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // The timer isn't set because we expect more acks.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Process another ack and then packet 1 will be lost.
-  unacked_packets_.RemoveFromInFlight(5);
-  packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(5));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(5), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(5, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -308,15 +332,17 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in an AckFrame with three missing packets.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // The timer isn't set because we expect more acks.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Process another ack and then packet 1 and 2 will be lost.
-  unacked_packets_.RemoveFromInFlight(5);
-  packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(5));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(5), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(5, packets_acked, {1, 2});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -330,10 +356,11 @@
     SendDataPacket(i);
   }
   AckedPacketVector packets_acked;
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
   for (size_t i = 1; i < 500; ++i) {
-    VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+    VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
     packets_acked.clear();
   }
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
@@ -357,9 +384,10 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
@@ -370,7 +398,7 @@
     EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
               loss_algorithm_.GetLossTimeout() - clock_.Now());
   }
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -388,16 +416,17 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost without a nack.
-  unacked_packets_.RemoveFromInFlight(1);
-  packets_acked.push_back(AckedPacket(1, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(1), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(1, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // The timer should still not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
-  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(1, packets_acked, std::vector<uint64_t>{});
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
-  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(1, packets_acked, std::vector<uint64_t>{});
 
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -414,9 +443,10 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
-  unacked_packets_.RemoveFromInFlight(10);
-  packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(10));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(10), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(10, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
@@ -445,9 +475,10 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
 
-  unacked_packets_.RemoveFromInFlight(10);
-  packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(10));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(10), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(10, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
@@ -461,10 +492,11 @@
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   // Now ack packets 1 to 9 and ensure the timer is no longer set and no packets
   // are lost.
-  for (QuicPacketNumber i = 1; i <= 9; ++i) {
-    unacked_packets_.RemoveFromInFlight(i);
-    packets_acked.push_back(AckedPacket(i, kMaxPacketSize, QuicTime::Zero()));
-    VerifyLosses(i, packets_acked, std::vector<QuicPacketNumber>{});
+  for (uint64_t i = 1; i <= 9; ++i) {
+    unacked_packets_.RemoveFromInFlight(QuicPacketNumber(i));
+    packets_acked.push_back(
+        AckedPacket(QuicPacketNumber(i), kMaxPacketSize, QuicTime::Zero()));
+    VerifyLosses(i, packets_acked, std::vector<uint64_t>{});
     packets_acked.clear();
     EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   }
@@ -484,14 +516,15 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Packet 1 should not be lost until 1/16 RTTs pass.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // Expect the timer to be set to 1/16 RTT's in the future.
   EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 16),
             loss_algorithm_.GetLossTimeout() - clock_.Now());
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 16));
   VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -508,13 +541,13 @@
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
   }
   loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
-                                             rtt_stats_, 11);
+                                             rtt_stats_, QuicPacketNumber(11));
   EXPECT_EQ(1, loss_algorithm_.reordering_shift());
 
   // Detect another spurious retransmit and ensure the threshold doesn't
   // increase again.
   loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
-                                             rtt_stats_, 12);
+                                             rtt_stats_, QuicPacketNumber(12));
   EXPECT_EQ(1, loss_algorithm_.reordering_shift());
 }
 
diff --git a/quic/core/congestion_control/hybrid_slow_start.cc b/quic/core/congestion_control/hybrid_slow_start.cc
index 11a14e6..28963b1 100644
--- a/quic/core/congestion_control/hybrid_slow_start.cc
+++ b/quic/core/congestion_control/hybrid_slow_start.cc
@@ -24,8 +24,6 @@
 HybridSlowStart::HybridSlowStart()
     : started_(false),
       hystart_found_(NOT_FOUND),
-      last_sent_packet_number_(0),
-      end_packet_number_(0),
       rtt_sample_count_(0),
       current_min_rtt_(QuicTime::Delta::Zero()) {}
 
@@ -56,7 +54,7 @@
 }
 
 bool HybridSlowStart::IsEndOfRound(QuicPacketNumber ack) const {
-  return end_packet_number_ <= ack;
+  return !end_packet_number_.IsInitialized() || end_packet_number_ <= ack;
 }
 
 bool HybridSlowStart::ShouldExitSlowStart(QuicTime::Delta latest_rtt,
diff --git a/quic/core/congestion_control/hybrid_slow_start_test.cc b/quic/core/congestion_control/hybrid_slow_start_test.cc
index c97c616..aa2f849 100644
--- a/quic/core/congestion_control/hybrid_slow_start_test.cc
+++ b/quic/core/congestion_control/hybrid_slow_start_test.cc
@@ -24,8 +24,8 @@
 };
 
 TEST_F(HybridSlowStartTest, Simple) {
-  QuicPacketNumber packet_number = 1;
-  QuicPacketNumber end_packet_number = 3;
+  QuicPacketNumber packet_number(1);
+  QuicPacketNumber end_packet_number(3);
   slow_start_->StartReceiveRound(end_packet_number);
 
   EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
@@ -39,7 +39,7 @@
   // Test without a new registered end_packet_number;
   EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
 
-  end_packet_number = 20;
+  end_packet_number = QuicPacketNumber(20);
   slow_start_->StartReceiveRound(end_packet_number);
   while (packet_number < end_packet_number) {
     EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
@@ -52,7 +52,7 @@
   // RTT of 60ms the detection will happen at 67.5 ms.
   const int kHybridStartMinSamples = 8;  // Number of acks required to trigger.
 
-  QuicPacketNumber end_packet_number = 1;
+  QuicPacketNumber end_packet_number(1);
   slow_start_->StartReceiveRound(end_packet_number++);
 
   // Will not trigger since our lowest RTT in our burst is the same as the long
diff --git a/quic/core/congestion_control/pacing_sender_test.cc b/quic/core/congestion_control/pacing_sender_test.cc
index 904fb8d..0bb9258 100644
--- a/quic/core/congestion_control/pacing_sender_test.cc
+++ b/quic/core/congestion_control/pacing_sender_test.cc
@@ -50,7 +50,7 @@
     if (burst_size == 0) {
       EXPECT_CALL(*mock_sender_, OnCongestionEvent(_, _, _, _, _));
       LostPacketVector lost_packets;
-      lost_packets.push_back(LostPacket(1, kMaxPacketSize));
+      lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
       AckedPacketVector empty;
       pacing_sender_->OnCongestionEvent(true, 1234, clock_.Now(), empty,
                                         lost_packets);
@@ -320,7 +320,7 @@
 
   // Losing a packet will set clear burst tokens.
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(1, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
   AckedPacketVector empty_acked;
   EXPECT_CALL(*mock_sender_,
               OnCongestionEvent(true, kMaxPacketSize, _, IsEmpty(), _));
diff --git a/quic/core/congestion_control/rtt_stats_test.cc b/quic/core/congestion_control/rtt_stats_test.cc
index 4d154a6..83cb155 100644
--- a/quic/core/congestion_control/rtt_stats_test.cc
+++ b/quic/core/congestion_control/rtt_stats_test.cc
@@ -192,9 +192,9 @@
   for (QuicTime::Delta bad_send_delta : bad_send_deltas) {
     SCOPED_TRACE(Message() << "bad_send_delta = "
                            << bad_send_delta.ToMicroseconds());
-#if QUIC_LOG_WARNING_IS_ON
-    EXPECT_QUIC_LOG_CALL_CONTAINS(log, WARNING, "Ignoring");
-#endif
+    if (QUIC_LOG_WARNING_IS_ON()) {
+      EXPECT_QUIC_LOG_CALL_CONTAINS(log, WARNING, "Ignoring");
+    }
     rtt_stats_.UpdateRtt(bad_send_delta, QuicTime::Delta::Zero(),
                          QuicTime::Zero());
     EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
index 1d903ea..5b843eb 100644
--- a/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
+++ b/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
@@ -38,9 +38,6 @@
       stats_(stats),
       reno_(reno),
       num_connections_(kDefaultNumConnections),
-      largest_sent_packet_number_(kInvalidPacketNumber),
-      largest_acked_packet_number_(kInvalidPacketNumber),
-      largest_sent_at_last_cutback_(kInvalidPacketNumber),
       min4_mode_(false),
       last_cutback_exited_slowstart_(false),
       slow_start_large_reduction_(false),
@@ -151,8 +148,12 @@
                                         QuicByteCount acked_bytes,
                                         QuicByteCount prior_in_flight,
                                         QuicTime event_time) {
-  largest_acked_packet_number_ =
-      std::max(acked_packet_number, largest_acked_packet_number_);
+  if (largest_acked_packet_number_.IsInitialized()) {
+    largest_acked_packet_number_ =
+        std::max(acked_packet_number, largest_acked_packet_number_);
+  } else {
+    largest_acked_packet_number_ = acked_packet_number;
+  }
   if (InRecovery()) {
     if (!no_prr_) {
       // PRR is used when in recovery.
@@ -184,7 +185,8 @@
     // PRR is used when in recovery.
     prr_.OnPacketSent(bytes);
   }
-  DCHECK_LT(largest_sent_packet_number_, packet_number);
+  DCHECK(!largest_sent_packet_number_.IsInitialized() ||
+         largest_sent_packet_number_ < packet_number);
   largest_sent_packet_number_ = packet_number;
   hybrid_slow_start_.OnPacketSent(packet_number);
 }
@@ -240,8 +242,9 @@
 }
 
 bool TcpCubicSenderBytes::InRecovery() const {
-  return largest_acked_packet_number_ <= largest_sent_at_last_cutback_ &&
-         largest_acked_packet_number_ != kInvalidPacketNumber;
+  return largest_acked_packet_number_.IsInitialized() &&
+         largest_sent_at_last_cutback_.IsInitialized() &&
+         largest_acked_packet_number_ <= largest_sent_at_last_cutback_;
 }
 
 bool TcpCubicSenderBytes::ShouldSendProbingPacket() const {
@@ -249,7 +252,7 @@
 }
 
 void TcpCubicSenderBytes::OnRetransmissionTimeout(bool packets_retransmitted) {
-  largest_sent_at_last_cutback_ = kInvalidPacketNumber;
+  largest_sent_at_last_cutback_.Clear();
   if (!packets_retransmitted) {
     return;
   }
@@ -298,7 +301,8 @@
                                        QuicByteCount prior_in_flight) {
   // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
   // already sent should be treated as a single loss event, since it's expected.
-  if (packet_number <= largest_sent_at_last_cutback_) {
+  if (largest_sent_at_last_cutback_.IsInitialized() &&
+      packet_number <= largest_sent_at_last_cutback_) {
     if (last_cutback_exited_slowstart_) {
       ++stats_->slowstart_packets_lost;
       stats_->slowstart_bytes_lost += lost_bytes;
@@ -414,9 +418,9 @@
 void TcpCubicSenderBytes::OnConnectionMigration() {
   hybrid_slow_start_.Restart();
   prr_ = PrrSender();
-  largest_sent_packet_number_ = kInvalidPacketNumber;
-  largest_acked_packet_number_ = kInvalidPacketNumber;
-  largest_sent_at_last_cutback_ = kInvalidPacketNumber;
+  largest_sent_packet_number_.Clear();
+  largest_acked_packet_number_.Clear();
+  largest_sent_at_last_cutback_.Clear();
   last_cutback_exited_slowstart_ = false;
   cubic_.ResetCubicState();
   num_acked_packets_ = 0;
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
index b7234bc..5eb6226 100644
--- a/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
+++ b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -69,8 +69,9 @@
     int packets_sent = 0;
     bool can_send = sender_->CanSend(bytes_in_flight_);
     while (can_send) {
-      sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++,
-                            kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA);
+      sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
+                            QuicPacketNumber(packet_number_++), kDefaultTCPMSS,
+                            HAS_RETRANSMITTABLE_DATA);
       ++packets_sent;
       bytes_in_flight_ += kDefaultTCPMSS;
       can_send = sender_->CanSend(bytes_in_flight_);
@@ -87,7 +88,8 @@
     for (int i = 0; i < n; ++i) {
       ++acked_packet_number_;
       acked_packets.push_back(
-          AckedPacket(acked_packet_number_, kDefaultTCPMSS, QuicTime::Zero()));
+          AckedPacket(QuicPacketNumber(acked_packet_number_), kDefaultTCPMSS,
+                      QuicTime::Zero()));
     }
     sender_->OnCongestionEvent(true, bytes_in_flight_, clock_.Now(),
                                acked_packets, lost_packets);
@@ -102,7 +104,8 @@
     LostPacketVector lost_packets;
     for (int i = 0; i < n; ++i) {
       ++acked_packet_number_;
-      lost_packets.push_back(LostPacket(acked_packet_number_, packet_length));
+      lost_packets.push_back(
+          LostPacket(QuicPacketNumber(acked_packet_number_), packet_length));
     }
     sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(),
                                acked_packets, lost_packets);
@@ -110,10 +113,11 @@
   }
 
   // Does not increment acked_packet_number_.
-  void LosePacket(QuicPacketNumber packet_number) {
+  void LosePacket(uint64_t packet_number) {
     AckedPacketVector acked_packets;
     LostPacketVector lost_packets;
-    lost_packets.push_back(LostPacket(packet_number, kDefaultTCPMSS));
+    lost_packets.push_back(
+        LostPacket(QuicPacketNumber(packet_number), kDefaultTCPMSS));
     sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(),
                                acked_packets, lost_packets);
     bytes_in_flight_ -= kDefaultTCPMSS;
@@ -122,8 +126,8 @@
   const QuicTime::Delta one_ms_;
   MockClock clock_;
   std::unique_ptr<TcpCubicSenderBytesPeer> sender_;
-  QuicPacketNumber packet_number_;
-  QuicPacketNumber acked_packet_number_;
+  uint64_t packet_number_;
+  uint64_t acked_packet_number_;
   QuicByteCount bytes_in_flight_;
 };
 
@@ -779,7 +783,8 @@
   LostPacketVector missing_packets;
   for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
     acked_packets.clear();
-    acked_packets.push_back(AckedPacket(i, 1350, QuicTime::Zero()));
+    acked_packets.push_back(
+        AckedPacket(QuicPacketNumber(i), 1350, QuicTime::Zero()));
     sender->OnCongestionEvent(true, sender->GetCongestionWindow(), clock_.Now(),
                               acked_packets, missing_packets);
   }
diff --git a/quic/core/crypto/aead_base_decrypter.cc b/quic/core/crypto/aead_base_decrypter.cc
index f5ec25c..51cfa26 100644
--- a/quic/core/crypto/aead_base_decrypter.cc
+++ b/quic/core/crypto/aead_base_decrypter.cc
@@ -142,7 +142,7 @@
 }
 
 bool AeadBaseDecrypter::DecryptPacket(QuicTransportVersion /*version*/,
-                                      QuicPacketNumber packet_number,
+                                      uint64_t packet_number,
                                       QuicStringPiece associated_data,
                                       QuicStringPiece ciphertext,
                                       char* output,
diff --git a/quic/core/crypto/aead_base_decrypter.h b/quic/core/crypto/aead_base_decrypter.h
index 494d6c2..b4906b8 100644
--- a/quic/core/crypto/aead_base_decrypter.h
+++ b/quic/core/crypto/aead_base_decrypter.h
@@ -36,7 +36,7 @@
   bool SetPreliminaryKey(QuicStringPiece key) override;
   bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
   bool DecryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.cc b/quic/core/crypto/aead_base_encrypter.cc
index cbe07e3..199851e 100644
--- a/quic/core/crypto/aead_base_encrypter.cc
+++ b/quic/core/crypto/aead_base_encrypter.cc
@@ -124,7 +124,7 @@
 }
 
 bool AeadBaseEncrypter::EncryptPacket(QuicTransportVersion /*version*/,
-                                      QuicPacketNumber packet_number,
+                                      uint64_t packet_number,
                                       QuicStringPiece associated_data,
                                       QuicStringPiece plaintext,
                                       char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.h b/quic/core/crypto/aead_base_encrypter.h
index d3ee016..255bd87 100644
--- a/quic/core/crypto/aead_base_encrypter.h
+++ b/quic/core/crypto/aead_base_encrypter.h
@@ -34,7 +34,7 @@
   bool SetNoncePrefix(QuicStringPiece nonce_prefix) override;
   bool SetIV(QuicStringPiece iv) override;
   bool EncryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
diff --git a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
index 7ffbf6e..eb2fa5e 100644
--- a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
+++ b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -203,7 +203,7 @@
                            QuicStringPiece nonce,
                            QuicStringPiece associated_data,
                            QuicStringPiece ciphertext) {
-  QuicPacketNumber packet_number;
+  uint64_t packet_number;
   QuicStringPiece nonce_prefix(nonce.data(),
                                nonce.size() - sizeof(packet_number));
   decrypter->SetNoncePrefix(nonce_prefix);
diff --git a/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
index 68f56d0..79276ca 100644
--- a/quic/core/crypto/aes_128_gcm_encrypter_test.cc
+++ b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
@@ -220,7 +220,7 @@
 TEST_F(Aes128GcmEncrypterTest, EncryptPacket) {
   QuicString key = QuicTextUtils::HexDecode("d95a145250826c25a77b6a84fd4d34fc");
   QuicString iv = QuicTextUtils::HexDecode("50c4431ebb18283448e276e2");
-  QuicPacketNumber packet_num = 0x13278f44;
+  uint64_t packet_num = 0x13278f44;
   QuicString aad =
       QuicTextUtils::HexDecode("875d49f64a70c9cbe713278f44ff000005");
   QuicString pt = QuicTextUtils::HexDecode("aa0003a250bd000000000001");
diff --git a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
index ba72027..a0c3cbe 100644
--- a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -116,7 +116,7 @@
                            QuicStringPiece nonce,
                            QuicStringPiece associated_data,
                            QuicStringPiece ciphertext) {
-  QuicPacketNumber packet_number;
+  uint64_t packet_number;
   QuicStringPiece nonce_prefix(nonce.data(),
                                nonce.size() - sizeof(packet_number));
   decrypter->SetNoncePrefix(nonce_prefix);
diff --git a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
index b5b43fb..8d9a900 100644
--- a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -96,7 +96,7 @@
   ASSERT_TRUE(encrypter.SetNoncePrefix("abcd"));
   ASSERT_TRUE(decrypter.SetNoncePrefix("abcd"));
 
-  QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
+  uint64_t packet_number = UINT64_C(0x123456789ABC);
   QuicString associated_data = "associated_data";
   QuicString plaintext = "plaintext";
   char encrypted[1024];
diff --git a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
index 4a9ecf8..bc7c6c4 100644
--- a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
@@ -95,7 +95,7 @@
   ASSERT_TRUE(encrypter.SetIV("abcdefghijkl"));
   ASSERT_TRUE(decrypter.SetIV("abcdefghijkl"));
 
-  QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
+  uint64_t packet_number = UINT64_C(0x123456789ABC);
   QuicString associated_data = "associated_data";
   QuicString plaintext = "plaintext";
   char encrypted[1024];
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc
index a97b829..c2c4041 100644
--- a/quic/core/crypto/crypto_server_test.cc
+++ b/quic/core/crypto/crypto_server_test.cc
@@ -107,7 +107,7 @@
   CryptoServerTest()
       : rand_(QuicRandom::GetInstance()),
         client_address_(QuicIpAddress::Loopback4(), 1234),
-        client_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+        client_version_(UnsupportedQuicVersion()),
         config_(QuicCryptoServerConfig::TESTING,
                 rand_,
                 crypto_test_utils::ProofSourceForTesting(),
@@ -723,6 +723,26 @@
   CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons));
 }
 
+TEST_P(CryptoServerTest, CorruptSourceAddressTokenIsStillAccepted) {
+  // This tests corrupted source address token.
+  CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO(
+      {{"PDMD", "X509"},
+       {"AEAD", "AESG"},
+       {"KEXS", "C255"},
+       {"SCID", scid_hex_},
+       {"#004b5453", (QuicString(1, 'X') + srct_hex_)},
+       {"PUBS", pub_hex_},
+       {"NONC", nonce_hex_},
+       {"XLCT", XlctHexString()},
+       {"VER\0", client_version_string_}},
+      kClientHelloMinimumSize);
+
+  config_.set_validate_source_address_token(false);
+
+  ShouldSucceed(msg);
+  EXPECT_EQ(kSHLO, out_.tag());
+}
+
 TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) {
   // This test corrupts client nonce and source address token.
   CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO(
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc
index 72fbdd9..46d172f 100644
--- a/quic/core/crypto/crypto_utils.cc
+++ b/quic/core/crypto/crypto_utils.cc
@@ -95,11 +95,13 @@
 
 // static
 void CryptoUtils::CreateTlsInitialCrypters(Perspective perspective,
+                                           QuicTransportVersion version,
                                            QuicConnectionId connection_id,
                                            CrypterPair* crypters) {
-  QUIC_BUG_IF(connection_id.length() != kQuicDefaultConnectionIdLength)
-      << "CreateTlsInitialCrypters called with connection ID " << connection_id
-      << " of unsupported length " << connection_id.length();
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(connection_id, version))
+      << "CreateTlsInitialCrypters: attempted to use connection ID "
+      << connection_id << " which is invalid with version "
+      << QuicVersionToString(version);
   const EVP_MD* hash = EVP_sha256();
 
   std::vector<uint8_t> handshake_secret;
diff --git a/quic/core/crypto/crypto_utils.h b/quic/core/crypto/crypto_utils.h
index 713822a..511bae9 100644
--- a/quic/core/crypto/crypto_utils.h
+++ b/quic/core/crypto/crypto_utils.h
@@ -90,6 +90,7 @@
   // decrypter (put in |*crypters|) to use for this packet protection, as well
   // as setting the key and IV on those crypters.
   static void CreateTlsInitialCrypters(Perspective perspective,
+                                       QuicTransportVersion version,
                                        QuicConnectionId connection_id,
                                        CrypterPair* crypters);
 
diff --git a/quic/core/crypto/ephemeral_key_source.h b/quic/core/crypto/ephemeral_key_source.h
deleted file mode 100644
index e494310..0000000
--- a/quic/core/crypto/ephemeral_key_source.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
-#define QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
-
-#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
-#include "net/third_party/quiche/src/quic/core/quic_time.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-
-namespace quic {
-
-class QuicRandom;
-
-// EphemeralKeySource manages and rotates ephemeral keys as they can be reused
-// for several connections in a short space of time. Since the implementation
-// of this may involve locking or thread-local data, this interface abstracts
-// that away.
-class QUIC_EXPORT_PRIVATE EphemeralKeySource {
- public:
-  virtual ~EphemeralKeySource() {}
-
-  // CalculateForwardSecureKey generates an ephemeral public/private key pair
-  // using the algorithm represented by |key_exchange_factory|, sets
-  // |*public_value| to the public key and returns the shared key between
-  // |peer_public_value| and the private key. |*public_value| will be sent to
-  // the peer to be used with the peer's private key.
-  virtual QuicString CalculateForwardSecureKey(
-      const KeyExchange::Factory& key_exchange_factory,
-      QuicRandom* rand,
-      QuicTime now,
-      QuicStringPiece peer_public_value,
-      QuicString* public_value) = 0;
-};
-
-}  // namespace quic
-
-#endif  // QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
diff --git a/quic/core/crypto/null_decrypter.cc b/quic/core/crypto/null_decrypter.cc
index ba470f5..0c108b6 100644
--- a/quic/core/crypto/null_decrypter.cc
+++ b/quic/core/crypto/null_decrypter.cc
@@ -39,7 +39,7 @@
 }
 
 bool NullDecrypter::DecryptPacket(QuicTransportVersion version,
-                                  QuicPacketNumber /*packet_number*/,
+                                  uint64_t /*packet_number*/,
                                   QuicStringPiece associated_data,
                                   QuicStringPiece ciphertext,
                                   char* output,
diff --git a/quic/core/crypto/null_decrypter.h b/quic/core/crypto/null_decrypter.h
index 275228c..3996eb7 100644
--- a/quic/core/crypto/null_decrypter.h
+++ b/quic/core/crypto/null_decrypter.h
@@ -36,7 +36,7 @@
   bool SetPreliminaryKey(QuicStringPiece key) override;
   bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
   bool DecryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
diff --git a/quic/core/crypto/null_encrypter.cc b/quic/core/crypto/null_encrypter.cc
index 524caef..e4a165f 100644
--- a/quic/core/crypto/null_encrypter.cc
+++ b/quic/core/crypto/null_encrypter.cc
@@ -27,7 +27,7 @@
 }
 
 bool NullEncrypter::EncryptPacket(QuicTransportVersion version,
-                                  QuicPacketNumber /*packet_number*/,
+                                  uint64_t /*packet_number*/,
                                   QuicStringPiece associated_data,
                                   QuicStringPiece plaintext,
                                   char* output,
diff --git a/quic/core/crypto/null_encrypter.h b/quic/core/crypto/null_encrypter.h
index d826202..01ecd45 100644
--- a/quic/core/crypto/null_encrypter.h
+++ b/quic/core/crypto/null_encrypter.h
@@ -30,7 +30,7 @@
   bool SetNoncePrefix(QuicStringPiece nonce_prefix) override;
   bool SetIV(QuicStringPiece iv) override;
   bool EncryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index 0a37be8..56447bb 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -13,6 +13,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
 #include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
 #include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h"
 #include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
@@ -88,8 +89,8 @@
 
   const CryptoHandshakeMessage* scfg = GetServerConfig();
   if (!scfg) {
-    RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
     // Should be impossible short of cache corruption.
+    RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
     DCHECK(false);
     return false;
   }
@@ -441,7 +442,11 @@
     CryptoHandshakeMessage* out) const {
   out->set_tag(kCHLO);
   // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag.
-  out->set_minimum_size(kClientHelloMinimumSize);
+  if (pad_inchoate_hello_) {
+    out->set_minimum_size(kClientHelloMinimumSize);
+  } else {
+    out->set_minimum_size(1);
+  }
 
   // Server name indication. We only send SNI if it's a valid domain name, as
   // per the spec.
@@ -517,13 +522,21 @@
     CryptoHandshakeMessage* out,
     QuicString* error_details) const {
   DCHECK(error_details != nullptr);
-  QUIC_BUG_IF(connection_id.length() != kQuicDefaultConnectionIdLength)
-      << "FillClientHello called with connection ID " << connection_id
-      << " of unsupported length " << connection_id.length();
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      connection_id, preferred_version.transport_version))
+      << "FillClientHello: attempted to use connection ID " << connection_id
+      << " which is invalid with version "
+      << QuicVersionToString(preferred_version.transport_version);
 
   FillInchoateClientHello(server_id, preferred_version, cached, rand,
                           /* demand_x509_proof= */ true, out_params, out);
 
+  if (pad_full_hello_) {
+    out->set_minimum_size(kClientHelloMinimumSize);
+  } else {
+    out->set_minimum_size(1);
+  }
+
   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
   if (!scfg) {
     // This should never happen as our caller should have checked
@@ -860,10 +873,9 @@
       }
       connection_id = QuicConnectionId(connection_id_bytes.data(),
                                        connection_id_bytes.length());
-      if (connection_id.length() != kQuicDefaultConnectionIdLength) {
+      if (!QuicUtils::IsConnectionIdValidForVersion(connection_id, version)) {
         QUIC_PEER_BUG << "Received server-designated connection ID "
-                      << connection_id << " of bad length "
-                      << connection_id.length() << " with version "
+                      << connection_id << " which is invalid with version "
                       << QuicVersionToString(version);
         *error_details = "Bad kRCID length";
         return QUIC_CRYPTO_INTERNAL_ERROR;
diff --git a/quic/core/crypto/quic_crypto_client_config.h b/quic/core/crypto/quic_crypto_client_config.h
index c7e46a9..32df726 100644
--- a/quic/core/crypto/quic_crypto_client_config.h
+++ b/quic/core/crypto/quic_crypto_client_config.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "third_party/boringssl/src/include/openssl/base.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_server_id.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -351,6 +352,14 @@
     pre_shared_key_ = QuicString(psk);
   }
 
+  bool pad_inchoate_hello() const { return pad_inchoate_hello_; }
+  void set_pad_inchoate_hello(bool new_value) {
+    pad_inchoate_hello_ = new_value;
+  }
+
+  bool pad_full_hello() const { return pad_full_hello_; }
+  void set_pad_full_hello(bool new_value) { pad_full_hello_ = new_value; }
+
  private:
   // Sets the members to reasonable, default values.
   void SetDefaults();
@@ -402,6 +411,20 @@
   // If non-empty, the client will operate in the pre-shared key mode by
   // incorporating |pre_shared_key_| into the key schedule.
   QuicString pre_shared_key_;
+
+  // In QUIC, technically, client hello should be fully padded.
+  // However, fully padding on slow network connection (e.g. 50kbps) can add
+  // 150ms latency to one roundtrip. Therefore, you can disable padding of
+  // individual messages. It is recommend to leave at least one message in
+  // each direction fully padded (e.g. full CHLO and SHLO), but if you know
+  // the lower-bound MTU, you don't need to pad all of them (keep in mind that
+  // it's not OK to do it according to the standard).
+  //
+  // Also, if you disable padding, you must disable (change) the
+  // anti-amplification protection. You should only do so if you have some
+  // other means of verifying the client.
+  bool pad_inchoate_hello_ = true;
+  bool pad_full_hello_ = true;
 };
 
 }  // namespace quic
diff --git a/quic/core/crypto/quic_crypto_client_config_test.cc b/quic/core/crypto/quic_crypto_client_config_test.cc
index 8cc0420..5e0ca6e 100644
--- a/quic/core/crypto/quic_crypto_client_config_test.cc
+++ b/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -113,9 +113,11 @@
 TEST_F(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) {
   QuicCryptoClientConfig::CachedState state;
   EXPECT_FALSE(state.has_server_designated_connection_id());
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
   EXPECT_DEBUG_DEATH(state.GetNextServerDesignatedConnectionId(),
                      "Attempting to consume a connection id "
                      "that was never designated.");
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
 }
 
 TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonce) {
@@ -152,9 +154,11 @@
 TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonceConsumedBeforeSet) {
   QuicCryptoClientConfig::CachedState state;
   EXPECT_FALSE(state.has_server_nonce());
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
   EXPECT_DEBUG_DEATH(state.GetNextServerNonce(),
                      "Attempting to consume a server nonce "
                      "that was never designated.");
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
 }
 
 TEST_F(QuicCryptoClientConfigTest, CachedState_InitializeFrom) {
@@ -197,6 +201,26 @@
   QuicStringPiece alpn;
   EXPECT_TRUE(msg.GetStringPiece(kALPN, &alpn));
   EXPECT_EQ("hq", alpn);
+
+  EXPECT_EQ(msg.minimum_size(), 1024u);
+}
+
+TEST_F(QuicCryptoClientConfigTest, InchoateChloIsNotPadded) {
+  QuicCryptoClientConfig::CachedState state;
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
+                                TlsClientHandshaker::CreateSslCtx());
+  config.set_pad_inchoate_hello(false);
+  config.set_user_agent_id("quic-tester");
+  config.set_alpn("hq");
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
+      new QuicCryptoNegotiatedParameters);
+  CryptoHandshakeMessage msg;
+  QuicServerId server_id("www.google.com", 443, false);
+  MockRandom rand;
+  config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
+                                 /* demand_x509_proof= */ true, params, &msg);
+
+  EXPECT_EQ(msg.minimum_size(), 1u);
 }
 
 // Make sure AES-GCM is the preferred encryption algorithm if it has hardware
@@ -307,6 +331,30 @@
   EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver);
 }
 
+TEST_F(QuicCryptoClientConfigTest, FillClientHelloNoPadding) {
+  QuicCryptoClientConfig::CachedState state;
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
+                                TlsClientHandshaker::CreateSslCtx());
+  config.set_pad_full_hello(false);
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
+      new QuicCryptoNegotiatedParameters);
+  QuicConnectionId kConnectionId = TestConnectionId(1234);
+  QuicString error_details;
+  MockRandom rand;
+  CryptoHandshakeMessage chlo;
+  QuicServerId server_id("www.google.com", 443, false);
+  config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state,
+                         QuicWallTime::Zero(), &rand,
+                         nullptr,  // channel_id_key
+                         params, &chlo, &error_details);
+
+  // Verify that the version label has been set correctly in the CHLO.
+  QuicVersionLabel cver;
+  EXPECT_EQ(QUIC_NO_ERROR, chlo.GetVersionLabel(kVER, &cver));
+  EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver);
+  EXPECT_EQ(chlo.minimum_size(), 1u);
+}
+
 TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) {
   ParsedQuicVersionVector supported_versions = AllSupportedVersions();
   if (supported_versions.size() == 1) {
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index 1004236..851f8e3 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -20,7 +20,6 @@
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
 #include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h"
-#include "net/third_party/quiche/src/quic/core/crypto/ephemeral_key_source.h"
 #include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
 #include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h"
 #include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
@@ -35,6 +34,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
@@ -220,7 +220,11 @@
       source_address_token_future_secs_(3600),
       source_address_token_lifetime_secs_(86400),
       enable_serving_sct_(false),
-      rejection_observer_(nullptr) {
+      rejection_observer_(nullptr),
+      pad_rej_(true),
+      pad_shlo_(true),
+      validate_chlo_size_(true),
+      validate_source_address_token_(true) {
   DCHECK(proof_source_.get());
   source_address_token_boxer_.SetKeys(
       {DeriveSourceAddressTokenKey(source_address_token_secret)});
@@ -507,13 +511,11 @@
   QuicReferenceCountedPointer<Config> primary_config;
   {
     QuicReaderMutexLock locked(&configs_lock_);
-
     if (!primary_config_.get()) {
       result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
       result->error_details = "No configurations loaded";
     } else {
-      if (!next_config_promotion_time_.IsZero() &&
-          next_config_promotion_time_.IsAfter(now)) {
+      if (IsNextConfigReady(now)) {
         configs_lock_.ReaderUnlock();
         configs_lock_.WriterLock();
         SelectNewPrimaryConfig(now);
@@ -678,6 +680,7 @@
           validate_chlo_result,
       QuicConnectionId connection_id,
       const QuicSocketAddress& client_address,
+      ParsedQuicVersion version,
       const ParsedQuicVersionVector& supported_versions,
       const QuicClock* clock,
       QuicRandom* rand,
@@ -694,6 +697,7 @@
         validate_chlo_result_(std::move(validate_chlo_result)),
         connection_id_(connection_id),
         client_address_(client_address),
+        version_(version),
         supported_versions_(supported_versions),
         clock_(clock),
         rand_(rand),
@@ -707,7 +711,7 @@
     config_->ProcessClientHelloAfterCalculateSharedKeys(
         !ok, std::move(proof_source_details_), key_exchange_factory_,
         std::move(out_), public_value_, *validate_chlo_result_, connection_id_,
-        client_address_, supported_versions_, clock_, rand_, params_,
+        client_address_, version_, supported_versions_, clock_, rand_, params_,
         signed_config_, requested_config_, primary_config_,
         std::move(done_cb_));
   }
@@ -722,6 +726,7 @@
       validate_chlo_result_;
   QuicConnectionId connection_id_;
   const QuicSocketAddress client_address_;
+  ParsedQuicVersion version_;
   const ParsedQuicVersionVector supported_versions_;
   const QuicClock* clock_;
   QuicRandom* rand_;
@@ -780,8 +785,7 @@
     if (!primary_config_) {
       no_primary_config = true;
     } else {
-      if (!next_config_promotion_time_.IsZero() &&
-          next_config_promotion_time_.IsAfter(now)) {
+      if (IsNextConfigReady(now)) {
         configs_lock_.ReaderUnlock();
         configs_lock_.WriterLock();
         SelectNewPrimaryConfig(now);
@@ -867,11 +871,11 @@
     const QuicReferenceCountedPointer<Config>& requested_config,
     const QuicReferenceCountedPointer<Config>& primary_config,
     std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
-  if (connection_id.length() != kQuicDefaultConnectionIdLength) {
-    QUIC_BUG << "ProcessClientHelloAfterGetProof called with connection ID "
-             << connection_id << " of unsupported length "
-             << connection_id.length();
-  }
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      connection_id, version.transport_version))
+      << "ProcessClientHelloAfterGetProof: attempted to use connection ID "
+      << connection_id << " which is invalid with version "
+      << QuicVersionToString(version.transport_version);
   if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
     connection_id = QuicConnectionIdFromUInt64(
         QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)));
@@ -965,25 +969,13 @@
   // TODO(rch): Would it be better to implement a move operator and just
   // std::move(helper) instead of done_cb?
   helper.DetachCallback();
-  if (GetQuicRestartFlag(quic_use_async_key_exchange)) {
-    QUIC_RESTART_FLAG_COUNT(quic_use_async_key_exchange);
-    auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>(
-        this, std::move(proof_source_details), key_exchange->GetFactory(),
-        std::move(out), public_value, validate_chlo_result, connection_id,
-        client_address, supported_versions, clock, rand, params, signed_config,
-        requested_config, primary_config, std::move(done_cb));
-    key_exchange->CalculateSharedKey(
-        public_value, &params->initial_premaster_secret, std::move(cb));
-  } else {
-    found_error = !key_exchange->CalculateSharedKey(
-        public_value, &params->initial_premaster_secret);
-    ProcessClientHelloAfterCalculateSharedKeys(
-        found_error, std::move(proof_source_details),
-        key_exchange->GetFactory(), std::move(out), public_value,
-        *validate_chlo_result, connection_id, client_address,
-        supported_versions, clock, rand, params, signed_config,
-        requested_config, primary_config, std::move(done_cb));
-  }
+  auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>(
+      this, std::move(proof_source_details), key_exchange->GetFactory(),
+      std::move(out), public_value, validate_chlo_result, connection_id,
+      client_address, version, supported_versions, clock, rand, params,
+      signed_config, requested_config, primary_config, std::move(done_cb));
+  key_exchange->CalculateSharedKey(
+      public_value, &params->initial_premaster_secret, std::move(cb));
 }
 
 void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
@@ -995,6 +987,7 @@
     const ValidateClientHelloResultCallback::Result& validate_chlo_result,
     QuicConnectionId connection_id,
     const QuicSocketAddress& client_address,
+    ParsedQuicVersion version,
     const ParsedQuicVersionVector& supported_versions,
     const QuicClock* clock,
     QuicRandom* rand,
@@ -1003,12 +996,12 @@
     const QuicReferenceCountedPointer<Config>& requested_config,
     const QuicReferenceCountedPointer<Config>& primary_config,
     std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
-  if (connection_id.length() != kQuicDefaultConnectionIdLength) {
-    QUIC_BUG << "ProcessClientHelloAfterCalculateSharedKeys called with "
-                "connection ID "
-             << connection_id << " of unsupported length "
-             << connection_id.length();
-  }
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      connection_id, version.transport_version))
+      << "ProcessClientHelloAfterCalculateSharedKeys:"
+         " attempted to use connection ID "
+      << connection_id << " which is invalid with version "
+      << QuicVersionToString(version.transport_version);
   ProcessClientHelloHelper helper(&done_cb);
 
   if (found_error) {
@@ -1140,30 +1133,14 @@
   }
 
   QuicString forward_secure_public_value;
-  if (GetQuicRestartFlag(quic_no_ephemeral_key_source)) {
-    if (ephemeral_key_source_) {
-      QUIC_BUG << "quic_no_ephemeral_key_source flag is on, but "
-                  "ephemeral_key_source is present";
-    } else {
-      QUIC_RESTART_FLAG_COUNT(quic_no_ephemeral_key_source);
-    }
-  }
-  if (ephemeral_key_source_) {
-    params->forward_secure_premaster_secret =
-        ephemeral_key_source_->CalculateForwardSecureKey(
-            key_exchange_factory, rand, clock->ApproximateNow(), public_value,
-            &forward_secure_public_value);
-  } else {
-    std::unique_ptr<KeyExchange> forward_secure_key_exchange =
-        key_exchange_factory.Create(rand);
-    forward_secure_public_value =
-        QuicString(forward_secure_key_exchange->public_value());
-    if (!forward_secure_key_exchange->CalculateSharedKey(
-            public_value, &params->forward_secure_premaster_secret)) {
-      helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
-                  "Invalid public value");
-      return;
-    }
+  std::unique_ptr<KeyExchange> forward_secure_key_exchange =
+      key_exchange_factory.Create(rand);
+  forward_secure_public_value =
+      QuicString(forward_secure_key_exchange->public_value());
+  if (!forward_secure_key_exchange->CalculateSharedKey(
+          public_value, &params->forward_secure_premaster_secret)) {
+    helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "Invalid public value");
+    return;
   }
 
   QuicString forward_secure_hkdf_input;
@@ -1332,7 +1309,6 @@
           requested_config,
       QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
           primary_config,
-      bool use_get_cert_chain,
       QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
       QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
           client_hello_state,
@@ -1342,7 +1318,6 @@
         version_(version),
         requested_config_(std::move(requested_config)),
         primary_config_(std::move(primary_config)),
-        use_get_cert_chain_(use_get_cert_chain),
         signed_config_(signed_config),
         client_hello_state_(std::move(client_hello_state)),
         done_cb_(std::move(done_cb)) {}
@@ -1357,8 +1332,8 @@
     }
     config_.EvaluateClientHelloAfterGetProof(
         server_ip_, version_, requested_config_, primary_config_,
-        signed_config_, std::move(details), use_get_cert_chain_, !ok,
-        client_hello_state_, std::move(done_cb_));
+        signed_config_, std::move(details), !ok, client_hello_state_,
+        std::move(done_cb_));
   }
 
  private:
@@ -1369,7 +1344,6 @@
       requested_config_;
   const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
       primary_config_;
-  const bool use_get_cert_chain_;
   QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
   QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
       client_hello_state_;
@@ -1392,7 +1366,7 @@
   const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
   ClientHelloInfo* info = &(client_hello_state->info);
 
-  if (client_hello.size() < kClientHelloMinimumSize) {
+  if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
     helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
                               "Client hello too small", nullptr);
     return;
@@ -1408,22 +1382,27 @@
   client_hello.GetStringPiece(kUAID, &info->user_agent_id);
 
   HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
-  QuicStringPiece srct;
-  if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
-    Config& config =
-        requested_config != nullptr ? *requested_config : *primary_config;
-    source_address_token_error =
-        ParseSourceAddressToken(config, srct, &info->source_address_tokens);
+  if (validate_source_address_token_) {
+    QuicStringPiece srct;
+    if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
+      Config& config =
+          requested_config != nullptr ? *requested_config : *primary_config;
+      source_address_token_error =
+          ParseSourceAddressToken(config, srct, &info->source_address_tokens);
 
-    if (source_address_token_error == HANDSHAKE_OK) {
-      source_address_token_error = ValidateSourceAddressTokens(
-          info->source_address_tokens, info->client_ip, info->now,
-          &client_hello_state->cached_network_params);
+      if (source_address_token_error == HANDSHAKE_OK) {
+        source_address_token_error = ValidateSourceAddressTokens(
+            info->source_address_tokens, info->client_ip, info->now,
+            &client_hello_state->cached_network_params);
+      }
+      info->valid_source_address_token =
+          (source_address_token_error == HANDSHAKE_OK);
+    } else {
+      source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
     }
-    info->valid_source_address_token =
-        (source_address_token_error == HANDSHAKE_OK);
   } else {
-    source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
+    source_address_token_error = HANDSHAKE_OK;
+    info->valid_source_address_token = true;
   }
 
   if (!requested_config.get()) {
@@ -1450,28 +1429,6 @@
     // No valid source address token.
   }
 
-  const bool use_get_cert_chain =
-      GetQuicReloadableFlag(quic_use_get_cert_chain);
-  if (!use_get_cert_chain) {
-    QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_get_cert_chain, 1, 2);
-    QuicString serialized_config = primary_config->serialized;
-    QuicString chlo_hash;
-    CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash,
-                                      Perspective::IS_SERVER);
-    // Make an async call to GetProof and setup the callback to trampoline
-    // back into EvaluateClientHelloAfterGetProof
-    auto cb = QuicMakeUnique<EvaluateClientHelloCallback>(
-        *this, server_address.host(), version, requested_config, primary_config,
-        use_get_cert_chain, signed_config, client_hello_state,
-        std::move(done_cb));
-    proof_source_->GetProof(server_address, QuicString(info->sni),
-                            serialized_config, version, chlo_hash,
-                            std::move(cb));
-    helper.DetachCallback();
-    return;
-  }
-
-  QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_get_cert_chain, 2, 2);
   QuicReferenceCountedPointer<ProofSource::Chain> chain =
       proof_source_->GetCertChain(server_address, QuicString(info->sni));
   if (!chain) {
@@ -1481,7 +1438,7 @@
   }
   EvaluateClientHelloAfterGetProof(
       server_address.host(), version, requested_config, primary_config,
-      signed_config, /*proof_source_details=*/nullptr, use_get_cert_chain,
+      signed_config, /*proof_source_details=*/nullptr,
       /*get_proof_failed=*/false, client_hello_state, std::move(done_cb));
   helper.DetachCallback();
 }
@@ -1493,7 +1450,6 @@
     QuicReferenceCountedPointer<Config> primary_config,
     QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
     std::unique_ptr<ProofSource::Details> proof_source_details,
-    bool use_get_cert_chain,
     bool get_proof_failed,
     QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
         client_hello_state,
@@ -1502,18 +1458,6 @@
   const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
   ClientHelloInfo* info = &(client_hello_state->info);
 
-  if (!use_get_cert_chain) {
-    if (get_proof_failed) {
-      info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
-    }
-
-    if (signed_config->chain != nullptr &&
-        !ValidateExpectedLeafCertificate(client_hello,
-                                         signed_config->chain->certs)) {
-      info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
-    }
-  }
-
   if (info->client_nonce.size() != kNonceSize) {
     info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
     // Invalid client nonce.
@@ -1673,12 +1617,11 @@
       out->SetValue(kRCID, QuicEndian::HostToNet64(QuicConnectionIdToUInt64(
                                server_designated_connection_id)));
     } else {
-      if (server_designated_connection_id.length() !=
-              kQuicDefaultConnectionIdLength &&
-          version < QUIC_VERSION_99) {
-        QUIC_BUG << "Tried to send connection ID "
-                 << server_designated_connection_id << " of bad length "
-                 << server_designated_connection_id.length() << " with version "
+      if (!QuicUtils::IsConnectionIdValidForVersion(
+              server_designated_connection_id, version)) {
+        QUIC_BUG << "Tried to send server designated connection ID "
+                 << server_designated_connection_id
+                 << " which is invalid with version "
                  << QuicVersionToString(version);
         return;
       }
@@ -1754,8 +1697,22 @@
     out->SetStringPiece(kPROF, signed_config.proof.signature);
     if (should_return_sct) {
       if (cert_sct.empty()) {
-        QUIC_LOG_EVERY_N_SEC(WARNING, 60)
-            << "SCT is expected but it is empty. sni :" << params->sni;
+        if (!GetQuicReloadableFlag(quic_log_cert_name_for_empty_sct)) {
+          QUIC_LOG_EVERY_N_SEC(WARNING, 60)
+              << "SCT is expected but it is empty. sni :" << params->sni;
+        } else {
+          // Log SNI and subject name for the leaf cert if its SCT is empty.
+          // This is for debugging b/28342827.
+          const std::vector<quic::QuicString>& certs =
+              signed_config.chain->certs;
+          QuicStringPiece ca_subject;
+          if (!certs.empty()) {
+            QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
+          }
+          QUIC_LOG_EVERY_N_SEC(WARNING, 60)
+              << "SCT is expected but it is empty. sni: '" << params->sni
+              << "' cert subject: '" << ca_subject << "'";
+        }
       } else {
         out->SetStringPiece(kCertificateSCTTag, cert_sct);
       }
@@ -1855,7 +1812,7 @@
   static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
   memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
 
-  if (kexs_tags.size() != protobuf->key_size()) {
+  if (kexs_tags.size() != static_cast<size_t>(protobuf->key_size())) {
     QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size()
                       << " key exchange methods configured, but "
                       << protobuf->key_size() << " private keys";
@@ -1878,7 +1835,7 @@
 
     config->kexs.push_back(tag);
 
-    for (size_t j = 0; j < protobuf->key_size(); j++) {
+    for (int j = 0; j < protobuf->key_size(); j++) {
       const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i);
       if (key.tag() == tag) {
         private_key = key.private_key();
@@ -1911,11 +1868,6 @@
   return config;
 }
 
-void QuicCryptoServerConfig::SetEphemeralKeySource(
-    std::unique_ptr<EphemeralKeySource> ephemeral_key_source) {
-  ephemeral_key_source_ = std::move(ephemeral_key_source);
-}
-
 void QuicCryptoServerConfig::set_replay_protection(bool on) {
   replay_protection_ = on;
 }
@@ -2124,6 +2076,15 @@
   return false;
 }
 
+bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
+  if (GetQuicReloadableFlag(quic_fix_config_rotation)) {
+    return !next_config_promotion_time_.IsZero() &&
+           !next_config_promotion_time_.IsAfter(now);
+  }
+  return !next_config_promotion_time_.IsZero() &&
+         next_config_promotion_time_.IsAfter(now);
+}
+
 QuicCryptoServerConfig::Config::Config()
     : channel_id_enabled(false),
       is_primary(false),
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
index b10786d..3561844 100644
--- a/quic/core/crypto/quic_crypto_server_config.h
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -34,7 +34,6 @@
 namespace quic {
 
 class CryptoHandshakeMessage;
-class EphemeralKeySource;
 class ProofSource;
 class QuicClock;
 class QuicRandom;
@@ -370,12 +369,6 @@
       const CachedNetworkParameters* cached_network_params,
       std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
 
-  // SetEphemeralKeySource installs an object that can cache ephemeral keys for
-  // a short period of time. If not set, ephemeral keys will be generated
-  // per-connection.
-  void SetEphemeralKeySource(
-      std::unique_ptr<EphemeralKeySource> ephemeral_key_source);
-
   // set_replay_protection controls whether replay protection is enabled. If
   // replay protection is disabled then no strike registers are needed and
   // frontends can share an orbit value without a shared strike-register.
@@ -388,6 +381,19 @@
   // valid source-address token.
   void set_chlo_multiplier(size_t multiplier);
 
+  // When sender is allowed to not pad client hello (not standards compliant),
+  // we need to disable the client hello check.
+  void set_validate_chlo_size(bool new_value) {
+    validate_chlo_size_ = new_value;
+  }
+
+  // When QUIC is tunneled through some other mechanism, source token validation
+  // may be disabled. Do not disable it if you are not providing other
+  // protection. (|true| protects against UDP amplification attack.).
+  void set_validate_source_address_token(bool new_value) {
+    validate_source_address_token_ = new_value;
+  }
+
   // set_source_address_token_future_secs sets the number of seconds into the
   // future that source-address tokens will be accepted from. Since
   // source-address tokens are authenticated, this should only happen if
@@ -423,6 +429,12 @@
     pre_shared_key_ = QuicString(psk);
   }
 
+  bool pad_rej() const { return pad_rej_; }
+  void set_pad_rej(bool new_value) { pad_rej_ = new_value; }
+
+  bool pad_shlo() const { return pad_shlo_; }
+  void set_pad_shlo(bool new_value) { pad_shlo_ = new_value; }
+
  private:
   friend class test::QuicCryptoServerConfigPeer;
   friend struct QuicSignedServerConfig;
@@ -539,7 +551,6 @@
       QuicReferenceCountedPointer<Config> primary_config,
       QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof,
       std::unique_ptr<ProofSource::Details> proof_source_details,
-      bool use_get_cert_chain,
       bool get_proof_failed,
       QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
           client_hello_state,
@@ -589,6 +600,7 @@
       const ValidateClientHelloResultCallback::Result& validate_chlo_result,
       QuicConnectionId connection_id,
       const QuicSocketAddress& client_address,
+      ParsedQuicVersion version,
       const ParsedQuicVersionVector& supported_versions,
       const QuicClock* clock,
       QuicRandom* rand,
@@ -754,6 +766,10 @@
       CryptoHandshakeMessage message,
       std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
 
+  // Returns true if the next config promotion should happen now.
+  bool IsNextConfigReady(QuicWallTime now) const
+      SHARED_LOCKS_REQUIRED(configs_lock_);
+
   // replay_protection_ controls whether the server enforces that handshakes
   // aren't replays.
   bool replay_protection_;
@@ -805,10 +821,6 @@
   // ssl_ctx_ contains the server configuration for doing TLS handshakes.
   bssl::UniquePtr<SSL_CTX> ssl_ctx_;
 
-  // ephemeral_key_source_ contains an object that caches ephemeral keys for a
-  // short period of time.
-  std::unique_ptr<EphemeralKeySource> ephemeral_key_source_;
-
   // These fields store configuration values. See the comments for their
   // respective setter functions.
   uint32_t source_address_token_future_secs_;
@@ -823,6 +835,23 @@
   // If non-empty, the server will operate in the pre-shared key mode by
   // incorporating |pre_shared_key_| into the key schedule.
   QuicString pre_shared_key_;
+
+  // Whether REJ message should be padded to max packet size.
+  bool pad_rej_;
+
+  // Whether SHLO message should be padded to max packet size.
+  bool pad_shlo_;
+
+  // If client is allowed to send a small client hello (by disabling padding),
+  // server MUST not check for the client hello size.
+  // DO NOT disable this unless you have some other way of validating client.
+  // (e.g. in realtime scenarios, where quic is tunneled through ICE, ICE will
+  // do its own peer validation using STUN pings with ufrag/upass).
+  bool validate_chlo_size_;
+
+  // When source address is validated by some other means (e.g. when using ICE),
+  // source address token validation may be disabled.
+  bool validate_source_address_token_;
 };
 
 struct QUIC_EXPORT_PRIVATE QuicSignedServerConfig
diff --git a/quic/core/crypto/quic_crypto_server_config_test.cc b/quic/core/crypto/quic_crypto_server_config_test.cc
index 15de28b..81e6951 100644
--- a/quic/core/crypto/quic_crypto_server_config_test.cc
+++ b/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -258,12 +258,12 @@
       NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input);
 
   CachedNetworkParameters cached_network_params_output;
-  EXPECT_NE(cached_network_params_output.DebugString(),
-            cached_network_params_input.DebugString());
+  EXPECT_NE(cached_network_params_output.SerializeAsString(),
+            cached_network_params_input.SerializeAsString());
   ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params, ip4_,
                               &cached_network_params_output);
-  EXPECT_EQ(cached_network_params_output.DebugString(),
-            cached_network_params_input.DebugString());
+  EXPECT_EQ(cached_network_params_output.SerializeAsString(),
+            cached_network_params_input.SerializeAsString());
 }
 
 // Test the ability for a source address token to be valid for multiple
@@ -457,6 +457,33 @@
   test_peer_.CheckConfigs({{"a", false}, {"b", true}});
 }
 
+class ValidateCallback : public ValidateClientHelloResultCallback {
+ public:
+  void Run(QuicReferenceCountedPointer<Result> result,
+           std::unique_ptr<ProofSource::Details> /* details */) override {}
+};
+
+TEST_F(CryptoServerConfigsTest, AdvancePrimaryViaValidate) {
+  SetQuicReloadableFlag(quic_fix_config_rotation, true);
+  // Check that a new primary config is enabled at the right time.
+  SetConfigs({{"a", 900, 1}, {"b", 1100, 1}});
+  test_peer_.SelectNewPrimaryConfig(1000);
+  test_peer_.CheckConfigs({{"a", true}, {"b", false}});
+  CryptoHandshakeMessage client_hello;
+  QuicIpAddress client_ip;
+  QuicSocketAddress server_address;
+  QuicTransportVersion version = QUIC_VERSION_99;
+  MockClock clock;
+  QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config(
+      new QuicSignedServerConfig);
+  std::unique_ptr<ValidateClientHelloResultCallback> done_cb(
+      new ValidateCallback);
+  clock.AdvanceTime(QuicTime::Delta::FromSeconds(1100));
+  config_.ValidateClientHello(client_hello, client_ip, server_address, version,
+                              &clock, signed_config, std::move(done_cb));
+  test_peer_.CheckConfigs({{"a", false}, {"b", true}});
+}
+
 TEST_F(CryptoServerConfigsTest, InvalidConfigs) {
   // Ensure that invalid configs don't change anything.
   SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}});
diff --git a/quic/core/crypto/quic_decrypter.h b/quic/core/crypto/quic_decrypter.h
index f61f621..892504c 100644
--- a/quic/core/crypto/quic_decrypter.h
+++ b/quic/core/crypto/quic_decrypter.h
@@ -54,7 +54,7 @@
   // TODO(wtc): add a way for DecryptPacket to report decryption failure due
   // to non-authentic inputs, as opposed to other reasons for failure.
   virtual bool DecryptPacket(QuicTransportVersion version,
-                             QuicPacketNumber packet_number,
+                             uint64_t packet_number,
                              QuicStringPiece associated_data,
                              QuicStringPiece ciphertext,
                              char* output,
diff --git a/quic/core/crypto/quic_encrypter.h b/quic/core/crypto/quic_encrypter.h
index ea1cee8..591021e 100644
--- a/quic/core/crypto/quic_encrypter.h
+++ b/quic/core/crypto/quic_encrypter.h
@@ -35,7 +35,7 @@
   // |associated_data|. If |output| overlaps with |plaintext| then
   // |plaintext| must be <= |output|.
   virtual bool EncryptPacket(QuicTransportVersion version,
-                             QuicPacketNumber packet_number,
+                             uint64_t packet_number,
                              QuicStringPiece associated_data,
                              QuicStringPiece plaintext,
                              char* output,
diff --git a/quic/core/frames/quic_ack_frame.cc b/quic/core/frames/quic_ack_frame.cc
index 3493f97..5f47b3f 100644
--- a/quic/core/frames/quic_ack_frame.cc
+++ b/quic/core/frames/quic_ack_frame.cc
@@ -12,19 +12,29 @@
 namespace quic {
 
 namespace {
-const QuicPacketNumber kMaxPrintRange = 128;
+
+const QuicPacketCount kMaxPrintRange = 128;
+
+uint64_t PacketNumberIntervalLength(
+    const QuicInterval<QuicPacketNumber>& interval) {
+  if (interval.Empty()) {
+    return 0u;
+  }
+  return interval.max() - interval.min();
+}
 }  // namespace
 
 bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
                       QuicPacketNumber packet_number,
                       QuicPacketNumber peer_least_packet_awaiting_ack) {
-  return packet_number >= peer_least_packet_awaiting_ack &&
+  DCHECK(packet_number.IsInitialized());
+  return (!peer_least_packet_awaiting_ack.IsInitialized() ||
+          packet_number >= peer_least_packet_awaiting_ack) &&
          !ack_frame.packets.Contains(packet_number);
 }
 
 QuicAckFrame::QuicAckFrame()
-    : largest_acked(kInvalidPacketNumber),
-      ack_delay_time(QuicTime::Delta::Infinite()),
+    : ack_delay_time(QuicTime::Delta::Infinite()),
       ecn_counters_populated(false),
       ect_0_count(0),
       ect_1_count(0),
@@ -56,7 +66,7 @@
 }
 
 void QuicAckFrame::Clear() {
-  largest_acked = kInvalidPacketNumber;
+  largest_acked.Clear();
   ack_delay_time = QuicTime::Delta::Infinite();
   received_packet_times.clear();
   packets.Clear();
@@ -73,6 +83,9 @@
     default;
 
 void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
+  if (!packet_number.IsInitialized()) {
+    return;
+  }
   // Check if the deque is empty
   if (packet_number_deque_.empty()) {
     packet_number_deque_.push_front(
@@ -148,7 +161,7 @@
 
 void PacketNumberQueue::AddRange(QuicPacketNumber lower,
                                  QuicPacketNumber higher) {
-  if (lower >= higher) {
+  if (!lower.IsInitialized() || !higher.IsInitialized() || lower >= higher) {
     return;
   }
   if (packet_number_deque_.empty()) {
@@ -187,7 +200,7 @@
 }
 
 bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
-  if (Empty()) {
+  if (!higher.IsInitialized() || Empty()) {
     return false;
   }
   const QuicPacketNumber old_min = Min();
@@ -221,7 +234,7 @@
 }
 
 bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
-  if (packet_number_deque_.empty()) {
+  if (!packet_number.IsInitialized() || packet_number_deque_.empty()) {
     return false;
   }
   if (packet_number_deque_.front().min() > packet_number ||
@@ -253,7 +266,7 @@
 QuicPacketCount PacketNumberQueue::NumPacketsSlow() const {
   QuicPacketCount n_packets = 0;
   for (QuicInterval<QuicPacketNumber> interval : packet_number_deque_) {
-    n_packets += interval.Length();
+    n_packets += PacketNumberIntervalLength(interval);
   }
   return n_packets;
 }
@@ -278,9 +291,9 @@
   return packet_number_deque_.rend();
 }
 
-QuicPacketNumber PacketNumberQueue::LastIntervalLength() const {
+QuicPacketCount PacketNumberQueue::LastIntervalLength() const {
   DCHECK(!Empty());
-  return packet_number_deque_.back().Length();
+  return PacketNumberIntervalLength(packet_number_deque_.back());
 }
 
 // Largest min...max range for packet numbers where we print the numbers
diff --git a/quic/core/frames/quic_ack_frame.h b/quic/core/frames/quic_ack_frame.h
index 29d511e..4dcfc3d 100644
--- a/quic/core/frames/quic_ack_frame.h
+++ b/quic/core/frames/quic_ack_frame.h
@@ -73,7 +73,7 @@
   size_t NumIntervals() const;
 
   // Returns the length of last interval.
-  QuicPacketNumber LastIntervalLength() const;
+  QuicPacketCount LastIntervalLength() const;
 
   // Returns iterators over the packet number intervals.
   const_iterator begin() const;
diff --git a/quic/core/frames/quic_blocked_frame.h b/quic/core/frames/quic_blocked_frame.h
index 3203c67..a4be664 100644
--- a/quic/core/frames/quic_blocked_frame.h
+++ b/quic/core/frames/quic_blocked_frame.h
@@ -37,6 +37,9 @@
   // BLOCKED or STREAM_BLOCKED frame is generated.
   // If stream_id is 0 then a BLOCKED frame is generated and transmitted,
   // if non-0, a STREAM_BLOCKED.
+  // TODO(fkastenholz): This should be converted to use
+  // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+  // and not rely on 0.
   QuicStreamId stream_id;
 
   // For Google QUIC, the offset is ignored.
diff --git a/quic/core/frames/quic_crypto_frame.cc b/quic/core/frames/quic_crypto_frame.cc
index c7f500a..9d602bc 100644
--- a/quic/core/frames/quic_crypto_frame.cc
+++ b/quic/core/frames/quic_crypto_frame.cc
@@ -8,15 +8,27 @@
 
 namespace quic {
 
-QuicCryptoFrame::QuicCryptoFrame() : QuicCryptoFrame(0, nullptr, 0) {}
+QuicCryptoFrame::QuicCryptoFrame()
+    : QuicCryptoFrame(ENCRYPTION_NONE, 0, nullptr, 0) {}
 
-QuicCryptoFrame::QuicCryptoFrame(QuicStreamOffset offset, QuicStringPiece data)
-    : QuicCryptoFrame(offset, data.data(), data.length()) {}
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
+                                 QuicPacketLength data_length)
+    : QuicCryptoFrame(level, offset, nullptr, data_length) {}
 
-QuicCryptoFrame::QuicCryptoFrame(QuicStreamOffset offset,
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
+                                 QuicStringPiece data)
+    : QuicCryptoFrame(level, offset, data.data(), data.length()) {}
+
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
                                  const char* data_buffer,
                                  QuicPacketLength data_length)
-    : data_length(data_length), data_buffer(data_buffer), offset(offset) {}
+    : level(level),
+      data_length(data_length),
+      data_buffer(data_buffer),
+      offset(offset) {}
 
 QuicCryptoFrame::~QuicCryptoFrame() {}
 
diff --git a/quic/core/frames/quic_crypto_frame.h b/quic/core/frames/quic_crypto_frame.h
index bbf8ea0..a3968fe 100644
--- a/quic/core/frames/quic_crypto_frame.h
+++ b/quic/core/frames/quic_crypto_frame.h
@@ -17,20 +17,29 @@
 
 struct QUIC_EXPORT_PRIVATE QuicCryptoFrame {
   QuicCryptoFrame();
-  QuicCryptoFrame(QuicStreamOffset offset, QuicStringPiece data);
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
+                  QuicPacketLength data_length);
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
+                  QuicStringPiece data);
   ~QuicCryptoFrame();
 
   friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                                       const QuicCryptoFrame& s);
 
+  // When writing a crypto frame to a packet, the packet must be encrypted at
+  // |level|. When a crypto frame is read, the encryption level of the packet it
+  // was received in is put in |level|.
+  EncryptionLevel level;
   QuicPacketLength data_length;
   // When reading, |data_buffer| points to the data that was received in the
-  // frame. When writing, |data_buffer| must be a valid pointer for the lifetime
-  // of the frame, which may get serialized some time after creation.
+  // frame. |data_buffer| is not used when writing.
   const char* data_buffer;
   QuicStreamOffset offset;  // Location of this data in the stream.
 
-  QuicCryptoFrame(QuicStreamOffset offset,
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
                   const char* data_buffer,
                   QuicPacketLength data_length);
 };
diff --git a/quic/core/frames/quic_frame.cc b/quic/core/frames/quic_frame.cc
index a951ce6..2e6a303 100644
--- a/quic/core/frames/quic_frame.cc
+++ b/quic/core/frames/quic_frame.cc
@@ -246,15 +246,15 @@
     case PING_FRAME:
       copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id));
       break;
+    case STOP_SENDING_FRAME:
+      copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
+      break;
     case STREAM_ID_BLOCKED_FRAME:
       copy = QuicFrame(QuicStreamIdBlockedFrame(frame.stream_id_blocked_frame));
       break;
     case MAX_STREAM_ID_FRAME:
       copy = QuicFrame(QuicMaxStreamIdFrame(frame.max_stream_id_frame));
       break;
-    case STOP_SENDING_FRAME:
-      copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
-      break;
     default:
       QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame;
       copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
index 725ce83..af9c40b 100644
--- a/quic/core/frames/quic_frames_test.cc
+++ b/quic/core/frames/quic_frames_test.cc
@@ -27,12 +27,13 @@
 
 TEST_F(QuicFramesTest, AckFrameToString) {
   QuicAckFrame frame;
-  frame.largest_acked = 5;
+  frame.largest_acked = QuicPacketNumber(5);
   frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
-  frame.packets.Add(4);
-  frame.packets.Add(5);
+  frame.packets.Add(QuicPacketNumber(4));
+  frame.packets.Add(QuicPacketNumber(5));
   frame.received_packet_times = {
-      {6, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
+      {QuicPacketNumber(6),
+       QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
   std::ostringstream stream;
   stream << frame;
   EXPECT_EQ(
@@ -45,11 +46,12 @@
 
 TEST_F(QuicFramesTest, BigAckFrameToString) {
   QuicAckFrame frame;
-  frame.largest_acked = 500;
+  frame.largest_acked = QuicPacketNumber(500);
   frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
-  frame.packets.AddRange(4, 501);
+  frame.packets.AddRange(QuicPacketNumber(4), QuicPacketNumber(501));
   frame.received_packet_times = {
-      {500, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
+      {QuicPacketNumber(500),
+       QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
   std::ostringstream stream;
   stream << frame;
   EXPECT_EQ(
@@ -213,7 +215,7 @@
 
 TEST_F(QuicFramesTest, StopWaitingFrameToString) {
   QuicStopWaitingFrame frame;
-  frame.least_unacked = 2;
+  frame.least_unacked = QuicPacketNumber(2);
   std::ostringstream stream;
   stream << frame;
   EXPECT_EQ("{ least_unacked: 2 }\n", stream.str());
@@ -223,69 +225,84 @@
 
 TEST_F(QuicFramesTest, IsAwaitingPacket) {
   QuicAckFrame ack_frame1;
-  ack_frame1.largest_acked = 10u;
-  ack_frame1.packets.AddRange(1, 11);
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u));
-  EXPECT_FALSE(IsAwaitingPacket(ack_frame1, 1u, 0u));
+  ack_frame1.largest_acked = QuicPacketNumber(10u);
+  ack_frame1.packets.AddRange(QuicPacketNumber(1), QuicPacketNumber(11));
+  EXPECT_TRUE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(11u), QuicPacketNumber()));
+  EXPECT_FALSE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(1u), QuicPacketNumber()));
 
-  ack_frame1.packets.Add(12);
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u));
+  ack_frame1.packets.Add(QuicPacketNumber(12));
+  EXPECT_TRUE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(11u), QuicPacketNumber()));
 
   QuicAckFrame ack_frame2;
-  ack_frame2.largest_acked = 100u;
-  ack_frame2.packets.AddRange(21, 100);
-  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 11u, 20u));
-  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 80u, 20u));
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
+  ack_frame2.largest_acked = QuicPacketNumber(100u);
+  ack_frame2.packets.AddRange(QuicPacketNumber(21), QuicPacketNumber(100));
+  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(11u),
+                                QuicPacketNumber(20u)));
+  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(80u),
+                                QuicPacketNumber(20u)));
+  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(101u),
+                               QuicPacketNumber(20u)));
 
-  ack_frame2.packets.AddRange(102, 200);
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
+  ack_frame2.packets.AddRange(QuicPacketNumber(102), QuicPacketNumber(200));
+  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(101u),
+                               QuicPacketNumber(20u)));
 }
 
 TEST_F(QuicFramesTest, AddPacket) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.Add(1);
-  ack_frame1.packets.Add(99);
+  ack_frame1.packets.Add(QuicPacketNumber(1));
+  ack_frame1.packets.Add(QuicPacketNumber(99));
 
   EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(1u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(1u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 2));
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(99, 100));
+  expected_intervals.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   EXPECT_EQ(expected_intervals, actual_intervals);
 
-  ack_frame1.packets.Add(20);
+  ack_frame1.packets.Add(QuicPacketNumber(20));
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2;
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(1, 2));
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(20, 21));
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(99, 100));
+  expected_intervals2.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(21)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
 
   EXPECT_EQ(3u, ack_frame1.packets.NumIntervals());
   EXPECT_EQ(expected_intervals2, actual_intervals2);
 
-  ack_frame1.packets.Add(19);
-  ack_frame1.packets.Add(21);
+  ack_frame1.packets.Add(QuicPacketNumber(19));
+  ack_frame1.packets.Add(QuicPacketNumber(21));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals3(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals3;
-  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(1, 2));
-  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(19, 22));
-  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(99, 100));
+  expected_intervals3.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(19), QuicPacketNumber(22)));
+  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
 
   EXPECT_EQ(expected_intervals3, actual_intervals3);
 
-  ack_frame1.packets.Add(20);
+  ack_frame1.packets.Add(QuicPacketNumber(20));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals4(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -293,37 +310,44 @@
   EXPECT_EQ(expected_intervals3, actual_intervals4);
 
   QuicAckFrame ack_frame2;
-  ack_frame2.packets.Add(20);
-  ack_frame2.packets.Add(40);
-  ack_frame2.packets.Add(60);
-  ack_frame2.packets.Add(10);
-  ack_frame2.packets.Add(80);
+  ack_frame2.packets.Add(QuicPacketNumber(20));
+  ack_frame2.packets.Add(QuicPacketNumber(40));
+  ack_frame2.packets.Add(QuicPacketNumber(60));
+  ack_frame2.packets.Add(QuicPacketNumber(10));
+  ack_frame2.packets.Add(QuicPacketNumber(80));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals5(
       ack_frame2.packets.begin(), ack_frame2.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals5;
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(10, 11));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(20, 21));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(40, 41));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(60, 61));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(80, 81));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(10), QuicPacketNumber(11)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(21)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(40), QuicPacketNumber(41)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(60), QuicPacketNumber(61)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(80), QuicPacketNumber(81)));
 
   EXPECT_EQ(expected_intervals5, actual_intervals5);
 }
 
 TEST_F(QuicFramesTest, AddInterval) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.AddRange(1, 10);
-  ack_frame1.packets.AddRange(50, 100);
+  ack_frame1.packets.AddRange(QuicPacketNumber(1), QuicPacketNumber(10));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(100));
 
   EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(1u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(1u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 10));
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(50, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(10)));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(50), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -331,48 +355,58 @@
   EXPECT_EQ(expected_intervals, actual_intervals);
 
   // Ensure adding a range within the existing ranges fails.
-  EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(20, 30), "");
+  EXPECT_QUIC_BUG(
+      ack_frame1.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(30)),
+      "");
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2;
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(1, 10));
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(50, 100));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(10)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(50), QuicPacketNumber(100)));
 
   EXPECT_EQ(expected_intervals2.size(), ack_frame1.packets.NumIntervals());
   EXPECT_EQ(expected_intervals2, actual_intervals2);
 
   // Add ranges at both ends.
   QuicAckFrame ack_frame2;
-  ack_frame2.packets.AddRange(20, 25);
-  ack_frame2.packets.AddRange(40, 45);
-  ack_frame2.packets.AddRange(60, 65);
-  ack_frame2.packets.AddRange(10, 15);
-  ack_frame2.packets.AddRange(80, 85);
+  ack_frame2.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(25));
+  ack_frame2.packets.AddRange(QuicPacketNumber(40), QuicPacketNumber(45));
+  ack_frame2.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(65));
+  ack_frame2.packets.AddRange(QuicPacketNumber(10), QuicPacketNumber(15));
+  ack_frame2.packets.AddRange(QuicPacketNumber(80), QuicPacketNumber(85));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals8(
       ack_frame2.packets.begin(), ack_frame2.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals8;
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(10, 15));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(20, 25));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(40, 45));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(60, 65));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(80, 85));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(10), QuicPacketNumber(15)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(25)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(40), QuicPacketNumber(45)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(60), QuicPacketNumber(65)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(80), QuicPacketNumber(85)));
 
   EXPECT_EQ(expected_intervals8, actual_intervals8);
 }
 
 TEST_F(QuicFramesTest, AddAdjacentForward) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.Add(49);
-  ack_frame1.packets.AddRange(50, 60);
-  ack_frame1.packets.AddRange(60, 70);
-  ack_frame1.packets.AddRange(70, 100);
+  ack_frame1.packets.Add(QuicPacketNumber(49));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(60));
+  ack_frame1.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(70));
+  ack_frame1.packets.AddRange(QuicPacketNumber(70), QuicPacketNumber(100));
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(49, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(49), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -382,13 +416,14 @@
 
 TEST_F(QuicFramesTest, AddAdjacentReverse) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.AddRange(70, 100);
-  ack_frame1.packets.AddRange(60, 70);
-  ack_frame1.packets.AddRange(50, 60);
-  ack_frame1.packets.Add(49);
+  ack_frame1.packets.AddRange(QuicPacketNumber(70), QuicPacketNumber(100));
+  ack_frame1.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(70));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(60));
+  ack_frame1.packets.Add(QuicPacketNumber(49));
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(49, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(49), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -398,19 +433,19 @@
 
 TEST_F(QuicFramesTest, RemoveSmallestInterval) {
   QuicAckFrame ack_frame1;
-  ack_frame1.largest_acked = 100u;
-  ack_frame1.packets.AddRange(51, 60);
-  ack_frame1.packets.AddRange(71, 80);
-  ack_frame1.packets.AddRange(91, 100);
+  ack_frame1.largest_acked = QuicPacketNumber(100u);
+  ack_frame1.packets.AddRange(QuicPacketNumber(51), QuicPacketNumber(60));
+  ack_frame1.packets.AddRange(QuicPacketNumber(71), QuicPacketNumber(80));
+  ack_frame1.packets.AddRange(QuicPacketNumber(91), QuicPacketNumber(100));
   ack_frame1.packets.RemoveSmallestInterval();
   EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(71u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(71u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 
   ack_frame1.packets.RemoveSmallestInterval();
   EXPECT_EQ(1u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(91u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(91u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 }
 
 class PacketNumberQueueTest : public QuicTest {};
@@ -418,85 +453,85 @@
 // Tests that a queue contains the expected data after calls to Add().
 TEST_F(PacketNumberQueueTest, AddRange) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 51);
-  queue.Add(53);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(51));
+  queue.Add(QuicPacketNumber(53));
 
-  EXPECT_FALSE(queue.Contains(0));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
   for (int i = 1; i < 51; ++i) {
-    EXPECT_TRUE(queue.Contains(i));
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
   }
-  EXPECT_FALSE(queue.Contains(51));
-  EXPECT_FALSE(queue.Contains(52));
-  EXPECT_TRUE(queue.Contains(53));
-  EXPECT_FALSE(queue.Contains(54));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(51)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(52)));
+  EXPECT_TRUE(queue.Contains(QuicPacketNumber(53)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(54)));
   EXPECT_EQ(51u, queue.NumPacketsSlow());
-  EXPECT_EQ(1u, queue.Min());
-  EXPECT_EQ(53u, queue.Max());
+  EXPECT_EQ(QuicPacketNumber(1u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(53u), queue.Max());
 
-  queue.Add(70);
-  EXPECT_EQ(70u, queue.Max());
+  queue.Add(QuicPacketNumber(70));
+  EXPECT_EQ(QuicPacketNumber(70u), queue.Max());
 }
 
 // Tests Contains function
 TEST_F(PacketNumberQueueTest, Contains) {
   PacketNumberQueue queue;
-  EXPECT_FALSE(queue.Contains(0));
-  queue.AddRange(5, 10);
-  queue.Add(20);
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
+  queue.AddRange(QuicPacketNumber(5), QuicPacketNumber(10));
+  queue.Add(QuicPacketNumber(20));
 
   for (int i = 1; i < 5; ++i) {
-    EXPECT_FALSE(queue.Contains(i));
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
   }
 
   for (int i = 5; i < 10; ++i) {
-    EXPECT_TRUE(queue.Contains(i));
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
   }
   for (int i = 10; i < 20; ++i) {
-    EXPECT_FALSE(queue.Contains(i));
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
   }
-  EXPECT_TRUE(queue.Contains(20));
-  EXPECT_FALSE(queue.Contains(21));
+  EXPECT_TRUE(queue.Contains(QuicPacketNumber(20)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(21)));
 
   PacketNumberQueue queue2;
-  EXPECT_FALSE(queue2.Contains(1));
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber(1)));
   for (int i = 1; i < 51; ++i) {
-    queue2.Add(2 * i);
+    queue2.Add(QuicPacketNumber(2 * i));
   }
-  EXPECT_FALSE(queue2.Contains(0));
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber()));
   for (int i = 1; i < 51; ++i) {
     if (i % 2 == 0) {
-      EXPECT_TRUE(queue2.Contains(i));
+      EXPECT_TRUE(queue2.Contains(QuicPacketNumber(i)));
     } else {
-      EXPECT_FALSE(queue2.Contains(i));
+      EXPECT_FALSE(queue2.Contains(QuicPacketNumber(i)));
     }
   }
-  EXPECT_FALSE(queue2.Contains(101));
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber(101)));
 }
 
 // Tests that a queue contains the expected data after calls to RemoveUpTo().
 TEST_F(PacketNumberQueueTest, Removal) {
   PacketNumberQueue queue;
-  EXPECT_FALSE(queue.Contains(51));
-  queue.AddRange(0, 100);
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(51)));
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
 
-  EXPECT_TRUE(queue.RemoveUpTo(51));
-  EXPECT_FALSE(queue.RemoveUpTo(51));
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(51)));
+  EXPECT_FALSE(queue.RemoveUpTo(QuicPacketNumber(51)));
 
-  EXPECT_FALSE(queue.Contains(0));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
   for (int i = 1; i < 51; ++i) {
-    EXPECT_FALSE(queue.Contains(i));
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
   }
   for (int i = 51; i < 100; ++i) {
-    EXPECT_TRUE(queue.Contains(i));
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
   }
   EXPECT_EQ(49u, queue.NumPacketsSlow());
-  EXPECT_EQ(51u, queue.Min());
-  EXPECT_EQ(99u, queue.Max());
+  EXPECT_EQ(QuicPacketNumber(51u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), queue.Max());
 
   PacketNumberQueue queue2;
-  queue2.AddRange(0, 5);
-  EXPECT_TRUE(queue2.RemoveUpTo(3));
-  EXPECT_TRUE(queue2.RemoveUpTo(50));
+  queue2.AddRange(QuicPacketNumber(1), QuicPacketNumber(5));
+  EXPECT_TRUE(queue2.RemoveUpTo(QuicPacketNumber(3)));
+  EXPECT_TRUE(queue2.RemoveUpTo(QuicPacketNumber(50)));
   EXPECT_TRUE(queue2.Empty());
 }
 
@@ -506,8 +541,8 @@
   EXPECT_TRUE(queue.Empty());
   EXPECT_EQ(0u, queue.NumPacketsSlow());
 
-  queue.AddRange(1, 100);
-  EXPECT_TRUE(queue.RemoveUpTo(100));
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(100)));
   EXPECT_TRUE(queue.Empty());
   EXPECT_EQ(0u, queue.NumPacketsSlow());
 }
@@ -518,29 +553,30 @@
   PacketNumberQueue queue;
   oss << queue;
 
-  queue.Add(1);
-  queue.AddRange(50, 100);
+  queue.Add(QuicPacketNumber(1));
+  queue.AddRange(QuicPacketNumber(50), QuicPacketNumber(100));
   oss << queue;
 }
 
 // Tests that the iterators returned from a packet queue iterate over the queue.
 TEST_F(PacketNumberQueueTest, Iterators) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 100);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       queue.begin(), queue.end());
 
   PacketNumberQueue queue2;
   for (int i = 1; i < 100; i++) {
-    queue2.AddRange(i, i + 1);
+    queue2.AddRange(QuicPacketNumber(i), QuicPacketNumber(i + 1));
   }
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
       queue2.begin(), queue2.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(100)));
   EXPECT_EQ(expected_intervals, actual_intervals);
   EXPECT_EQ(expected_intervals, actual_intervals2);
   EXPECT_EQ(actual_intervals, actual_intervals2);
@@ -548,10 +584,10 @@
 
 TEST_F(PacketNumberQueueTest, ReversedIterators) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 100);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
   PacketNumberQueue queue2;
   for (int i = 1; i < 100; i++) {
-    queue2.AddRange(i, i + 1);
+    queue2.AddRange(QuicPacketNumber(i), QuicPacketNumber(i + 1));
   }
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       queue.rbegin(), queue.rend());
@@ -559,7 +595,8 @@
       queue2.rbegin(), queue2.rend());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(100)));
 
   EXPECT_EQ(expected_intervals, actual_intervals);
   EXPECT_EQ(expected_intervals, actual_intervals2);
@@ -567,7 +604,7 @@
 
   PacketNumberQueue queue3;
   for (int i = 1; i < 20; i++) {
-    queue3.Add(2 * i);
+    queue3.Add(QuicPacketNumber(2 * i));
   }
 
   auto begin = queue3.begin();
@@ -583,17 +620,17 @@
 
 TEST_F(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 10);
-  queue.AddRange(20, 30);
-  queue.AddRange(40, 50);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(10));
+  queue.AddRange(QuicPacketNumber(20), QuicPacketNumber(30));
+  queue.AddRange(QuicPacketNumber(40), QuicPacketNumber(50));
   EXPECT_EQ(3u, queue.NumIntervals());
   EXPECT_EQ(10u, queue.LastIntervalLength());
 
-  EXPECT_TRUE(queue.RemoveUpTo(25));
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(25)));
   EXPECT_EQ(2u, queue.NumIntervals());
   EXPECT_EQ(10u, queue.LastIntervalLength());
-  EXPECT_EQ(25u, queue.Min());
-  EXPECT_EQ(49u, queue.Max());
+  EXPECT_EQ(QuicPacketNumber(25u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(49u), queue.Max());
 }
 
 }  // namespace
diff --git a/quic/core/frames/quic_stop_waiting_frame.cc b/quic/core/frames/quic_stop_waiting_frame.cc
index 696bed4..0674e8f 100644
--- a/quic/core/frames/quic_stop_waiting_frame.cc
+++ b/quic/core/frames/quic_stop_waiting_frame.cc
@@ -8,7 +8,7 @@
 
 namespace quic {
 
-QuicStopWaitingFrame::QuicStopWaitingFrame() : least_unacked(0) {}
+QuicStopWaitingFrame::QuicStopWaitingFrame() {}
 
 QuicStopWaitingFrame::~QuicStopWaitingFrame() {}
 
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 55c72ff..132da8e 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -22,6 +22,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -62,8 +63,6 @@
 #include "net/third_party/quiche/src/quic/tools/quic_simple_client_stream.h"
 #include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h"
 
-using gfe2::EpollEvent;
-using gfe2::EpollServer;
 using spdy::kV3LowestPriority;
 using spdy::SETTINGS_MAX_HEADER_LIST_SIZE;
 using spdy::SpdyFramer;
@@ -260,7 +259,7 @@
   explicit ClientDelegate(QuicClient* client) : client_(client) {}
   ~ClientDelegate() override = default;
   void OnCanWrite() override {
-    EpollEvent event(EPOLLOUT);
+    QuicEpollEvent event(EPOLLOUT);
     client_->epoll_network_helper()->OnEvent(client_->GetLatestFD(), &event);
   }
 
@@ -278,10 +277,11 @@
         server_hostname_("test.example.com"),
         client_writer_(nullptr),
         server_writer_(nullptr),
-        negotiated_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+        negotiated_version_(UnsupportedQuicVersion()),
         chlo_multiplier_(0),
         stream_factory_(nullptr),
-        support_server_push_(false) {
+        support_server_push_(false),
+        override_connection_id_(nullptr) {
     FLAGS_quic_supports_tls_handshake = true;
     SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, true);
     SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, true);
@@ -330,6 +330,9 @@
     if (!pre_shared_key_client_.empty()) {
       client->client()->SetPreSharedKey(pre_shared_key_client_);
     }
+    if (override_connection_id_ != nullptr) {
+      client->UseConnectionId(*override_connection_id_);
+    }
     client->Connect();
     return client;
   }
@@ -419,14 +422,14 @@
     }
 
     CreateClientWithWriter();
-    static EpollEvent event(EPOLLOUT);
+    static QuicEpollEvent event(EPOLLOUT);
     if (client_writer_ != nullptr) {
       client_writer_->Initialize(
           QuicConnectionPeer::GetHelper(
               client_->client()->client_session()->connection()),
           QuicConnectionPeer::GetAlarmFactory(
               client_->client()->client_session()->connection()),
-          absl::make_unique<ClientDelegate>(client_->client()));
+          QuicMakeUnique<ClientDelegate>(client_->client()));
     }
     initialized_ = true;
     return client_->client()->connected();
@@ -470,7 +473,7 @@
 
     server_writer_->Initialize(QuicDispatcherPeer::GetHelper(dispatcher),
                                QuicDispatcherPeer::GetAlarmFactory(dispatcher),
-                               absl::make_unique<ServerDelegate>(dispatcher));
+                               QuicMakeUnique<ServerDelegate>(dispatcher));
     if (stream_factory_ != nullptr) {
       down_cast<QuicTestServer*>(server_thread_->server())
           ->SetSpdyStreamFactory(stream_factory_);
@@ -632,6 +635,7 @@
   bool support_server_push_;
   QuicString pre_shared_key_client_;
   QuicString pre_shared_key_server_;
+  QuicConnectionId* override_connection_id_;
 };
 
 // Run all end to end tests with all supported versions.
@@ -724,6 +728,28 @@
             client_->client()->GetNumSentClientHellos());
 }
 
+TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) {
+  QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId(
+      GetParam().negotiated_version.transport_version);
+  override_connection_id_ = &connection_id;
+  ASSERT_TRUE(Initialize());
+
+  EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+  EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+  int expected_num_client_hellos = 2;
+  if (ServerSendsVersionNegotiation()) {
+    ++expected_num_client_hellos;
+    if (BothSidesSupportStatelessRejects()) {
+      ++expected_num_client_hellos;
+    }
+  }
+  EXPECT_EQ(expected_num_client_hellos,
+            client_->client()->GetNumSentClientHellos());
+  EXPECT_EQ(client_->client()->client_session()->connection()->connection_id(),
+            QuicUtils::CreateZeroConnectionId(
+                GetParam().negotiated_version.transport_version));
+}
+
 // TODO(dschinazi) remove this test once the flags are deprecated
 TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDServer) {
   SetQuicRestartFlag(quic_variable_length_connection_ids_client, false);
@@ -1870,7 +1896,7 @@
 
   // Register the new FD for epoll events.
   int new_fd = client_->client()->GetLatestFD();
-  EpollServer* eps = client_->epoll_server();
+  QuicEpollServer* eps = client_->epoll_server();
   eps->RegisterFD(new_fd, client_->client()->epoll_network_helper(),
                   EPOLLIN | EPOLLOUT | EPOLLET);
 
@@ -3132,13 +3158,13 @@
   client->UseWriter(client_writer_);
   client->Connect();
   client_.reset(client);
-  static EpollEvent event(EPOLLOUT);
+  static QuicEpollEvent event(EPOLLOUT);
   client_writer_->Initialize(
       QuicConnectionPeer::GetHelper(
           client_->client()->client_session()->connection()),
       QuicConnectionPeer::GetAlarmFactory(
           client_->client()->client_session()->connection()),
-      absl::make_unique<ClientDelegate>(client_->client()));
+      QuicMakeUnique<ClientDelegate>(client_->client()));
   initialized_ = true;
   ASSERT_TRUE(client_->client()->connected());
 
@@ -3695,6 +3721,32 @@
   EXPECT_EQ(kStopSendingTestCode, client_stream->last_stop_sending_code());
 }
 
+TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) {
+  ASSERT_TRUE(Initialize());
+
+  // Send a request without a fin, to keep the stream open
+  SpdyHeaderBlock headers;
+  headers[":method"] = "POST";
+  headers[":path"] = "/foo";
+  headers[":scheme"] = "https";
+  headers[":authority"] = server_hostname_;
+  client_->SendMessage(headers, "", /*fin=*/false);
+  // Stream should be open
+  ASSERT_NE(nullptr, client_->latest_created_stream());
+  EXPECT_FALSE(
+      QuicStreamPeer::write_side_closed(client_->latest_created_stream()));
+  EXPECT_FALSE(
+      QuicStreamPeer::read_side_closed(client_->latest_created_stream()));
+
+  // Send a RST_STREAM+STOP_SENDING on the stream
+  // Code is not important.
+  client_->latest_created_stream()->Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+  client_->WaitForResponse();
+
+  // Stream should be gone.
+  ASSERT_EQ(nullptr, client_->latest_created_stream());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index f1d6de0..345f2cb 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -262,6 +262,24 @@
       }
       return;
     }
+
+    case 0xE: {  // DUPLICATE_PUSH
+      BufferFramePayload(reader);
+      if (remaining_frame_length_ != 0) {
+        return;
+      }
+      QuicDataReader reader(buffer_.data(), current_frame_length_,
+                            NETWORK_BYTE_ORDER);
+      DuplicatePushFrame frame;
+      if (!reader.ReadVarInt62(&frame.push_id)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+        return;
+      }
+      visitor_->OnDuplicatePushFrame(frame);
+      state_ = STATE_READING_FRAME_LENGTH;
+      current_length_field_size_ = 0;
+      return;
+    }
     // Reserved frame types.
     // TODO(rch): Since these are actually the same behavior as the
     // default, we probably don't need to special case them here?
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h
index 730bbe3..a5f41b5 100644
--- a/quic/core/http/http_decoder.h
+++ b/quic/core/http/http_decoder.h
@@ -58,7 +58,10 @@
     // Called when a SETTINGS frame has been successfully parsed.
     virtual void OnSettingsFrame(const SettingsFrame& frame) = 0;
 
-    // Called when a DATA frame has been recevied, |frame_lengths| will be
+    // Called when a DUPLICATE_PUSH frame has been successfully parsed.
+    virtual void OnDuplicatePushFrame(const DuplicatePushFrame& frame) = 0;
+
+    // Called when a DATA frame has been received, |frame_lengths| will be
     // passed to inform header length and payload length of the frame.
     virtual void OnDataFrameStart(Http3FrameLengths frame_length) = 0;
     // Called when the payload of a DATA frame has read. May be called
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index 5261d65..c2b303c 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -23,6 +23,7 @@
   MOCK_METHOD1(OnMaxPushIdFrame, void(const MaxPushIdFrame& frame));
   MOCK_METHOD1(OnGoAwayFrame, void(const GoAwayFrame& frame));
   MOCK_METHOD1(OnSettingsFrame, void(const SettingsFrame& frame));
+  MOCK_METHOD1(OnDuplicatePushFrame, void(const DuplicatePushFrame& frame));
 
   MOCK_METHOD1(OnDataFrameStart, void(Http3FrameLengths frame_lengths));
   MOCK_METHOD1(OnDataFramePayload, void(QuicStringPiece payload));
@@ -134,7 +135,7 @@
   // Process the full frame.
   InSequence s;
   EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("Headers"));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("Headers")));
   EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
   EXPECT_EQ(QUIC_ARRAYSIZE(input),
             decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
@@ -143,13 +144,13 @@
 
   // Process the frame incremently.
   EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("H"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("e"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("a"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("d"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("e"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("r"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("s"));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("H")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("d")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("r")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("s")));
   EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
   for (char c : input) {
     EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
@@ -182,6 +183,29 @@
   EXPECT_EQ("", decoder_.error_detail());
 }
 
+TEST_F(HttpDecoderTest, DuplicatePush) {
+  char input[] = {// length
+                  0x1,
+                  // type (DUPLICATE_PUSH)
+                  0x0E,
+                  // Push Id
+                  0x01};
+  // Process the full frame.
+  EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1})));
+  EXPECT_EQ(QUIC_ARRAYSIZE(input),
+            decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
+  EXPECT_EQ("", decoder_.error_detail());
+
+  // Process the frame incremently.
+  EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1})));
+  for (char c : input) {
+    EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
+  }
+  EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
+  EXPECT_EQ("", decoder_.error_detail());
+}
+
 TEST_F(HttpDecoderTest, PriorityFrame) {
   char input[] = {// length
                   0x4,
@@ -273,7 +297,7 @@
   // Process the full frame.
   InSequence s;
   EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)));
-  EXPECT_CALL(visitor_, OnDataFramePayload("Data!"));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("Data!")));
   EXPECT_CALL(visitor_, OnDataFrameEnd());
   EXPECT_EQ(QUIC_ARRAYSIZE(input),
             decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
@@ -282,11 +306,11 @@
 
   // Process the frame incremently.
   EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)));
-  EXPECT_CALL(visitor_, OnDataFramePayload("D"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("a"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("t"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("a"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("!"));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("D")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("t")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("!")));
   EXPECT_CALL(visitor_, OnDataFrameEnd());
   for (char c : input) {
     EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
@@ -358,7 +382,7 @@
   // Process the full frame.
   InSequence s;
   EXPECT_CALL(visitor_, OnHeadersFrameStart());
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("Headers"));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("Headers")));
   EXPECT_CALL(visitor_, OnHeadersFrameEnd());
   EXPECT_EQ(QUIC_ARRAYSIZE(input),
             decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
@@ -367,13 +391,13 @@
 
   // Process the frame incremently.
   EXPECT_CALL(visitor_, OnHeadersFrameStart());
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("H"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("e"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("a"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("d"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("e"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("r"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("s"));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("H")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("d")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("r")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("s")));
   EXPECT_CALL(visitor_, OnHeadersFrameEnd());
   for (char c : input) {
     EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
diff --git a/quic/core/http/http_encoder.cc b/quic/core/http/http_encoder.cc
index 6e2487b..7c07838 100644
--- a/quic/core/http/http_encoder.cc
+++ b/quic/core/http/http_encoder.cc
@@ -59,33 +59,32 @@
 HttpEncoder::~HttpEncoder() {}
 
 QuicByteCount HttpEncoder::SerializeDataFrameHeader(
-    QuicByteCount length,
+    QuicByteCount payload_length,
     std::unique_ptr<char[]>* output) {
-  DCHECK_NE(0u, length);
+  DCHECK_NE(0u, payload_length);
   QuicByteCount header_length =
-      QuicDataWriter::GetVarInt62Len(length) + kFrameTypeLength;
+      QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength;
 
   output->reset(new char[header_length]);
   QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER);
 
-  if (WriteFrameHeader(length, HttpFrameType::DATA, &writer)) {
+  if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) {
     return header_length;
   }
   return 0;
 }
 
 QuicByteCount HttpEncoder::SerializeHeadersFrameHeader(
-    const HeadersFrame& headers,
+    QuicByteCount payload_length,
     std::unique_ptr<char[]>* output) {
+  DCHECK_NE(0u, payload_length);
   QuicByteCount header_length =
-      QuicDataWriter::GetVarInt62Len(headers.headers.length()) +
-      kFrameTypeLength;
+      QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength;
 
   output->reset(new char[header_length]);
   QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER);
 
-  if (WriteFrameHeader(headers.headers.length(), HttpFrameType::HEADERS,
-                       &writer)) {
+  if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) {
     return header_length;
   }
   return 0;
@@ -225,6 +224,24 @@
   return 0;
 }
 
+QuicByteCount HttpEncoder::SerializeDuplicatePushFrame(
+    const DuplicatePushFrame& duplicate_push,
+    std::unique_ptr<char[]>* output) {
+  QuicByteCount payload_length =
+      QuicDataWriter::GetVarInt62Len(duplicate_push.push_id);
+  QuicByteCount total_length = GetTotalLength(payload_length);
+
+  output->reset(new char[total_length]);
+  QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (WriteFrameHeader(payload_length, HttpFrameType::DUPLICATE_PUSH,
+                       &writer) &&
+      writer.WriteVarInt62(duplicate_push.push_id)) {
+    return total_length;
+  }
+  return 0;
+}
+
 bool HttpEncoder::WriteFrameHeader(QuicByteCount length,
                                    HttpFrameType type,
                                    QuicDataWriter* writer) {
diff --git a/quic/core/http/http_encoder.h b/quic/core/http/http_encoder.h
index 79b76e9..f04e6e4 100644
--- a/quic/core/http/http_encoder.h
+++ b/quic/core/http/http_encoder.h
@@ -24,14 +24,14 @@
 
   ~HttpEncoder();
 
-  // Serializes the header of a DATA frame into a new buffer stored in |output|.
+  // Serializes a DATA frame header into a new buffer stored in |output|.
   // Returns the length of the buffer on success, or 0 otherwise.
-  QuicByteCount SerializeDataFrameHeader(QuicByteCount length,
+  QuicByteCount SerializeDataFrameHeader(QuicByteCount payload_length,
                                          std::unique_ptr<char[]>* output);
 
-  // Serializes the header of a HEADERS frame into a new buffer stored in
-  // |output|. Returns the length of the buffer on success, or 0 otherwise.
-  QuicByteCount SerializeHeadersFrameHeader(const HeadersFrame& headers,
+  // Serializes a HEADERS frame header into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeHeadersFrameHeader(QuicByteCount payload_length,
                                             std::unique_ptr<char[]>* output);
 
   // Serializes a PRIORITY frame into a new buffer stored in |output|.
@@ -66,6 +66,12 @@
   QuicByteCount SerializeMaxPushIdFrame(const MaxPushIdFrame& max_push_id,
                                         std::unique_ptr<char[]>* output);
 
+  // Serialize a DUPLICATE_PUSH frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeDuplicatePushFrame(
+      const DuplicatePushFrame& duplicate_push,
+      std::unique_ptr<char[]>* output);
+
  private:
   bool WriteFrameHeader(QuicByteCount length,
                         HttpFrameType type,
diff --git a/quic/core/http/http_encoder_test.cc b/quic/core/http/http_encoder_test.cc
index 70cfd6a..a484aed 100644
--- a/quic/core/http/http_encoder_test.cc
+++ b/quic/core/http/http_encoder_test.cc
@@ -18,11 +18,9 @@
 };
 
 TEST_F(HttpEncoderTest, SerializeDataFrameHeader) {
-  DataFrame data;
-  data.data = "Data!";
   std::unique_ptr<char[]> buffer;
   uint64_t length =
-      encoder_.SerializeDataFrameHeader(data.data.length(), &buffer);
+      encoder_.SerializeDataFrameHeader(/* payload_length = */ 5, &buffer);
   char output[] = {// length
                    0x05,
                    // type (DATA)
@@ -33,10 +31,9 @@
 }
 
 TEST_F(HttpEncoderTest, SerializeHeadersFrameHeader) {
-  HeadersFrame headers;
-  headers.headers = "Headers";
   std::unique_ptr<char[]> buffer;
-  uint64_t length = encoder_.SerializeHeadersFrameHeader(headers, &buffer);
+  uint64_t length =
+      encoder_.SerializeHeadersFrameHeader(/* payload_length = */ 7, &buffer);
   char output[] = {// length
                    0x07,
                    // type (HEADERS)
@@ -167,5 +164,22 @@
                                 QUIC_ARRAYSIZE(output));
 }
 
+TEST_F(HttpEncoderTest, SerializeDuplicatePushFrame) {
+  DuplicatePushFrame duplicate_push;
+  duplicate_push.push_id = 0x1;
+  char output[] = {// length
+                   0x1,
+                   // type (DUPLICATE_PUSH)
+                   0x0E,
+                   // Push Id
+                   0x01};
+  std::unique_ptr<char[]> buffer;
+  uint64_t length =
+      encoder_.SerializeDuplicatePushFrame(duplicate_push, &buffer);
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("DUPLICATE_PUSH", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/http/http_frames.h b/quic/core/http/http_frames.h
index 6b6aa41..ea11557 100644
--- a/quic/core/http/http_frames.h
+++ b/quic/core/http/http_frames.h
@@ -21,10 +21,11 @@
   SETTINGS = 0x4,
   PUSH_PROMISE = 0x5,
   GOAWAY = 0x7,
-  MAX_PUSH_ID = 0xD
+  MAX_PUSH_ID = 0xD,
+  DUPLICATE_PUSH = 0xE
 };
 
-// 4.2.2.  DATA
+// 4.2.1.  DATA
 //
 //   DATA frames (type=0x0) convey arbitrary, variable-length sequences of
 //   octets associated with an HTTP request or response payload.
@@ -32,7 +33,7 @@
   QuicStringPiece data;
 };
 
-// 4.2.3.  HEADERS
+// 4.2.2.  HEADERS
 //
 //   The HEADERS frame (type=0x1) is used to carry a header block,
 //   compressed using QPACK.
@@ -40,7 +41,7 @@
   QuicStringPiece headers;
 };
 
-// 4.2.4.  PRIORITY
+// 4.2.3.  PRIORITY
 //
 //   The PRIORITY (type=0x02) frame specifies the sender-advised priority
 //   of a stream
@@ -69,7 +70,7 @@
   }
 };
 
-// 4.2.5.  CANCEL_PUSH
+// 4.2.4.  CANCEL_PUSH
 //
 //   The CANCEL_PUSH frame (type=0x3) is used to request cancellation of
 //   server push prior to the push stream being created.
@@ -83,7 +84,7 @@
   }
 };
 
-// 4.2.6.  SETTINGS
+// 4.2.5.  SETTINGS
 //
 //   The SETTINGS frame (type=0x4) conveys configuration parameters that
 //   affect how endpoints communicate, such as preferences and constraints
@@ -100,7 +101,7 @@
   }
 };
 
-// 4.2.7.  PUSH_PROMISE
+// 4.2.6.  PUSH_PROMISE
 //
 //   The PUSH_PROMISE frame (type=0x05) is used to carry a request header
 //   set from server to client, as in HTTP/2.
@@ -113,7 +114,7 @@
   }
 };
 
-// 4.2.8.  GOAWAY
+// 4.2.7.  GOAWAY
 //
 //   The GOAWAY frame (type=0x7) is used to initiate graceful shutdown of
 //   a connection by a server.
@@ -125,7 +126,7 @@
   }
 };
 
-// 4.2.9.  MAX_PUSH_ID
+// 4.2.8.  MAX_PUSH_ID
 //
 //   The MAX_PUSH_ID frame (type=0xD) is used by clients to control the
 //   number of server pushes that the server can initiate.
@@ -137,6 +138,19 @@
   }
 };
 
+// 4.2.9.  DUPLICATE_PUSH
+//
+//  The DUPLICATE_PUSH frame (type=0xE) is used by servers to indicate
+//  that an existing pushed resource is related to multiple client
+//  requests.
+struct DuplicatePushFrame {
+  PushId push_id;
+
+  bool operator==(const DuplicatePushFrame& rhs) const {
+    return push_id == rhs.push_id;
+  }
+};
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_HTTP_HTTP_FRAMES_H_
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc
index 47e3a27..40b43dc 100644
--- a/quic/core/http/quic_server_session_base.cc
+++ b/quic/core/http/quic_server_session_base.cc
@@ -30,8 +30,7 @@
       helper_(helper),
       bandwidth_resumption_enabled_(false),
       bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
-      last_scup_time_(QuicTime::Zero()),
-      last_scup_packet_number_(0) {}
+      last_scup_time_(QuicTime::Zero()) {}
 
 QuicServerSessionBase::~QuicServerSessionBase() {}
 
@@ -112,9 +111,15 @@
   int64_t srtt_ms =
       sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds();
   int64_t now_ms = (now - last_scup_time_).ToMilliseconds();
-  int64_t packets_since_last_scup =
-      connection()->sent_packet_manager().GetLargestSentPacket() -
-      last_scup_packet_number_;
+  int64_t packets_since_last_scup = 0;
+  const QuicPacketNumber largest_sent_packet =
+      connection()->sent_packet_manager().GetLargestSentPacket();
+  if (largest_sent_packet.IsInitialized()) {
+    packets_since_last_scup =
+        last_scup_packet_number_.IsInitialized()
+            ? largest_sent_packet - last_scup_packet_number_
+            : largest_sent_packet.ToUint64();
+  }
   if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
       now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
       packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
diff --git a/quic/core/http/quic_server_session_base.h b/quic/core/http/quic_server_session_base.h
index 7495253..55a8d60 100644
--- a/quic/core/http/quic_server_session_base.h
+++ b/quic/core/http/quic_server_session_base.h
@@ -126,7 +126,7 @@
   QuicTime last_scup_time_;
 
   // Number of packets sent to the peer, at the time we last sent a SCUP.
-  int64_t last_scup_packet_number_;
+  QuicPacketNumber last_scup_packet_number_;
 
   // Converts QuicBandwidth to an int32 bytes/second that can be
   // stored in CachedNetworkParameters.  TODO(jokulik): This function
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc
index 6a8fb37..9f36e37 100644
--- a/quic/core/http/quic_server_session_base_test.cc
+++ b/quic/core/http/quic_server_session_base_test.cc
@@ -170,6 +170,28 @@
     return connection_->transport_version();
   }
 
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close. This method can be used to inject a STOP_SENDING, which
+  // would cause a close in the opposite direction. This allows tests to do the
+  // extra work to get a two-way (full) close where desired. Also sets up
+  // expects needed to ensure that the STOP_SENDING worked as expected.
+  void InjectStopSendingFrame(QuicStreamId stream_id,
+                              QuicRstStreamErrorCode rst_stream_code) {
+    if (transport_version() != QUIC_VERSION_99) {
+      // Only needed for version 99/IETF QUIC. Noop otherwise.
+      return;
+    }
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_id,
+        static_cast<QuicApplicationErrorCode>(rst_stream_code));
+    EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
+    session_->OnStopSendingFrame(stop_sending);
+  }
+
   StrictMock<MockQuicSessionVisitor> owner_;
   StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
   MockQuicConnectionHelper helper_;
@@ -221,6 +243,12 @@
               OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst1);
+
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send the same two bytes of payload in a new packet.
@@ -242,6 +270,12 @@
               OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst1);
+
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send two bytes of payload.
@@ -275,6 +309,11 @@
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst);
 
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   // If we were tracking, we'd probably want to reject this because it's data
   // past the reset point of stream 3.  As it's a closed stream we just drop the
   // data on the floor, but accept the packet because it has data for stream 5.
@@ -499,10 +538,11 @@
 
   // Bandwidth estimate has now changed sufficiently, enough time has passed,
   // and enough packets have been sent.
-  SerializedPacket packet(1 + kMinPacketsBetweenServerConfigUpdates,
-                          PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false,
-                          false);
-  sent_packet_manager->OnPacketSent(&packet, 0, now, NOT_RETRANSMISSION,
+  SerializedPacket packet(
+      QuicPacketNumber(1) + kMinPacketsBetweenServerConfigUpdates,
+      PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false, false);
+  sent_packet_manager->OnPacketSent(&packet, QuicPacketNumber(), now,
+                                    NOT_RETRANSMISSION,
                                     HAS_RETRANSMITTABLE_DATA);
 
   // Verify that the proto has exactly the values we expect.
@@ -655,7 +695,7 @@
 
   EXPECT_CALL(stream_helper_, CanAcceptClientHello(_, _, _, _, _))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(stream_helper_, GenerateConnectionIdForReject(_))
+  EXPECT_CALL(stream_helper_, GenerateConnectionIdForReject(_, _))
       .WillOnce(testing::Return(TestConnectionId(12345)));
 
   // Set the current packet
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index 579870a..a9d6c62 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -454,7 +454,7 @@
   QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false);
   // Close connection shouldn't be called.
   EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
-  if (connection_->transport_version() == QUIC_VERSION_99) {
+  if (connection_->transport_version() > QUIC_VERSION_46) {
     // Illegal fixed bit value.
     EXPECT_CALL(*connection_, OnError(_)).Times(1);
   }
diff --git a/quic/core/http/quic_spdy_server_stream_base_test.cc b/quic/core/http/quic_spdy_server_stream_base_test.cc
index ab13943..51abf0c 100644
--- a/quic/core/http/quic_spdy_server_stream_base_test.cc
+++ b/quic/core/http/quic_spdy_server_stream_base_test.cc
@@ -62,6 +62,14 @@
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
                                QUIC_STREAM_CANCELLED, 1234);
   stream_->OnStreamReset(rst_frame);
+  if (session_.connection()->transport_version() == QUIC_VERSION_99) {
+    // Create and inject a STOP SENDING frame to complete the close
+    // of the stream. This is only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_->id(),
+        static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+    session_.OnStopSendingFrame(stop_sending);
+  }
 
   EXPECT_TRUE(stream_->reading_stopped());
   EXPECT_TRUE(stream_->write_side_closed());
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 00fb10f..affa07a 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -1001,6 +1001,23 @@
                           GetNthClientInitiatedBidirectionalId(0),
                           QUIC_ERROR_PROCESSING_STREAM, 0);
   session_.OnRstStream(rst1);
+
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close.
+  if (transport_version() == QUIC_VERSION_99) {
+    // Only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0),
+        static_cast<QuicApplicationErrorCode>(QUIC_ERROR_PROCESSING_STREAM));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_ERROR_PROCESSING_STREAM));
+    session_.OnStopSendingFrame(stop_sending);
+  }
+
   EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
   // Connection should remain alive.
   EXPECT_TRUE(connection_->connected());
@@ -1219,15 +1236,31 @@
         .Times(2)
         .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
   } else {
-    // V99 has an additional, STOP_SENDING, frame.
+    // V99 has an additional, STOP_SENDING, frame and an additional RST_STREAM
+    // (the response to the STOP_SENDING) frame.
     EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(3)
+        .Times(4)
         .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
   }
   EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(),
                                QUIC_STREAM_CANCELLED, kByteOffset);
   session_.OnRstStream(rst_frame);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close.
+  if (transport_version() == QUIC_VERSION_99) {
+    // Only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream->id(),
+        static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_,
+                OnStreamReset(stream->id(), QUIC_STREAM_CANCELLED));
+    session_.OnStopSendingFrame(stop_sending);
+  }
+
   EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
 }
 
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc
index 9a5d024..eb8135a 100644
--- a/quic/core/http/quic_spdy_stream.cc
+++ b/quic/core/http/quic_spdy_stream.cc
@@ -59,6 +59,10 @@
     CloseConnectionOnWrongFrame("Settings");
   }
 
+  void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override {
+    CloseConnectionOnWrongFrame("Duplicate Push");
+  }
+
   void OnDataFrameStart(Http3FrameLengths frame_lengths) override {
     stream_->OnDataFrameStart(frame_lengths);
   }
@@ -176,19 +180,23 @@
     QuicStringPiece data,
     bool fin,
     QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
-  if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99 &&
-      data.length() > 0) {
-    std::unique_ptr<char[]> buffer;
-    QuicByteCount header_length =
-        encoder_.SerializeDataFrameHeader(data.length(), &buffer);
-    WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false,
-                      nullptr);
-    QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length "
-                    << header_length;
-    total_header_bytes_written_ += header_length;
+  if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99 ||
+      data.length() == 0) {
+    WriteOrBufferData(data, fin, std::move(ack_listener));
+    return;
   }
+  QuicConnection::ScopedPacketFlusher flusher(
+      spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
+  std::unique_ptr<char[]> buffer;
+  QuicByteCount header_length =
+      encoder_.SerializeDataFrameHeader(data.length(), &buffer);
+  WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false,
+                    nullptr);
+  QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length "
+                  << header_length;
+  total_header_bytes_written_ += header_length;
   WriteOrBufferData(data, fin, std::move(ack_listener));
-  QUIC_DLOG(INFO) << "Stream" << id() << " is writing body of length "
+  QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length "
                   << data.length();
 }
 
@@ -254,6 +262,8 @@
     return {0, false};
   }
 
+  QuicConnection::ScopedPacketFlusher flusher(
+      spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
   struct iovec header_iov = {static_cast<void*>(buffer.get()), header_length};
   QuicMemSliceStorage storage(
       &header_iov, 1,
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.h b/quic/core/http/quic_spdy_stream_body_buffer.h
index acd4985..2485aac 100644
--- a/quic/core/http/quic_spdy_stream_body_buffer.h
+++ b/quic/core/http/quic_spdy_stream_body_buffer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H
-#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H
+#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
+#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
 
 #include "net/third_party/quiche/src/quic/core/http/http_decoder.h"
 #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h"
@@ -72,4 +72,4 @@
 
 }  // namespace quic
 
-#endif  // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H
+#endif  // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
diff --git a/quic/core/http/spdy_utils_test.cc b/quic/core/http/spdy_utils_test.cc
index b8edf49..6cd2f1d 100644
--- a/quic/core/http/spdy_utils_test.cc
+++ b/quic/core/http/spdy_utils_test.cc
@@ -327,6 +327,24 @@
   EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
 }
 
+TEST_F(GetPromisedUrlFromHeaders, InvalidUserinfo) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  headers[":authority"] = "user@www.google.com";
+  headers[":scheme"] = "https";
+  headers[":path"] = "/";
+  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
+}
+
+TEST_F(GetPromisedUrlFromHeaders, InvalidPath) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  headers[":authority"] = "www.google.com";
+  headers[":scheme"] = "https";
+  headers[":path"] = "";
+  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
+}
+
 using GetPromisedHostNameFromHeaders = QuicTest;
 
 TEST_F(GetPromisedHostNameFromHeaders, NormalUsage) {
diff --git a/quic/core/legacy_quic_stream_id_manager.cc b/quic/core/legacy_quic_stream_id_manager.cc
index 000d0cb..6fb662a 100644
--- a/quic/core/legacy_quic_stream_id_manager.cc
+++ b/quic/core/legacy_quic_stream_id_manager.cc
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 #include "net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h"
 
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
diff --git a/quic/core/legacy_quic_stream_id_manager.h b/quic/core/legacy_quic_stream_id_manager.h
index 79a4d47..78d4545 100644
--- a/quic/core/legacy_quic_stream_id_manager.h
+++ b/quic/core/legacy_quic_stream_id_manager.h
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 #ifndef QUICHE_QUIC_CORE_LEGACY_QUIC_STREAM_ID_MANAGER_H_
 #define QUICHE_QUIC_CORE_LEGACY_QUIC_STREAM_ID_MANAGER_H_
 
diff --git a/quic/core/legacy_quic_stream_id_manager_test.cc b/quic/core/legacy_quic_stream_id_manager_test.cc
index 643ff5b..823cdc0 100644
--- a/quic/core/legacy_quic_stream_id_manager_test.cc
+++ b/quic/core/legacy_quic_stream_id_manager_test.cc
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 #include "net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
diff --git a/quic/core/packet_number_indexed_queue.h b/quic/core/packet_number_indexed_queue.h
index 97d93de..ab2e20b 100644
--- a/quic/core/packet_number_indexed_queue.h
+++ b/quic/core/packet_number_indexed_queue.h
@@ -5,8 +5,9 @@
 #ifndef QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
 #define QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
 
-#include "base/logging.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
 
 namespace quic {
@@ -35,8 +36,7 @@
 template <typename T>
 class PacketNumberIndexedQueue {
  public:
-  PacketNumberIndexedQueue()
-      : number_of_present_entries_(0), first_packet_(0) {}
+  PacketNumberIndexedQueue() : number_of_present_entries_(0) {}
 
   // Retrieve the entry associated with the packet number.  Returns the pointer
   // to the entry in case of success, or nullptr if the entry does not exist.
@@ -65,15 +65,15 @@
   // proportional to the memory usage of the queue.
   size_t entry_slots_used() const { return entries_.size(); }
 
-  // Packet number of the first entry in the queue.  Zero if the queue is empty.
-  size_t first_packet() const { return first_packet_; }
+  // Packet number of the first entry in the queue.
+  QuicPacketNumber first_packet() const { return first_packet_; }
 
   // Packet number of the last entry ever inserted in the queue.  Note that the
   // entry in question may have already been removed.  Zero if the queue is
   // empty.
-  size_t last_packet() const {
+  QuicPacketNumber last_packet() const {
     if (IsEmpty()) {
-      return 0;
+      return QuicPacketNumber();
     }
     return first_packet_ + entries_.size() - 1;
   }
@@ -127,9 +127,14 @@
 template <typename... Args>
 bool PacketNumberIndexedQueue<T>::Emplace(QuicPacketNumber packet_number,
                                           Args&&... args) {
+  if (!packet_number.IsInitialized()) {
+    QUIC_BUG << "Try to insert an uninitialized packet number";
+    return false;
+  }
+
   if (IsEmpty()) {
     DCHECK(entries_.empty());
-    DCHECK_EQ(0u, first_packet_);
+    DCHECK(!first_packet_.IsInitialized());
 
     entries_.emplace_back(std::forward<Args>(args)...);
     number_of_present_entries_ = 1;
@@ -176,18 +181,19 @@
     first_packet_++;
   }
   if (entries_.empty()) {
-    first_packet_ = 0;
+    first_packet_.Clear();
   }
 }
 
 template <typename T>
-auto PacketNumberIndexedQueue<T>::GetEntryWrapper(QuicPacketNumber offset) const
-    -> const EntryWrapper* {
-  if (offset < first_packet_) {
+auto PacketNumberIndexedQueue<T>::GetEntryWrapper(
+    QuicPacketNumber packet_number) const -> const EntryWrapper* {
+  if (!packet_number.IsInitialized() || IsEmpty() ||
+      packet_number < first_packet_) {
     return nullptr;
   }
 
-  offset -= first_packet_;
+  uint64_t offset = packet_number - first_packet_;
   if (offset >= entries_.size()) {
     return nullptr;
   }
diff --git a/quic/core/packet_number_indexed_queue_test.cc b/quic/core/packet_number_indexed_queue_test.cc
index 0190df2..294d2a4 100644
--- a/quic/core/packet_number_indexed_queue_test.cc
+++ b/quic/core/packet_number_indexed_queue_test.cc
@@ -23,156 +23,156 @@
 
 TEST_F(PacketNumberIndexedQueueTest, InitialState) {
   EXPECT_TRUE(queue_.IsEmpty());
-  EXPECT_EQ(0u, queue_.first_packet());
-  EXPECT_EQ(0u, queue_.last_packet());
+  EXPECT_FALSE(queue_.first_packet().IsInitialized());
+  EXPECT_FALSE(queue_.last_packet().IsInitialized());
   EXPECT_EQ(0u, queue_.number_of_present_entries());
   EXPECT_EQ(0u, queue_.entry_slots_used());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingContinuousElements) {
-  ASSERT_TRUE(queue_.Emplace(1001, "one"));
-  EXPECT_EQ("one", *queue_.GetEntry(1001));
+  ASSERT_TRUE(queue_.Emplace(QuicPacketNumber(1001), "one"));
+  EXPECT_EQ("one", *queue_.GetEntry(QuicPacketNumber(1001)));
 
-  ASSERT_TRUE(queue_.Emplace(1002, "two"));
-  EXPECT_EQ("two", *queue_.GetEntry(1002));
+  ASSERT_TRUE(queue_.Emplace(QuicPacketNumber(1002), "two"));
+  EXPECT_EQ("two", *queue_.GetEntry(QuicPacketNumber(1002)));
 
   EXPECT_FALSE(queue_.IsEmpty());
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(1002u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1002u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(2u, queue_.entry_slots_used());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingOutOfOrder) {
-  queue_.Emplace(1001, "one");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
 
-  ASSERT_TRUE(queue_.Emplace(1003, "three"));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1002));
-  EXPECT_EQ("three", *queue_.GetEntry(1003));
+  ASSERT_TRUE(queue_.Emplace(QuicPacketNumber(1003), "three"));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1002)));
+  EXPECT_EQ("three", *queue_.GetEntry(QuicPacketNumber(1003)));
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1003u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(3u, queue_.entry_slots_used());
 
-  ASSERT_FALSE(queue_.Emplace(1002, "two"));
+  ASSERT_FALSE(queue_.Emplace(QuicPacketNumber(1002), "two"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingIntoPast) {
-  queue_.Emplace(1001, "one");
-  EXPECT_FALSE(queue_.Emplace(1000, "zero"));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  EXPECT_FALSE(queue_.Emplace(QuicPacketNumber(1000), "zero"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingDuplicate) {
-  queue_.Emplace(1001, "one");
-  EXPECT_FALSE(queue_.Emplace(1001, "one"));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  EXPECT_FALSE(queue_.Emplace(QuicPacketNumber(1001), "one"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveInTheMiddle) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(1002, "two");
-  queue_.Emplace(1003, "three");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(1002), "two");
+  queue_.Emplace(QuicPacketNumber(1003), "three");
 
-  ASSERT_TRUE(queue_.Remove(1002));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1002));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1002)));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1002)));
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1003u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(3u, queue_.entry_slots_used());
 
-  EXPECT_FALSE(queue_.Emplace(1002, "two"));
-  EXPECT_TRUE(queue_.Emplace(1004, "four"));
+  EXPECT_FALSE(queue_.Emplace(QuicPacketNumber(1002), "two"));
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(1004), "four"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveAtImmediateEdges) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(1002, "two");
-  queue_.Emplace(1003, "three");
-  ASSERT_TRUE(queue_.Remove(1001));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1001));
-  ASSERT_TRUE(queue_.Remove(1003));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1003));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(1002), "two");
+  queue_.Emplace(QuicPacketNumber(1003), "three");
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1001)));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1003)));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1003)));
 
-  EXPECT_EQ(1002u, queue_.first_packet());
-  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1002u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1003u), queue_.last_packet());
   EXPECT_EQ(1u, queue_.number_of_present_entries());
   EXPECT_EQ(2u, queue_.entry_slots_used());
 
-  EXPECT_TRUE(queue_.Emplace(1004, "four"));
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(1004), "four"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveAtDistantFront) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(1002, "one (kinda)");
-  queue_.Emplace(2001, "two");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(1002), "one (kinda)");
+  queue_.Emplace(QuicPacketNumber(2001), "two");
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
   EXPECT_EQ(3u, queue_.number_of_present_entries());
   EXPECT_EQ(1001u, queue_.entry_slots_used());
 
-  ASSERT_TRUE(queue_.Remove(1002));
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1002)));
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(1001u, queue_.entry_slots_used());
 
-  ASSERT_TRUE(queue_.Remove(1001));
-  EXPECT_EQ(2001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
   EXPECT_EQ(1u, queue_.number_of_present_entries());
   EXPECT_EQ(1u, queue_.entry_slots_used());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveAtDistantBack) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(2001, "two");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(2001), "two");
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
 
-  ASSERT_TRUE(queue_.Remove(2001));
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(2001)));
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, ClearAndRepopulate) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(2001, "two");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(2001), "two");
 
-  ASSERT_TRUE(queue_.Remove(1001));
-  ASSERT_TRUE(queue_.Remove(2001));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(2001)));
   EXPECT_TRUE(queue_.IsEmpty());
-  EXPECT_EQ(0u, queue_.first_packet());
-  EXPECT_EQ(0u, queue_.last_packet());
+  EXPECT_FALSE(queue_.first_packet().IsInitialized());
+  EXPECT_FALSE(queue_.last_packet().IsInitialized());
 
-  EXPECT_TRUE(queue_.Emplace(101, "one"));
-  EXPECT_TRUE(queue_.Emplace(201, "two"));
-  EXPECT_EQ(101u, queue_.first_packet());
-  EXPECT_EQ(201u, queue_.last_packet());
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(101), "one"));
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(201), "two"));
+  EXPECT_EQ(QuicPacketNumber(101u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(201u), queue_.last_packet());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, FailToRemoveElementsThatNeverExisted) {
-  ASSERT_FALSE(queue_.Remove(1000));
-  queue_.Emplace(1001, "one");
-  ASSERT_FALSE(queue_.Remove(1000));
-  ASSERT_FALSE(queue_.Remove(1002));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1000)));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1000)));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1002)));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, FailToRemoveElementsTwice) {
-  queue_.Emplace(1001, "one");
-  ASSERT_TRUE(queue_.Remove(1001));
-  ASSERT_FALSE(queue_.Remove(1001));
-  ASSERT_FALSE(queue_.Remove(1001));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1001)));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1001)));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, ConstGetter) {
-  queue_.Emplace(1001, "one");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
   const auto& const_queue = queue_;
 
-  EXPECT_EQ("one", *const_queue.GetEntry(1001));
-  EXPECT_EQ(nullptr, const_queue.GetEntry(1002));
+  EXPECT_EQ("one", *const_queue.GetEntry(QuicPacketNumber(1001)));
+  EXPECT_EQ(nullptr, const_queue.GetEntry(QuicPacketNumber(1002)));
 }
 
 }  // namespace
diff --git a/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc
index e61c973..980889d 100644
--- a/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc
+++ b/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc
@@ -28,7 +28,7 @@
   void OnInsertWithoutNameReference(QuicStringPiece name,
                                     QuicStringPiece value) override {}
   void OnDuplicate(uint64_t index) override {}
-  void OnDynamicTableSizeUpdate(uint64_t max_size) override {}
+  void OnSetDynamicTableCapacity(uint64_t capacity) override {}
   void OnErrorDetected(QuicStringPiece error_message) override {
     error_detected_ = true;
   }
diff --git a/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
index f404a76..501a69f 100644
--- a/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
+++ b/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
@@ -8,6 +8,7 @@
 #include <cstdint>
 #include <limits>
 
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fuzzed_data_provider.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -15,22 +16,12 @@
 namespace quic {
 namespace test {
 
-// A QpackEncoderStreamSender::Delegate implementation that ignores encoded
-// data.
-class NoOpDelegate : public QpackEncoderStreamSender::Delegate {
- public:
-  NoOpDelegate() = default;
-  ~NoOpDelegate() override = default;
-
-  void Write(QuicStringPiece data) override {}
-};
-
 // This fuzzer exercises QpackEncoderStreamSender.
 // TODO(bnc): Encoded data could be fed into QpackEncoderStreamReceiver and
 // decoded instructions directly compared to input.  Figure out how to get gMock
 // enabled for cc_fuzz_target target types.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  NoOpDelegate delegate;
+  NoopEncoderStreamSenderDelegate delegate;
   QpackEncoderStreamSender sender(&delegate);
 
   QuicFuzzedDataProvider provider(data, size);
@@ -65,8 +56,8 @@
         break;
       }
       case 3: {
-        uint64_t max_size = provider.ConsumeIntegral<uint64_t>();
-        sender.SendDynamicTableSizeUpdate(max_size);
+        uint64_t capacity = provider.ConsumeIntegral<uint64_t>();
+        sender.SendSetDynamicTableCapacity(capacity);
         break;
       }
     }
diff --git a/quic/core/qpack/offline/qpack_offline_decoder.cc b/quic/core/qpack/offline/qpack_offline_decoder.cc
index c3ad1f9..2b02edd 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder.cc
+++ b/quic/core/qpack/offline/qpack_offline_decoder.cc
@@ -44,7 +44,7 @@
   return true;
 }
 
-void QpackOfflineDecoder::OnError(QuicStringPiece error_message) {
+void QpackOfflineDecoder::OnEncoderStreamError(QuicStringPiece error_message) {
   QUIC_LOG(ERROR) << "Encoder stream error: " << error_message;
   encoder_stream_error_detected_ = true;
 }
diff --git a/quic/core/qpack/offline/qpack_offline_decoder.h b/quic/core/qpack/offline/qpack_offline_decoder.h
index faa64bc..922fd64 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder.h
+++ b/quic/core/qpack/offline/qpack_offline_decoder.h
@@ -5,6 +5,8 @@
 #ifndef QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_
 #define QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_
 
+#include <list>
+
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -30,7 +32,7 @@
                                   QuicStringPiece expected_headers_filename);
 
   // QpackDecoder::EncoderStreamErrorDelegate implementation:
-  void OnError(QuicStringPiece error_message) override;
+  void OnEncoderStreamError(QuicStringPiece error_message) override;
 
  private:
   // Parse decoder parameters from |input_filename| and set up |decoder_|
diff --git a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
index 2068f52..499c9fd 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
+++ b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
@@ -20,7 +20,7 @@
     return 1;
   }
 
-  size_t i;
+  int i;
   for (i = 0; 2 * i + 1 < argc; ++i) {
     const quic::QuicStringPiece input_filename(argv[2 * i + 1]);
     const quic::QuicStringPiece expected_headers_filename(argv[2 * i + 2]);
diff --git a/quic/core/qpack/qpack_constants.cc b/quic/core/qpack/qpack_constants.cc
index eda1ef4..b9144e0 100644
--- a/quic/core/qpack/qpack_constants.cc
+++ b/quic/core/qpack/qpack_constants.cc
@@ -4,7 +4,6 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
 
-#include <cstddef>
 #include <limits>
 
 #include "base/logging.h"
@@ -17,8 +16,9 @@
 //  * in each instruction, the bits of |value| that are zero in |mask| are zero;
 //  * every byte matches exactly one opcode.
 void ValidateLangague(const QpackLanguage* language) {
+#ifndef NDEBUG
   for (const auto* instruction : *language) {
-    DCHECK_EQ(0u, instruction->opcode.value & ~instruction->opcode.mask);
+    DCHECK_EQ(0, instruction->opcode.value & ~instruction->opcode.mask);
   }
 
   for (uint8_t byte = 0; byte < std::numeric_limits<uint8_t>::max(); ++byte) {
@@ -30,6 +30,7 @@
     }
     DCHECK_EQ(1u, match_count) << static_cast<int>(byte);
   }
+#endif
 }
 
 }  // namespace
@@ -68,7 +69,7 @@
   return instruction;
 }
 
-const QpackInstruction* DynamicTableSizeUpdateInstruction() {
+const QpackInstruction* SetDynamicTableCapacityInstruction() {
   static const QpackInstructionOpcode* const opcode =
       new QpackInstructionOpcode{0b00100000, 0b11100000};
   static const QpackInstruction* const instruction =
@@ -80,14 +81,12 @@
   static const QpackLanguage* const language = new QpackLanguage{
       InsertWithNameReferenceInstruction(),
       InsertWithoutNameReferenceInstruction(), DuplicateInstruction(),
-      DynamicTableSizeUpdateInstruction()};
-#ifndef NDEBUG
+      SetDynamicTableCapacityInstruction()};
   ValidateLangague(language);
-#endif
   return language;
 }
 
-const QpackInstruction* TableStateSynchronizeInstruction() {
+const QpackInstruction* InsertCountIncrementInstruction() {
   static const QpackInstructionOpcode* const opcode =
       new QpackInstructionOpcode{0b00000000, 0b11000000};
   static const QpackInstruction* const instruction =
@@ -113,11 +112,9 @@
 
 const QpackLanguage* QpackDecoderStreamLanguage() {
   static const QpackLanguage* const language = new QpackLanguage{
-      TableStateSynchronizeInstruction(), HeaderAcknowledgementInstruction(),
+      InsertCountIncrementInstruction(), HeaderAcknowledgementInstruction(),
       StreamCancellationInstruction()};
-#ifndef NDEBUG
   ValidateLangague(language);
-#endif
   return language;
 }
 
@@ -136,9 +133,7 @@
 const QpackLanguage* QpackPrefixLanguage() {
   static const QpackLanguage* const language =
       new QpackLanguage{QpackPrefixInstruction()};
-#ifndef NDEBUG
   ValidateLangague(language);
-#endif
   return language;
 }
 
@@ -198,9 +193,7 @@
                         QpackLiteralHeaderFieldNameReferenceInstruction(),
                         QpackLiteralHeaderFieldPostBaseInstruction(),
                         QpackLiteralHeaderFieldInstruction()};
-#ifndef NDEBUG
   ValidateLangague(language);
-#endif
   return language;
 }
 
diff --git a/quic/core/qpack/qpack_constants.h b/quic/core/qpack/qpack_constants.h
index 4fce3dd..7b7eb47 100644
--- a/quic/core/qpack/qpack_constants.h
+++ b/quic/core/qpack/qpack_constants.h
@@ -30,14 +30,14 @@
 // literal consumes all bytes containing the field value.
 enum class QpackInstructionFieldType {
   // A single bit indicating whether the index refers to the static table, or
-  // indicating the sign of Delta Base Index.  Called "S" bit because both
-  // "static" and "sign" start with the letter "S".
+  // indicating the sign of Delta Base.  Called "S" bit because both "static"
+  // and "sign" start with the letter "S".
   kSbit,
   // An integer encoded with variable length encoding.  This could be an index,
-  // stream ID, maximum size, or Largest Reference.
+  // stream ID, maximum size, or Encoded Required Insert Count.
   kVarint,
   // A second integer encoded with variable length encoding.  This could be
-  // Delta Base Index.
+  // Delta Base.
   kVarint2,
   // A header name or header value encoded as:
   //   a bit indicating whether it is Huffman encoded;
@@ -97,15 +97,15 @@
 const QpackInstruction* DuplicateInstruction();
 
 // 5.2.4 Dynamic Table Size Update
-const QpackInstruction* DynamicTableSizeUpdateInstruction();
+const QpackInstruction* SetDynamicTableCapacityInstruction();
 
 // Encoder stream language.
 const QpackLanguage* QpackEncoderStreamLanguage();
 
 // 5.3 Decoder stream instructions
 
-// 5.3.1 Table State Synchronize
-const QpackInstruction* TableStateSynchronizeInstruction();
+// 5.3.1 Insert Count Increment
+const QpackInstruction* InsertCountIncrementInstruction();
 
 // 5.3.2 Header Acknowledgement
 const QpackInstruction* HeaderAcknowledgementInstruction();
diff --git a/quic/core/qpack/qpack_decoder.cc b/quic/core/qpack/qpack_decoder.cc
index 9ae883f..fd0867a 100644
--- a/quic/core/qpack/qpack_decoder.cc
+++ b/quic/core/qpack/qpack_decoder.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 
+#include <limits>
+
 #include "base/logging.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 
@@ -40,33 +42,36 @@
   if (is_static) {
     auto entry = header_table_.LookupEntry(/* is_static = */ true, name_index);
     if (!entry) {
-      encoder_stream_error_delegate_->OnError("Invalid static table entry.");
+      encoder_stream_error_delegate_->OnEncoderStreamError(
+          "Invalid static table entry.");
       return;
     }
 
     entry = header_table_.InsertEntry(entry->name(), value);
     if (!entry) {
-      encoder_stream_error_delegate_->OnError(
+      encoder_stream_error_delegate_->OnEncoderStreamError(
           "Error inserting entry with name reference.");
     }
     return;
   }
 
-  uint64_t real_index;
-  if (!EncoderStreamRelativeIndexToRealIndex(name_index, &real_index)) {
-    encoder_stream_error_delegate_->OnError("Invalid relative index.");
+  uint64_t absolute_index;
+  if (!EncoderStreamRelativeIndexToAbsoluteIndex(name_index, &absolute_index)) {
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Invalid relative index.");
     return;
   }
 
   const QpackEntry* entry =
-      header_table_.LookupEntry(/* is_static = */ false, real_index);
+      header_table_.LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Dynamic table entry not found.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Dynamic table entry not found.");
     return;
   }
   entry = header_table_.InsertEntry(entry->name(), value);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError(
+    encoder_stream_error_delegate_->OnEncoderStreamError(
         "Error inserting entry with name reference.");
   }
 }
@@ -75,50 +80,54 @@
                                                 QuicStringPiece value) {
   const QpackEntry* entry = header_table_.InsertEntry(name, value);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Error inserting literal entry.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error inserting literal entry.");
   }
 }
 
 void QpackDecoder::OnDuplicate(uint64_t index) {
-  uint64_t real_index;
-  if (!EncoderStreamRelativeIndexToRealIndex(index, &real_index)) {
-    encoder_stream_error_delegate_->OnError("Invalid relative index.");
+  uint64_t absolute_index;
+  if (!EncoderStreamRelativeIndexToAbsoluteIndex(index, &absolute_index)) {
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Invalid relative index.");
     return;
   }
 
   const QpackEntry* entry =
-      header_table_.LookupEntry(/* is_static = */ false, real_index);
+      header_table_.LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Dynamic table entry not found.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Dynamic table entry not found.");
     return;
   }
   entry = header_table_.InsertEntry(entry->name(), entry->value());
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Error inserting duplicate entry.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error inserting duplicate entry.");
   }
 }
 
-void QpackDecoder::OnDynamicTableSizeUpdate(uint64_t max_size) {
-  if (!header_table_.UpdateTableSize(max_size)) {
-    encoder_stream_error_delegate_->OnError(
-        "Error updating dynamic table size.");
+void QpackDecoder::OnSetDynamicTableCapacity(uint64_t capacity) {
+  if (!header_table_.SetDynamicTableCapacity(capacity)) {
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error updating dynamic table capacity.");
   }
 }
 
 void QpackDecoder::OnErrorDetected(QuicStringPiece error_message) {
-  encoder_stream_error_delegate_->OnError(error_message);
+  encoder_stream_error_delegate_->OnEncoderStreamError(error_message);
 }
 
-bool QpackDecoder::EncoderStreamRelativeIndexToRealIndex(
+bool QpackDecoder::EncoderStreamRelativeIndexToAbsoluteIndex(
     uint64_t relative_index,
-    uint64_t* real_index) const {
+    uint64_t* absolute_index) const {
   if (relative_index == std::numeric_limits<uint64_t>::max() ||
       relative_index + 1 > std::numeric_limits<uint64_t>::max() -
                                header_table_.inserted_entry_count()) {
     return false;
   }
 
-  *real_index = header_table_.inserted_entry_count() - relative_index - 1;
+  *absolute_index = header_table_.inserted_entry_count() - relative_index - 1;
   return true;
 }
 
diff --git a/quic/core/qpack/qpack_decoder.h b/quic/core/qpack/qpack_decoder.h
index ffb2e88..c3b28a3 100644
--- a/quic/core/qpack/qpack_decoder.h
+++ b/quic/core/qpack/qpack_decoder.h
@@ -31,7 +31,7 @@
    public:
     virtual ~EncoderStreamErrorDelegate() {}
 
-    virtual void OnError(QuicStringPiece error_message) = 0;
+    virtual void OnEncoderStreamError(QuicStringPiece error_message) = 0;
   };
 
   QpackDecoder(
@@ -79,18 +79,17 @@
   void OnInsertWithoutNameReference(QuicStringPiece name,
                                     QuicStringPiece value) override;
   void OnDuplicate(uint64_t index) override;
-  void OnDynamicTableSizeUpdate(uint64_t max_size) override;
+  void OnSetDynamicTableCapacity(uint64_t capacity) override;
   void OnErrorDetected(QuicStringPiece error_message) override;
 
  private:
   // The encoder stream uses relative index (but different from the kind of
-  // relative index used on a request stream).
-  // The spec describes how to convert these into absolute index (one based).
-  // QpackHeaderTable uses real index (zero based, one less than the absolute
-  // index).  This method converts relative index to real index.  It returns
-  // true on success, or false if conversion fails due to overflow/underflow.
-  bool EncoderStreamRelativeIndexToRealIndex(uint64_t relative_index,
-                                             uint64_t* real_index) const;
+  // relative index used on a request stream).  This method converts relative
+  // index to absolute index (zero based).  It returns true on success, or false
+  // if conversion fails due to overflow/underflow.
+  bool EncoderStreamRelativeIndexToAbsoluteIndex(
+      uint64_t relative_index,
+      uint64_t* absolute_index) const;
 
   EncoderStreamErrorDelegate* const encoder_stream_error_delegate_;
   QpackEncoderStreamReceiver encoder_stream_receiver_;
diff --git a/quic/core/qpack/qpack_decoder_stream_receiver.cc b/quic/core/qpack/qpack_decoder_stream_receiver.cc
index b38aedf..559ce43 100644
--- a/quic/core/qpack/qpack_decoder_stream_receiver.cc
+++ b/quic/core/qpack/qpack_decoder_stream_receiver.cc
@@ -27,8 +27,8 @@
 
 bool QpackDecoderStreamReceiver::OnInstructionDecoded(
     const QpackInstruction* instruction) {
-  if (instruction == TableStateSynchronizeInstruction()) {
-    delegate_->OnTableStateSynchronize(instruction_decoder_.varint());
+  if (instruction == InsertCountIncrementInstruction()) {
+    delegate_->OnInsertCountIncrement(instruction_decoder_.varint());
     return true;
   }
 
diff --git a/quic/core/qpack/qpack_decoder_stream_receiver.h b/quic/core/qpack/qpack_decoder_stream_receiver.h
index 003be12..61c2773 100644
--- a/quic/core/qpack/qpack_decoder_stream_receiver.h
+++ b/quic/core/qpack/qpack_decoder_stream_receiver.h
@@ -25,8 +25,8 @@
    public:
     virtual ~Delegate() = default;
 
-    // 5.3.1 Table State Synchronize
-    virtual void OnTableStateSynchronize(uint64_t insert_count) = 0;
+    // 5.3.1 Insert Count Increment
+    virtual void OnInsertCountIncrement(uint64_t increment) = 0;
     // 5.3.2 Header Acknowledgement
     virtual void OnHeaderAcknowledgement(QuicStreamId stream_id) = 0;
     // 5.3.3 Stream Cancellation
diff --git a/quic/core/qpack/qpack_decoder_stream_receiver_test.cc b/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
index e9b3124..fc7225f 100644
--- a/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
+++ b/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
@@ -9,6 +9,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using testing::Eq;
 using testing::StrictMock;
 
 namespace quic {
@@ -19,7 +20,7 @@
  public:
   ~MockDelegate() override = default;
 
-  MOCK_METHOD1(OnTableStateSynchronize, void(uint64_t insert_count));
+  MOCK_METHOD1(OnInsertCountIncrement, void(uint64_t increment));
   MOCK_METHOD1(OnHeaderAcknowledgement, void(QuicStreamId stream_id));
   MOCK_METHOD1(OnStreamCancellation, void(QuicStreamId stream_id));
   MOCK_METHOD1(OnErrorDetected, void(QuicStringPiece error_message));
@@ -34,20 +35,20 @@
   StrictMock<MockDelegate> delegate_;
 };
 
-TEST_F(QpackDecoderStreamReceiverTest, TableStateSynchronize) {
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(0));
+TEST_F(QpackDecoderStreamReceiverTest, InsertCountIncrement) {
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(0));
   stream_.Decode(QuicTextUtils::HexDecode("00"));
 
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(10));
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(10));
   stream_.Decode(QuicTextUtils::HexDecode("0a"));
 
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(63));
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(63));
   stream_.Decode(QuicTextUtils::HexDecode("3f00"));
 
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(200));
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(200));
   stream_.Decode(QuicTextUtils::HexDecode("3f8901"));
 
-  EXPECT_CALL(delegate_, OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(delegate_, OnErrorDetected(Eq("Encoded integer too large.")));
   stream_.Decode(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
 }
 
@@ -64,7 +65,7 @@
   EXPECT_CALL(delegate_, OnHeaderAcknowledgement(503));
   stream_.Decode(QuicTextUtils::HexDecode("fff802"));
 
-  EXPECT_CALL(delegate_, OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(delegate_, OnErrorDetected(Eq("Encoded integer too large.")));
   stream_.Decode(QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
 }
 
@@ -81,7 +82,7 @@
   EXPECT_CALL(delegate_, OnStreamCancellation(110));
   stream_.Decode(QuicTextUtils::HexDecode("7f2f"));
 
-  EXPECT_CALL(delegate_, OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(delegate_, OnErrorDetected(Eq("Encoded integer too large.")));
   stream_.Decode(QuicTextUtils::HexDecode("7fffffffffffffffffffff"));
 }
 
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.cc b/quic/core/qpack/qpack_decoder_stream_sender.cc
index 48d0e0e..141b64a 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -18,18 +18,17 @@
   DCHECK(delegate_);
 }
 
-void QpackDecoderStreamSender::SendTableStateSynchronize(
-    uint64_t insert_count) {
-  instruction_encoder_.set_varint(insert_count);
+void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) {
+  instruction_encoder_.set_varint(increment);
 
-  instruction_encoder_.Encode(TableStateSynchronizeInstruction());
+  instruction_encoder_.Encode(InsertCountIncrementInstruction());
 
   QuicString output;
 
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendHeaderAcknowledgement(
@@ -43,7 +42,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) {
@@ -56,7 +55,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.h b/quic/core/qpack/qpack_decoder_stream_sender.h
index 0522042..a791173 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.h
+++ b/quic/core/qpack/qpack_decoder_stream_sender.h
@@ -24,9 +24,10 @@
     virtual ~Delegate() = default;
 
     // Encoded |data| is ready to be written on the decoder stream.
-    // Write() is called exactly once for each instruction, |data| contains the
-    // entire encoded instruction and it is guaranteed to be not empty.
-    virtual void Write(QuicStringPiece data) = 0;
+    // WriteDecoderStreamData() is called exactly once for each instruction.
+    // |data| contains the entire encoded instruction and it is guaranteed to be
+    // not empty.
+    virtual void WriteDecoderStreamData(QuicStringPiece data) = 0;
   };
 
   explicit QpackDecoderStreamSender(Delegate* delegate);
@@ -37,8 +38,8 @@
   // Methods for sending instructions, see
   // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.3
 
-  // 5.3.1 Table State Synchronize
-  void SendTableStateSynchronize(uint64_t insert_count);
+  // 5.3.1 Insert Count Increment
+  void SendInsertCountIncrement(uint64_t increment);
   // 5.3.2 Header Acknowledgement
   void SendHeaderAcknowledgement(QuicStreamId stream_id);
   // 5.3.3 Stream Cancellation
diff --git a/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/quic/core/qpack/qpack_decoder_stream_sender_test.cc
index ab65c8c..cc95759 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender_test.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender_test.cc
@@ -9,6 +9,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using ::testing::Eq;
 using ::testing::StrictMock;
 
 namespace quic {
@@ -19,7 +20,7 @@
  public:
   ~MockSenderDelegate() override = default;
 
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
+  MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data));
 };
 
 class QpackDecoderStreamSenderTest : public QuicTest {
@@ -31,45 +32,57 @@
   QpackDecoderStreamSender stream_;
 };
 
-TEST_F(QpackDecoderStreamSenderTest, TableStateSynchronize) {
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("00")));
-  stream_.SendTableStateSynchronize(0);
+TEST_F(QpackDecoderStreamSenderTest, InsertCountIncrement) {
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("00"))));
+  stream_.SendInsertCountIncrement(0);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("0a")));
-  stream_.SendTableStateSynchronize(10);
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("0a"))));
+  stream_.SendInsertCountIncrement(10);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("3f00")));
-  stream_.SendTableStateSynchronize(63);
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f00"))));
+  stream_.SendInsertCountIncrement(63);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("3f8901")));
-  stream_.SendTableStateSynchronize(200);
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f8901"))));
+  stream_.SendInsertCountIncrement(200);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, HeaderAcknowledgement) {
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("80")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("80"))));
   stream_.SendHeaderAcknowledgement(0);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("a5")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("a5"))));
   stream_.SendHeaderAcknowledgement(37);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("ff00")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("ff00"))));
   stream_.SendHeaderAcknowledgement(127);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("fff802")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("fff802"))));
   stream_.SendHeaderAcknowledgement(503);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, StreamCancellation) {
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("40")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("40"))));
   stream_.SendStreamCancellation(0);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("53")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("53"))));
   stream_.SendStreamCancellation(19);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("7f00")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f00"))));
   stream_.SendStreamCancellation(63);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("7f2f")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f2f"))));
   stream_.SendStreamCancellation(110);
 }
 
diff --git a/quic/core/qpack/qpack_decoder_test.cc b/quic/core/qpack/qpack_decoder_test.cc
index 5f68213..52f739c 100644
--- a/quic/core/qpack/qpack_decoder_test.cc
+++ b/quic/core/qpack/qpack_decoder_test.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
@@ -66,8 +68,8 @@
                                FragmentMode::kOctetByOctet));
 
 TEST_P(QpackDecoderTest, NoPrefix) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Incomplete header data prefix.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Incomplete header data prefix.")));
 
   // Header Data Prefix is at least two bytes long.
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00"));
@@ -76,60 +78,54 @@
 TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0000"));
 }
 
 TEST_P(QpackDecoderTest, LiteralEntryEmptyName) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece(""), QuicStringPiece("foo")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("foo")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002003666f6f"));
 }
 
 TEST_P(QpackDecoderTest, LiteralEntryEmptyValue) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f00"));
 }
 
 TEST_P(QpackDecoderTest, LiteralEntryEmptyNameAndValue) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece(""), QuicStringPiece("")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002000"));
 }
 
 TEST_P(QpackDecoderTest, SimpleLiteralEntry) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f03626172"));
 }
 
 TEST_P(QpackDecoderTest, MultipleLiteralEntries) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   QuicString str(127, 'a');
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("foobaar"),
-                                        QuicStringPiece(str)));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foobaar"), QuicStringPiece(str)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                // prefix
@@ -146,24 +142,24 @@
 
 // Name Length value is too large for varint decoder to decode.
 TEST_P(QpackDecoderTest, NameLenTooLargeForVarintDecoder) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Encoded integer too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000027ffffffffffffffffffff"));
 }
 
 // Name Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_P(QpackDecoderTest, NameLenExceedsLimit) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("String literal too long.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("String literal too long.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000027ffff7f"));
 }
 
 // Value Length value is too large for varint decoder to decode.
 TEST_P(QpackDecoderTest, ValueLenTooLargeForVarintDecoder) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Encoded integer too large.")));
 
   DecodeHeaderBlock(
       QuicTextUtils::HexDecode("000023666f6f7fffffffffffffffffffff"));
@@ -171,37 +167,35 @@
 
 // Value Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_P(QpackDecoderTest, ValueLenExceedsLimit) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("String literal too long.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("String literal too long.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f7fffff7f"));
 }
 
 TEST_P(QpackDecoderTest, IncompleteHeaderBlock) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Incomplete header block.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Incomplete header block.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002366"));
 }
 
 TEST_P(QpackDecoderTest, HuffmanSimple) {
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("custom-key"),
-                                        QuicStringPiece("custom-value")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
-  DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      QuicStringPiece("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf")));
+  DecodeHeaderBlock(
+      QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
 }
 
 TEST_P(QpackDecoderTest, AlternatingHuffmanNonHuffman) {
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("custom-key"),
-                                        QuicStringPiece("custom-value")))
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")))
       .Times(4);
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                        // Prefix.
@@ -212,8 +206,7 @@
       "2f0125a849e95ba97d7f"        // Huffman-encoded name.
       "0c637573746f6d2d76616c7565"  // Non-Huffman encoded value.
       "2703637573746f6d2d6b6579"    // Non-Huffman encoded name.
-      "8925a849e95bb8e8b4bf"        // Huffman-encoded value.
-      ));
+      "8925a849e95bb8e8b4bf"));     // Huffman-encoded value.
 }
 
 TEST_P(QpackDecoderTest, HuffmanNameDoesNotHaveEOSPrefix) {
@@ -260,30 +253,23 @@
 
 TEST_P(QpackDecoderTest, StaticTable) {
   // A header name that has multiple entries with different values.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("GET")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("POST")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("TRACE")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("POST")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("TRACE")));
 
   // A header name that has a single entry with non-empty value.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("gzip, deflate, br")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("compress")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("")));
+  EXPECT_CALL(handler_,
+              OnHeaderDecoded(Eq("accept-encoding"), Eq("gzip, deflate, br")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("compress")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("")));
 
   // A header name that has a single entry with empty value.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("location"),
-                                        QuicStringPiece("")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("location"),
-                                        QuicStringPiece("foo")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("foo")));
 
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
@@ -291,12 +277,12 @@
 
 TEST_P(QpackDecoderTest, TooHighStaticTableIndex) {
   // This is the last entry in the static table with index 98.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("x-frame-options"),
-                                        QuicStringPiece("sameorigin")));
+  EXPECT_CALL(handler_,
+              OnHeaderDecoded(Eq("x-frame-options"), Eq("sameorigin")));
 
   // Addressing entry 99 should trigger an error.
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Static table entry not found.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Static table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0000ff23ff24"));
 }
@@ -311,11 +297,10 @@
       "01"));           // Duplicate entry with relative index 1.
 
   // Now there are four entries in the dynamic table.
-  // Note that absolute indices start with 1.
-  // Entry 1: "foo", "bar"
-  // Entry 2: "foo", "ZZZ"
-  // Entry 3: ":method", "foo"
-  // Entry 4: "foo", "ZZZ"
+  // Entry 0: "foo", "bar"
+  // Entry 1: "foo", "ZZZ"
+  // Entry 2: ":method", "foo"
+  // Entry 3: "foo", "ZZZ"
 
   // Use a Sequence to test that mock methods are called in order.
   Sequence s;
@@ -327,17 +312,17 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"  // Largest Reference 4 and Delta Base Index 0.
-              // Base Index is 4 + 0 = 4.
-      "83"    // Dynamic table entry with relative index 3, absolute index 1.
-      "82"    // Dynamic table entry with relative index 2, absolute index 2.
-      "81"    // Dynamic table entry with relative index 1, absolute index 3.
-      "80"    // Dynamic table entry with relative index 0, absolute index 4.
+      "0500"  // Required Insert Count 4 and Delta Base 0.
+              // Base is 4 + 0 = 4.
+      "83"    // Dynamic table entry with relative index 3, absolute index 0.
+      "82"    // Dynamic table entry with relative index 2, absolute index 1.
+      "81"    // Dynamic table entry with relative index 1, absolute index 2.
+      "80"    // Dynamic table entry with relative index 0, absolute index 3.
       "41025a5a"));  // Name of entry 1 (relative index) from dynamic table,
                      // with value "ZZ".
 
@@ -348,17 +333,17 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0502"  // Largest Reference 4 and Delta Base Index 2.
-              // Base Index is 4 + 2 = 6.
-      "85"    // Dynamic table entry with relative index 5, absolute index 1.
-      "84"    // Dynamic table entry with relative index 4, absolute index 2.
-      "83"    // Dynamic table entry with relative index 3, absolute index 3.
-      "82"    // Dynamic table entry with relative index 2, absolute index 4.
+      "0502"  // Required Insert Count 4 and Delta Base 2.
+              // Base is 4 + 2 = 6.
+      "85"    // Dynamic table entry with relative index 5, absolute index 0.
+      "84"    // Dynamic table entry with relative index 4, absolute index 1.
+      "83"    // Dynamic table entry with relative index 3, absolute index 2.
+      "82"    // Dynamic table entry with relative index 2, absolute index 3.
       "43025a5a"));  // Name of entry 3 (relative index) from dynamic table,
                      // with value "ZZ".
 
@@ -369,17 +354,17 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0582"  // Largest Reference 4 and Delta Base Index 2 with sign bit set.
-              // Base Index is 4 - 2 - 1 = 1.
-      "80"    // Dynamic table entry with relative index 0, absolute index 1.
-      "10"    // Dynamic table entry with post-base index 0, absolute index 2.
-      "11"    // Dynamic table entry with post-base index 1, absolute index 3.
-      "12"    // Dynamic table entry with post-base index 2, absolute index 4.
+      "0582"  // Required Insert Count 4 and Delta Base 2 with sign bit set.
+              // Base is 4 - 2 - 1 = 1.
+      "80"    // Dynamic table entry with relative index 0, absolute index 0.
+      "10"    // Dynamic table entry with post-base index 0, absolute index 1.
+      "11"    // Dynamic table entry with post-base index 1, absolute index 2.
+      "12"    // Dynamic table entry with post-base index 2, absolute index 3.
       "01025a5a"));  // Name of entry 1 (post-base index) from dynamic table,
                      // with value "ZZ".
 }
@@ -391,12 +376,12 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference 1 and Delta Base Index 0.
-               // Base Index is 1 + 0 = 1.
-      "80"));  // Dynamic table entry with relative index 0, absolute index 1.
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
+      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
 
   // Change dynamic table capacity to 32 bytes, smaller than the entry.
   // This must cause the entry to be evicted.
@@ -406,14 +391,14 @@
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference 1 and Delta Base Index 0.
-               // Base Index is 1 + 0 = 1.
-      "80"));  // Dynamic table entry with relative index 0, absolute index 1.
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
+      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
 }
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorEntryTooLarge) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Error inserting literal entry.")));
+              OnEncoderStreamError(Eq("Error inserting literal entry.")));
 
   // Set dynamic table capacity to 34.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f03"));
@@ -423,7 +408,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidStaticTableEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Invalid static table entry.")));
+              OnEncoderStreamError(Eq("Invalid static table entry.")));
 
   // Address invalid static table entry index 99.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("ff2400"));
@@ -431,7 +416,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidDynamicTableEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Dynamic table entry not found.")));
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode(
       "6294e703626172"  // Add literal entry with name "foo" and value "bar".
@@ -442,7 +427,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorDuplicateInvalidEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Dynamic table entry not found.")));
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode(
       "6294e703626172"  // Add literal entry with name "foo" and value "bar".
@@ -453,27 +438,25 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorTooLargeInteger) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Encoded integer too large.")));
+              OnEncoderStreamError(Eq("Encoded integer too large.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
 }
 
-TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIndexIsZero) {
+TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIsZero) {
   EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0280"  // Largest Reference is 1.  Base Index 1 - 1 - 0 = 0 is explicitly
-              // permitted by the spec.
+      "0280"   // Required Insert Count is 1.  Base 1 - 1 - 0 = 0 is explicitly
+               // permitted by the spec.
       "80"));  // However, addressing entry with relative index 0 would point to
-               // absolute index 0, which is invalid (absolute index is one
-               // based).
+               // absolute index -1, which is invalid.
 }
 
-TEST_P(QpackDecoderTest, InvalidNegativeBaseIndex) {
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Error calculating Base Index.")));
+TEST_P(QpackDecoderTest, InvalidNegativeBase) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Error calculating Base.")));
 
-  // Largest reference 1, Delta Base Index 1 with sign bit set, Base Index would
+  // Required Insert Count 1, Delta Base 1 with sign bit set, Base would
   // be 1 - 1 - 1 = -1, but it is not allowed to be negative.
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0281"));
 }
@@ -486,38 +469,37 @@
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"   // Largest Reference 4 and Delta Base Index 0.
-               // Base Index is 4 + 0 = 4.
+      "0500"   // Required Insert Count 4 and Delta Base 0.
+               // Base is 4 + 0 = 4.
       "82"));  // Indexed Header Field instruction addressing relative index 2.
-               // This is absolute index 2. Such entry does not exist.
+               // This is absolute index 1. Such entry does not exist.
 
   EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"   // Largest Reference 4 and Delta Base Index 0.
-               // Base Index is 4 + 0 = 4.
+      "0500"   // Required Insert Count 4 and Delta Base 0.
+               // Base is 4 + 0 = 4.
       "84"));  // Indexed Header Field instruction addressing relative index 4.
-               // This is absolute index 0, which is invalid, because absolute
-               // indexing starts from 1.
+               // This is absolute index -1, which is invalid.
 
   EXPECT_CALL(handler_,
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"     // Largest Reference 4 and Delta Base Index 0.
-                 // Base Index is 4 + 0 = 4.
+      "0500"     // Required Insert Count 4 and Delta Base 0.
+                 // Base is 4 + 0 = 4.
       "4200"));  // Literal Header Field with Name Reference instruction
-                 // addressing relative index 2.  This is absolute index 2. Such
+                 // addressing relative index 2.  This is absolute index 1. Such
                  // entry does not exist.
 
   EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"     // Largest Reference 4 and Delta Base Index 0.
-                 // Base Index is 4 + 0 = 4.
+      "0500"     // Required Insert Count 4 and Delta Base 0.
+                 // Base is 4 + 0 = 4.
       "4400"));  // Literal Header Field with Name Reference instruction
-                 // addressing relative index 4.  This is absolute index 0,
-                 // which is invalid, because absolute indexing starts from 1.
+                 // addressing relative index 4.  This is absolute index -1,
+                 // which is invalid.
 }
 
 TEST_P(QpackDecoderTest, InvalidDynamicEntryByPostBaseIndex) {
@@ -528,26 +510,27 @@
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0380"   // Largest Reference 2 and Delta Base Index 0 with sign bit set.
-               // Base Index is 2 - 0 - 1 = 1
+      "0380"   // Required Insert Count 2 and Delta Base 0 with sign bit set.
+               // Base is 2 - 0 - 1 = 1
       "10"));  // Indexed Header Field instruction addressing dynamic table
-               // entry with post-base index 0, absolute index 2.  Such entry
+               // entry with post-base index 0, absolute index 1.  Such entry
                // does not exist.
 
   EXPECT_CALL(handler_,
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0380"  // Largest Reference 2 and Delta Base Index 0 with sign bit set.
-              // Base Index is 2 - 0 - 1 = 1
+      "0380"     // Required Insert Count 2 and Delta Base 0 with sign bit set.
+                 // Base is 2 - 0 - 1 = 1
       "0000"));  // Literal Header Field With Name Reference instruction
                  // addressing dynamic table entry with post-base index 0,
-                 // absolute index 2.  Such entry does not exist.
+                 // absolute index 1.  Such entry does not exist.
 }
 
 TEST_P(QpackDecoderTest, TableCapacityMustNotExceedMaximum) {
-  EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Error updating dynamic table size.")));
+  EXPECT_CALL(
+      encoder_stream_error_delegate_,
+      OnEncoderStreamError(Eq("Error updating dynamic table capacity.")));
 
   // Try to update dynamic table capacity to 2048, which exceeds the maximum.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe10f"));
@@ -558,17 +541,17 @@
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f61"));
 }
 
-TEST_P(QpackDecoderTest, LargestReferenceOutOfRange) {
+TEST_P(QpackDecoderTest, InvalidEncodedRequiredInsertCount) {
   // Maximum dynamic table capacity is 1024.
   // MaxEntries is 1024 / 32 = 32.
-  // Largest Reference is decoded modulo 2 * MaxEntries, that is, modulo 64.
+  // Required Insert Count is decoded modulo 2 * MaxEntries, that is, modulo 64.
   // A value of 1 cannot be encoded as 65 even though it has the same remainder.
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Error decoding Largest Reference.")));
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(
+                            Eq("Error decoding Required Insert Count.")));
   DecodeHeaderBlock(QuicTextUtils::HexDecode("4100"));
 }
 
-TEST_P(QpackDecoderTest, WrappedLargestReference) {
+TEST_P(QpackDecoderTest, WrappedRequiredInsertCount) {
   // Maximum dynamic table capacity is 1024.
   // MaxEntries is 1024 / 32 = 32.
 
@@ -583,131 +566,136 @@
   // Duplicate most recent entry 200 times.
   DecodeEncoderStreamData(QuicString(200, '\x00'));
 
-  // Now there is only one entry in the dynamic table, with absolute index 201.
+  // Now there is only one entry in the dynamic table, with absolute index 200.
 
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq(header_value)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
-  // Send header block with Largest Reference = 201.
+  // Send header block with Required Insert Count = 201.
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0a00"   // Wire Largest Reference 10, Largest Reference 201,
-               // Delta Base Index 0, Base Index 201.
+      "0a00"   // Encoded Required Insert Count 10, Required Insert Count 201,
+               // Delta Base 0, Base 201.
       "80"));  // Emit dynamic table entry with relative index 0.
 }
 
-TEST_P(QpackDecoderTest, NonZeroLargestReferenceButNoDynamicEntries) {
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("GET")));
+TEST_P(QpackDecoderTest, NonZeroRequiredInsertCountButNoDynamicEntries) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
   EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference is 1.
+      "0200"   // Required Insert Count is 1.
       "d1"));  // But the only instruction references the static table.
 }
 
-TEST_P(QpackDecoderTest, AddressEntryBeyondLargestReference) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0201"   // Largest Reference 1 and Delta Base Index 1.
-               // Base Index is 1 + 1 = 2.
+      "0201"   // Required Insert Count 1 and Delta Base 1.
+               // Base is 1 + 1 = 2.
       "80"));  // Indexed Header Field instruction addressing dynamic table
-               // entry with relative index 0, absolute index 2.  This is beyond
-               // Largest Reference.
+               // entry with relative index 0, absolute index 1.  This is not
+               // allowed by Required Insert Count.
 
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0201"     // Largest Reference 1 and Delta Base Index 1.
-                 // Base Index is 1 + 1 = 2.
+      "0201"     // Required Insert Count 1 and Delta Base 1.
+                 // Base is 1 + 1 = 2.
       "4000"));  // Literal Header Field with Name Reference instruction
                  // addressing dynamic table entry with relative index 0,
-                 // absolute index 2.  This is beyond Largest Reference.
+                 // absolute index 1.  This is not allowed by Required Index
+                 // Count.
 
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference 1 and Delta Base Index 0.
-               // Base Index is 1 + 0 = 1.
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
       "10"));  // Indexed Header Field with Post-Base Index instruction
                // addressing dynamic table entry with post-base index 0,
-               // absolute index 2.  This is beyond Largest Reference.
+               // absolute index 1.  This is not allowed by Required Insert
+               // Count.
 
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"     // Largest Reference 1 and Delta Base Index 0.
-                 // Base Index is 1 + 0 = 1.
+      "0200"     // Required Insert Count 1 and Delta Base 0.
+                 // Base is 1 + 0 = 1.
       "0000"));  // Literal Header Field with Post-Base Name Reference
                  // instruction addressing dynamic table entry with post-base
-                 // index 0, absolute index 2.  This is beyond Largest
-                 // Reference.
+                 // index 0, absolute index 1.  This is not allowed by Required
+                 // Index Count.
 }
 
-TEST_P(QpackDecoderTest, PromisedLargestReferenceLargerThanLargestActualIndex) {
+TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
   // Add literal entry with name "foo" and value "bar".
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
   // Duplicate entry.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("00"));
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0300"   // Largest Reference 2 and Delta Base Index 0.
-               // Base Index is 2 + 0 = 2.
+      "0300"   // Required Insert Count 2 and Delta Base 0.
+               // Base is 2 + 0 = 2.
       "81"));  // Indexed Header Field instruction addressing dynamic table
-               // entry with relative index 1, absolute index 1.  This is the
-               // largest reference in this header block, even though Largest
-               // Reference is 2.
+               // entry with relative index 1, absolute index 0.  Header block
+               // requires insert count of 1, even though Required Insert Count
+               // is 2.
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0300"     // Largest Reference 2 and Delta Base Index 0.
-                 // Base Index is 2 + 0 = 2.
+      "0300"     // Required Insert Count 2 and Delta Base 0.
+                 // Base is 2 + 0 = 2.
       "4100"));  // Literal Header Field with Name Reference instruction
                  // addressing dynamic table entry with relative index 1,
-                 // absolute index 1.  This is the largest reference in this
-                 // header block, even though Largest Reference is 2.
+                 // absolute index 0.  Header block requires insert count of 1,
+                 // even though Required Insert Count is 2.
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0481"   // Largest Reference 3 and Delta Base Index 1 with sign bit set.
-               // Base Index is 3 - 1 - 1 = 1.
+      "0481"   // Required Insert Count 3 and Delta Base 1 with sign bit set.
+               // Base is 3 - 1 - 1 = 1.
       "10"));  // Indexed Header Field with Post-Base Index instruction
                // addressing dynamic table entry with post-base index 0,
-               // absolute index 2.  This is the largest reference in this
-               // header block, even though Largest Reference is 3.
+               // absolute index 1.  Header block requires insert count of 2,
+               // even though Required Insert Count is 3.
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0481"  // Largest Reference 3 and Delta Base Index 1 with sign bit set.
-              // Base Index is 3 - 1 - 1 = 1.
+      "0481"     // Required Insert Count 3 and Delta Base 1 with sign bit set.
+                 // Base is 3 - 1 - 1 = 1.
       "0000"));  // Literal Header Field with Post-Base Name Reference
                  // instruction addressing dynamic table entry with post-base
-                 // index 0, absolute index 2.  This is the largest reference in
-                 // this header block, even though Largest Reference is 3.
+                 // index 0, absolute index 1.  Header block requires insert
+                 // count of 2, even though Required Insert Count is 3.
 }
 
 }  // namespace
diff --git a/quic/core/qpack/qpack_decoder_test_utils.cc b/quic/core/qpack/qpack_decoder_test_utils.cc
index 21a4606..e8bbd17 100644
--- a/quic/core/qpack/qpack_decoder_test_utils.cc
+++ b/quic/core/qpack/qpack_decoder_test_utils.cc
@@ -4,16 +4,20 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 
+#include <algorithm>
 #include <cstddef>
+#include <utility>
 
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace quic {
 namespace test {
 
-void NoopEncoderStreamErrorDelegate::OnError(QuicStringPiece error_message) {}
+void NoopEncoderStreamErrorDelegate::OnEncoderStreamError(
+    QuicStringPiece error_message) {}
 
-void NoopDecoderStreamSenderDelegate::Write(QuicStringPiece data) {}
+void NoopDecoderStreamSenderDelegate::WriteDecoderStreamData(
+    QuicStringPiece data) {}
 
 TestHeadersHandler::TestHeadersHandler()
     : decoding_completed_(false), decoding_error_detected_(false) {}
diff --git a/quic/core/qpack/qpack_decoder_test_utils.h b/quic/core/qpack/qpack_decoder_test_utils.h
index 4896ce0..937ecfc 100644
--- a/quic/core/qpack/qpack_decoder_test_utils.h
+++ b/quic/core/qpack/qpack_decoder_test_utils.h
@@ -21,7 +21,7 @@
  public:
   ~NoopEncoderStreamErrorDelegate() override = default;
 
-  void OnError(QuicStringPiece error_message) override;
+  void OnEncoderStreamError(QuicStringPiece error_message) override;
 };
 
 // Mock QpackDecoder::EncoderStreamErrorDelegate implementation.
@@ -30,7 +30,7 @@
  public:
   ~MockEncoderStreamErrorDelegate() override = default;
 
-  MOCK_METHOD1(OnError, void(QuicStringPiece error_message));
+  MOCK_METHOD1(OnEncoderStreamError, void(QuicStringPiece error_message));
 };
 
 // QpackDecoderStreamSender::Delegate implementation that does nothing.
@@ -39,7 +39,7 @@
  public:
   ~NoopDecoderStreamSenderDelegate() override = default;
 
-  void Write(QuicStringPiece data) override;
+  void WriteDecoderStreamData(QuicStringPiece data) override;
 };
 
 // Mock QpackDecoderStreamSender::Delegate implementation.
@@ -48,7 +48,7 @@
  public:
   ~MockDecoderStreamSenderDelegate() override = default;
 
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
+  MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data));
 };
 
 // HeadersHandlerInterface implementation that collects decoded headers
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index 86f1785..6019229 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -35,7 +35,7 @@
   decoder_stream_receiver_.Decode(data);
 }
 
-void QpackEncoder::OnTableStateSynchronize(uint64_t insert_count) {
+void QpackEncoder::OnInsertCountIncrement(uint64_t increment) {
   // TODO(bnc): Implement dynamic table management for encoding.
 }
 
@@ -48,7 +48,7 @@
 }
 
 void QpackEncoder::OnErrorDetected(QuicStringPiece error_message) {
-  decoder_stream_error_delegate_->OnError(error_message);
+  decoder_stream_error_delegate_->OnDecoderStreamError(error_message);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_encoder.h b/quic/core/qpack/qpack_encoder.h
index b7d7f20..4e65532 100644
--- a/quic/core/qpack/qpack_encoder.h
+++ b/quic/core/qpack/qpack_encoder.h
@@ -36,7 +36,7 @@
    public:
     virtual ~DecoderStreamErrorDelegate() {}
 
-    virtual void OnError(QuicStringPiece error_message) = 0;
+    virtual void OnDecoderStreamError(QuicStringPiece error_message) = 0;
   };
 
   QpackEncoder(
@@ -55,7 +55,7 @@
   void DecodeDecoderStreamData(QuicStringPiece data);
 
   // QpackDecoderStreamReceiver::Delegate implementation
-  void OnTableStateSynchronize(uint64_t insert_count) override;
+  void OnInsertCountIncrement(uint64_t increment) override;
   void OnHeaderAcknowledgement(QuicStreamId stream_id) override;
   void OnStreamCancellation(QuicStreamId stream_id) override;
   void OnErrorDetected(QuicStringPiece error_message) override;
diff --git a/quic/core/qpack/qpack_encoder_stream_receiver.cc b/quic/core/qpack/qpack_encoder_stream_receiver.cc
index 008e357..3f8ef08 100644
--- a/quic/core/qpack/qpack_encoder_stream_receiver.cc
+++ b/quic/core/qpack/qpack_encoder_stream_receiver.cc
@@ -45,8 +45,8 @@
     return true;
   }
 
-  DCHECK_EQ(instruction, DynamicTableSizeUpdateInstruction());
-  delegate_->OnDynamicTableSizeUpdate(instruction_decoder_.varint());
+  DCHECK_EQ(instruction, SetDynamicTableCapacityInstruction());
+  delegate_->OnSetDynamicTableCapacity(instruction_decoder_.varint());
   return true;
 }
 
diff --git a/quic/core/qpack/qpack_encoder_stream_receiver.h b/quic/core/qpack/qpack_encoder_stream_receiver.h
index 7ce4f15..66a2985 100644
--- a/quic/core/qpack/qpack_encoder_stream_receiver.h
+++ b/quic/core/qpack/qpack_encoder_stream_receiver.h
@@ -33,8 +33,8 @@
                                               QuicStringPiece value) = 0;
     // 5.2.3. Duplicate
     virtual void OnDuplicate(uint64_t index) = 0;
-    // 5.2.4. Dynamic Table Size Update
-    virtual void OnDynamicTableSizeUpdate(uint64_t max_size) = 0;
+    // 5.2.4. Set Dynamic Table Capacity
+    virtual void OnSetDynamicTableCapacity(uint64_t capacity) = 0;
     // Decoding error
     virtual void OnErrorDetected(QuicStringPiece error_message) = 0;
   };
diff --git a/quic/core/qpack/qpack_encoder_stream_receiver_test.cc b/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
index f9fce00..5685981 100644
--- a/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
+++ b/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
@@ -9,6 +9,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using testing::Eq;
 using testing::StrictMock;
 
 namespace quic {
@@ -26,7 +27,7 @@
   MOCK_METHOD2(OnInsertWithoutNameReference,
                void(QuicStringPiece name, QuicStringPiece value));
   MOCK_METHOD1(OnDuplicate, void(uint64_t index));
-  MOCK_METHOD1(OnDynamicTableSizeUpdate, void(uint64_t max_size));
+  MOCK_METHOD1(OnSetDynamicTableCapacity, void(uint64_t capacity));
   MOCK_METHOD1(OnErrorDetected, void(QuicStringPiece error_message));
 };
 
@@ -45,15 +46,15 @@
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReference) {
   // Static, index fits in prefix, empty value.
-  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 5, ""));
+  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 5, Eq("")));
   // Static, index fits in prefix, Huffman encoded value.
-  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 2, "foo"));
+  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 2, Eq("foo")));
   // Not static, index does not fit in prefix, not Huffman encoded value.
-  EXPECT_CALL(*delegate(), OnInsertWithNameReference(false, 137, "bar"));
+  EXPECT_CALL(*delegate(), OnInsertWithNameReference(false, 137, Eq("bar")));
   // Value length does not fit in prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(*delegate(),
-              OnInsertWithNameReference(false, 42, QuicString(127, 'Z')));
+              OnInsertWithNameReference(false, 42, Eq(QuicString(127, 'Z'))));
 
   Decode(QuicTextUtils::HexDecode(
       "c500"
@@ -66,29 +67,29 @@
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReferenceIndexTooLarge) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("bfffffffffffffffffffffff"));
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReferenceValueTooLong) {
-  EXPECT_CALL(*delegate(),
-              OnErrorDetected(QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("c57fffffffffffffffffffff"));
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithoutNameReference) {
   // Empty name and value.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference("", ""));
+  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq(""), Eq("")));
   // Huffman encoded short strings.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference("bar", "bar"));
+  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq("bar"), Eq("bar")));
   // Not Huffman encoded short strings.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference("foo", "foo"));
+  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq("foo"), Eq("foo")));
   // Not Huffman encoded long strings; length does not fit on prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(QuicString(31, 'Z'),
-                                                        QuicString(127, 'Z')));
+  EXPECT_CALL(*delegate(),
+              OnInsertWithoutNameReference(Eq(QuicString(31, 'Z')),
+                                           Eq(QuicString(127, 'Z'))));
 
   Decode(QuicTextUtils::HexDecode(
       "4000"
@@ -104,7 +105,7 @@
 // Name Length value is too large for varint decoder to decode.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceNameTooLongForVarintDecoder) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("5fffffffffffffffffffff"));
 }
@@ -112,8 +113,7 @@
 // Name Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceNameExceedsLimit) {
-  EXPECT_CALL(*delegate(),
-              OnErrorDetected(QuicStringPiece("String literal too long.")));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("String literal too long.")));
 
   Decode(QuicTextUtils::HexDecode("5fffff7f"));
 }
@@ -121,7 +121,7 @@
 // Value Length value is too large for varint decoder to decode.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceValueTooLongForVarintDecoder) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("436261727fffffffffffffffffffff"));
 }
@@ -129,7 +129,7 @@
 // Value Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceValueExceedsLimit) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("String literal too long."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("String literal too long.")));
 
   Decode(QuicTextUtils::HexDecode("436261727fffff7f"));
 }
@@ -144,22 +144,22 @@
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, DuplicateIndexTooLarge) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("1fffffffffffffffffffff"));
 }
 
-TEST_F(QpackEncoderStreamReceiverTest, DynamicTableSizeUpdate) {
-  // Small max size fits in prefix.
-  EXPECT_CALL(*delegate(), OnDynamicTableSizeUpdate(17));
-  // Large max size requires two extension bytes.
-  EXPECT_CALL(*delegate(), OnDynamicTableSizeUpdate(500));
+TEST_F(QpackEncoderStreamReceiverTest, SetDynamicTableCapacity) {
+  // Small capacity fits in prefix.
+  EXPECT_CALL(*delegate(), OnSetDynamicTableCapacity(17));
+  // Large capacity requires two extension bytes.
+  EXPECT_CALL(*delegate(), OnSetDynamicTableCapacity(500));
 
   Decode(QuicTextUtils::HexDecode("313fd503"));
 }
 
-TEST_F(QpackEncoderStreamReceiverTest, DynamicTableSizeUpdateMaxSizeTooLarge) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+TEST_F(QpackEncoderStreamReceiverTest, SetDynamicTableCapacityTooLarge) {
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
 }
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.cc b/quic/core/qpack/qpack_encoder_stream_sender.cc
index c7ee503..fb43046 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -33,7 +33,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendInsertWithoutNameReference(
@@ -49,7 +49,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendDuplicate(uint64_t index) {
@@ -62,20 +62,20 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
-void QpackEncoderStreamSender::SendDynamicTableSizeUpdate(uint64_t max_size) {
-  instruction_encoder_.set_varint(max_size);
+void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
+  instruction_encoder_.set_varint(capacity);
 
-  instruction_encoder_.Encode(DynamicTableSizeUpdateInstruction());
+  instruction_encoder_.Encode(SetDynamicTableCapacityInstruction());
 
   QuicString output;
 
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.h b/quic/core/qpack/qpack_encoder_stream_sender.h
index 0c8d4dd..ad34568 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -22,9 +22,10 @@
     virtual ~Delegate() = default;
 
     // Encoded |data| is ready to be written on the encoder stream.
-    // Write() is called exactly once for each instruction, |data| contains the
-    // entire encoded instruction and it is guaranteed to be not empty.
-    virtual void Write(QuicStringPiece data) = 0;
+    // WriteEncoderStreamData() is called exactly once for each instruction.
+    // |data| contains the entire encoded instruction and it is guaranteed to be
+    // not empty.
+    virtual void WriteEncoderStreamData(QuicStringPiece data) = 0;
   };
 
   explicit QpackEncoderStreamSender(Delegate* delegate);
@@ -44,8 +45,8 @@
                                       QuicStringPiece value);
   // 5.2.3. Duplicate
   void SendDuplicate(uint64_t index);
-  // 5.2.4. Dynamic Table Size Update
-  void SendDynamicTableSizeUpdate(uint64_t max_size);
+  // 5.2.4. Set Dynamic Table Capacity
+  void SendSetDynamicTableCapacity(uint64_t capacity);
 
  private:
   Delegate* const delegate_;
diff --git a/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index 46e5c46..a850f18 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
@@ -16,40 +17,36 @@
 namespace test {
 namespace {
 
-class MockSenderDelegate : public QpackEncoderStreamSender::Delegate {
- public:
-  ~MockSenderDelegate() override = default;
-
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
-};
-
 class QpackEncoderStreamSenderTest : public QuicTest {
  protected:
   QpackEncoderStreamSenderTest() : stream_(&delegate_) {}
   ~QpackEncoderStreamSenderTest() override = default;
 
-  StrictMock<MockSenderDelegate> delegate_;
+  StrictMock<MockEncoderStreamSenderDelegate> delegate_;
   QpackEncoderStreamSender stream_;
 };
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) {
   // Static, index fits in prefix, empty value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("c500"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c500"))));
   stream_.SendInsertWithNameReference(true, 5, "");
 
   // Static, index fits in prefix, Huffman encoded value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("c28294e7"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c28294e7"))));
   stream_.SendInsertWithNameReference(true, 2, "foo");
 
   // Not static, index does not fit in prefix, not Huffman encoded value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
   stream_.SendInsertWithNameReference(false, 137, "bar");
 
   // Value length does not fit in prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      Write(Eq(QuicTextUtils::HexDecode(
+      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
           "aa7f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -59,23 +56,25 @@
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
   // Empty name and value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("4000"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("4000"))));
   stream_.SendInsertWithoutNameReference("", "");
 
   // Huffman encoded short strings.
-  EXPECT_CALL(delegate_,
-              Write(Eq(QuicTextUtils::HexDecode("4362617203626172"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("4362617203626172"))));
   stream_.SendInsertWithoutNameReference("bar", "bar");
 
   // Not Huffman encoded short strings.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
   stream_.SendInsertWithoutNameReference("foo", "foo");
 
   // Not Huffman encoded long strings; length does not fit on prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      Write(Eq(QuicTextUtils::HexDecode(
+      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
           "5f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a7f"
           "005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -87,22 +86,26 @@
 
 TEST_F(QpackEncoderStreamSenderTest, Duplicate) {
   // Small index fits in prefix.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("11"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("11"))));
   stream_.SendDuplicate(17);
 
   // Large index requires two extension bytes.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("1fd503"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("1fd503"))));
   stream_.SendDuplicate(500);
 }
 
-TEST_F(QpackEncoderStreamSenderTest, DynamicTableSizeUpdate) {
-  // Small max size fits in prefix.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("31"))));
-  stream_.SendDynamicTableSizeUpdate(17);
+TEST_F(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
+  // Small capacity fits in prefix.
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("31"))));
+  stream_.SendSetDynamicTableCapacity(17);
 
-  // Large max size requires two extension bytes.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("3fd503"))));
-  stream_.SendDynamicTableSizeUpdate(500);
+  // Large capacity requires two extension bytes.
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("3fd503"))));
+  stream_.SendSetDynamicTableCapacity(500);
 }
 
 }  // namespace
diff --git a/quic/core/qpack/qpack_encoder_test.cc b/quic/core/qpack/qpack_encoder_test.cc
index 04e4dd6..e3dba00 100644
--- a/quic/core/qpack/qpack_encoder_test.cc
+++ b/quic/core/qpack/qpack_encoder_test.cc
@@ -11,6 +11,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using ::testing::Eq;
 using ::testing::StrictMock;
 using ::testing::Values;
 
@@ -153,7 +154,7 @@
 
 TEST_P(QpackEncoderTest, DecoderStreamError) {
   EXPECT_CALL(decoder_stream_error_delegate_,
-              OnError("Encoded integer too large."));
+              OnDecoderStreamError(Eq("Encoded integer too large.")));
 
   QpackEncoder encoder(&decoder_stream_error_delegate_,
                        &encoder_stream_sender_delegate_);
diff --git a/quic/core/qpack/qpack_encoder_test_utils.cc b/quic/core/qpack/qpack_encoder_test_utils.cc
index 606db4e..b9a3263 100644
--- a/quic/core/qpack/qpack_encoder_test_utils.cc
+++ b/quic/core/qpack/qpack_encoder_test_utils.cc
@@ -9,9 +9,11 @@
 namespace quic {
 namespace test {
 
-void NoopDecoderStreamErrorDelegate::OnError(QuicStringPiece error_message) {}
+void NoopDecoderStreamErrorDelegate::OnDecoderStreamError(
+    QuicStringPiece error_message) {}
 
-void NoopEncoderStreamSenderDelegate::Write(QuicStringPiece data) {}
+void NoopEncoderStreamSenderDelegate::WriteEncoderStreamData(
+    QuicStringPiece data) {}
 
 QuicString QpackEncode(
     QpackEncoder::DecoderStreamErrorDelegate* decoder_stream_error_delegate,
diff --git a/quic/core/qpack/qpack_encoder_test_utils.h b/quic/core/qpack/qpack_encoder_test_utils.h
index b000868..03d05cb 100644
--- a/quic/core/qpack/qpack_encoder_test_utils.h
+++ b/quic/core/qpack/qpack_encoder_test_utils.h
@@ -21,7 +21,7 @@
  public:
   ~NoopDecoderStreamErrorDelegate() override = default;
 
-  void OnError(QuicStringPiece error_message) override;
+  void OnDecoderStreamError(QuicStringPiece error_message) override;
 };
 
 // Mock QpackEncoder::DecoderStreamErrorDelegate implementation.
@@ -30,7 +30,7 @@
  public:
   ~MockDecoderStreamErrorDelegate() override = default;
 
-  MOCK_METHOD1(OnError, void(QuicStringPiece error_message));
+  MOCK_METHOD1(OnDecoderStreamError, void(QuicStringPiece error_message));
 };
 
 // QpackEncoderStreamSender::Delegate implementation that does nothing.
@@ -39,7 +39,16 @@
  public:
   ~NoopEncoderStreamSenderDelegate() override = default;
 
-  void Write(QuicStringPiece data) override;
+  void WriteEncoderStreamData(QuicStringPiece data) override;
+};
+
+// Mock QpackEncoderStreamSender::Delegate implementation.
+class MockEncoderStreamSenderDelegate
+    : public QpackEncoderStreamSender::Delegate {
+ public:
+  ~MockEncoderStreamSenderDelegate() override = default;
+
+  MOCK_METHOD1(WriteEncoderStreamData, void(QuicStringPiece data));
 };
 
 QuicString QpackEncode(
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc
index 4a4c9fa..4ba3ee3 100644
--- a/quic/core/qpack/qpack_header_table.cc
+++ b/quic/core/qpack/qpack_header_table.cc
@@ -143,12 +143,12 @@
   return new_entry;
 }
 
-bool QpackHeaderTable::UpdateTableSize(uint64_t max_size) {
-  if (max_size > maximum_dynamic_table_capacity_) {
+bool QpackHeaderTable::SetDynamicTableCapacity(uint64_t capacity) {
+  if (capacity > maximum_dynamic_table_capacity_) {
     return false;
   }
 
-  dynamic_table_capacity_ = max_size;
+  dynamic_table_capacity_ = capacity;
   EvictDownToCurrentCapacity();
 
   DCHECK_LE(dynamic_table_size_, dynamic_table_capacity_);
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h
index b98e7eb..eda7ab5 100644
--- a/quic/core/qpack/qpack_header_table.h
+++ b/quic/core/qpack/qpack_header_table.h
@@ -56,9 +56,9 @@
   // is larger than the capacity of the dynamic table.
   const QpackEntry* InsertEntry(QuicStringPiece name, QuicStringPiece value);
 
-  // Change dynamic table capacity to |max_size|.  Returns true on success.
-  // Returns false is |max_size| exceeds maximum dynamic table capacity.
-  bool UpdateTableSize(uint64_t max_size);
+  // Change dynamic table capacity to |capacity|.  Returns true on success.
+  // Returns false is |capacity| exceeds maximum dynamic table capacity.
+  bool SetDynamicTableCapacity(uint64_t capacity);
 
   // Set |maximum_dynamic_table_capacity_|.  The initial value is zero.  The
   // final value is determined by the decoder and is sent to the encoder as
@@ -68,7 +68,7 @@
   // This method must only be called at most once.
   void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
 
-  // Used by request streams to decode Largest Reference.
+  // Used on request streams to encode and decode Required Insert Count.
   uint64_t max_entries() const { return max_entries_; }
 
   // The number of entries inserted to the dynamic table (including ones that
diff --git a/quic/core/qpack/qpack_header_table_test.cc b/quic/core/qpack/qpack_header_table_test.cc
index 95df41d..f3ac5b5 100644
--- a/quic/core/qpack/qpack_header_table_test.cc
+++ b/quic/core/qpack/qpack_header_table_test.cc
@@ -6,7 +6,6 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_static_table.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h"
@@ -76,8 +75,8 @@
     EXPECT_FALSE(table_.InsertEntry(name, value));
   }
 
-  bool UpdateTableSize(uint64_t max_size) {
-    return table_.UpdateTableSize(max_size);
+  bool SetDynamicTableCapacity(uint64_t capacity) {
+    return table_.SetDynamicTableCapacity(capacity);
   }
 
   uint64_t max_entries() const { return table_.max_entries(); }
@@ -237,20 +236,21 @@
   EXPECT_EQ(15u, table2.max_entries());
 }
 
-TEST_F(QpackHeaderTableTest, UpdateTableSize) {
+TEST_F(QpackHeaderTableTest, SetDynamicTableCapacity) {
   // Dynamic table capacity does not affect MaxEntries.
-  EXPECT_TRUE(UpdateTableSize(1024));
+  EXPECT_TRUE(SetDynamicTableCapacity(1024));
   EXPECT_EQ(32u * 1024, max_entries());
 
-  EXPECT_TRUE(UpdateTableSize(500));
+  EXPECT_TRUE(SetDynamicTableCapacity(500));
   EXPECT_EQ(32u * 1024, max_entries());
 
   // Dynamic table capacity cannot exceed maximum dynamic table capacity.
-  EXPECT_FALSE(UpdateTableSize(2 * kMaximumDynamicTableCapacityForTesting));
+  EXPECT_FALSE(
+      SetDynamicTableCapacity(2 * kMaximumDynamicTableCapacityForTesting));
 }
 
 TEST_F(QpackHeaderTableTest, EvictByInsertion) {
-  EXPECT_TRUE(UpdateTableSize(40));
+  EXPECT_TRUE(SetDynamicTableCapacity(40));
 
   // Entry size is 3 + 3 + 32 = 38.
   InsertEntry("foo", "bar");
@@ -285,7 +285,7 @@
   ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
               /* expected_is_static = */ false, 1u);
 
-  EXPECT_TRUE(UpdateTableSize(40));
+  EXPECT_TRUE(SetDynamicTableCapacity(40));
   EXPECT_EQ(2u, inserted_entry_count());
   EXPECT_EQ(1u, dropped_entry_count());
 
@@ -293,7 +293,7 @@
   ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
               /* expected_is_static = */ false, 1u);
 
-  EXPECT_TRUE(UpdateTableSize(20));
+  EXPECT_TRUE(SetDynamicTableCapacity(20));
   EXPECT_EQ(2u, inserted_entry_count());
   EXPECT_EQ(2u, dropped_entry_count());
 
@@ -302,7 +302,7 @@
 }
 
 TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) {
-  EXPECT_TRUE(UpdateTableSize(80));
+  EXPECT_TRUE(SetDynamicTableCapacity(80));
 
   // Entry size is 3 + 3 + 32 = 38.
   // Insert same entry twice.
@@ -327,7 +327,7 @@
 }
 
 TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) {
-  EXPECT_TRUE(UpdateTableSize(80));
+  EXPECT_TRUE(SetDynamicTableCapacity(80));
 
   // Entry size is 3 + 3 + 32 = 38.
   // Insert two entries with same name but different values.
diff --git a/quic/core/qpack/qpack_instruction_decoder.cc b/quic/core/qpack/qpack_instruction_decoder.cc
index 9623dfb..dbb2076 100644
--- a/quic/core/qpack/qpack_instruction_decoder.cc
+++ b/quic/core/qpack/qpack_instruction_decoder.cc
@@ -4,6 +4,9 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h"
 
+#include <algorithm>
+#include <utility>
+
 #include "base/logging.h"
 
 namespace quic {
diff --git a/quic/core/qpack/qpack_instruction_decoder_test.cc b/quic/core/qpack/qpack_instruction_decoder_test.cc
index 99be5a0..d1fe9b5 100644
--- a/quic/core/qpack/qpack_instruction_decoder_test.cc
+++ b/quic/core/qpack/qpack_instruction_decoder_test.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -13,6 +15,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
 using ::testing::_;
+using ::testing::Eq;
 using ::testing::Expectation;
 using ::testing::Return;
 using ::testing::StrictMock;
@@ -140,14 +143,12 @@
 }
 
 TEST_P(QpackInstructionDecoderTest, InvalidHuffmanEncoding) {
-  EXPECT_CALL(delegate_,
-              OnError(QuicStringPiece("Error in Huffman-encoded string.")));
+  EXPECT_CALL(delegate_, OnError(Eq("Error in Huffman-encoded string.")));
   decoder_.Decode(QuicTextUtils::HexDecode("c1ff"));
 }
 
 TEST_P(QpackInstructionDecoderTest, InvalidVarintEncoding) {
-  EXPECT_CALL(delegate_,
-              OnError(QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(delegate_, OnError(Eq("Encoded integer too large.")));
   decoder_.Decode(QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
 }
 
diff --git a/quic/core/qpack/qpack_progressive_decoder.cc b/quic/core/qpack/qpack_progressive_decoder.cc
index 409c910..430e707 100644
--- a/quic/core/qpack/qpack_progressive_decoder.cc
+++ b/quic/core/qpack/qpack_progressive_decoder.cc
@@ -4,6 +4,9 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h"
 
+#include <algorithm>
+#include <limits>
+
 #include "base/logging.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
@@ -23,21 +26,21 @@
       header_table_(header_table),
       decoder_stream_sender_(decoder_stream_sender),
       handler_(handler),
-      largest_reference_(0),
-      base_index_(0),
-      largest_reference_seen_(0),
+      required_insert_count_(0),
+      base_(0),
+      required_insert_count_so_far_(0),
       prefix_decoded_(false),
       decoding_(true),
       error_detected_(false) {}
 
 // static
-bool QpackProgressiveDecoder::DecodeLargestReference(
-    uint64_t wire_largest_reference,
+bool QpackProgressiveDecoder::DecodeRequiredInsertCount(
+    uint64_t encoded_required_insert_count,
     uint64_t max_entries,
     uint64_t total_number_of_inserts,
-    uint64_t* largest_reference) {
-  if (wire_largest_reference == 0) {
-    *largest_reference = 0;
+    uint64_t* required_insert_count) {
+  if (encoded_required_insert_count == 0) {
+    *required_insert_count = 0;
     return true;
   }
 
@@ -45,37 +48,37 @@
   // precluding all calculations in this method from overflowing.
   DCHECK_LE(max_entries, std::numeric_limits<uint64_t>::max() / 32);
 
-  if (wire_largest_reference > 2 * max_entries) {
+  if (encoded_required_insert_count > 2 * max_entries) {
     return false;
   }
 
-  *largest_reference = wire_largest_reference - 1;
-  DCHECK_LT(*largest_reference, std::numeric_limits<uint64_t>::max() / 16);
+  *required_insert_count = encoded_required_insert_count - 1;
+  DCHECK_LT(*required_insert_count, std::numeric_limits<uint64_t>::max() / 16);
 
   uint64_t current_wrapped = total_number_of_inserts % (2 * max_entries);
   DCHECK_LT(current_wrapped, std::numeric_limits<uint64_t>::max() / 16);
 
-  if (current_wrapped >= *largest_reference + max_entries) {
-    // Largest Reference wrapped around 1 extra time.
-    *largest_reference += 2 * max_entries;
-  } else if (current_wrapped + max_entries < *largest_reference) {
+  if (current_wrapped >= *required_insert_count + max_entries) {
+    // Required Insert Count wrapped around 1 extra time.
+    *required_insert_count += 2 * max_entries;
+  } else if (current_wrapped + max_entries < *required_insert_count) {
     // Decoder wrapped around 1 extra time.
     current_wrapped += 2 * max_entries;
   }
 
-  if (*largest_reference >
+  if (*required_insert_count >
       std::numeric_limits<uint64_t>::max() - total_number_of_inserts) {
     return false;
   }
 
-  *largest_reference += total_number_of_inserts;
+  *required_insert_count += total_number_of_inserts;
 
-  // Prevent underflow, but also disallow invalid value 0 for Largest Reference.
-  if (current_wrapped >= *largest_reference) {
+  // Prevent underflow, also disallow invalid value 0 for Required Insert Count.
+  if (current_wrapped >= *required_insert_count) {
     return false;
   }
 
-  *largest_reference -= current_wrapped;
+  *required_insert_count -= current_wrapped;
 
   return true;
 }
@@ -118,8 +121,8 @@
     return;
   }
 
-  if (largest_reference_ != largest_reference_seen_) {
-    OnError("Largest Reference too large.");
+  if (required_insert_count_ != required_insert_count_so_far_) {
+    OnError("Required Insert Count too large.");
     return;
   }
 
@@ -164,17 +167,17 @@
       return false;
     }
 
-    if (absolute_index > largest_reference_) {
-      OnError("Index larger than Largest Reference.");
+    if (absolute_index >= required_insert_count_) {
+      OnError("Absolute Index must be smaller than Required Insert Count.");
       return false;
     }
 
-    largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+    DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+    required_insert_count_so_far_ =
+        std::max(required_insert_count_so_far_, absolute_index + 1);
 
-    DCHECK_NE(0u, absolute_index);
-    const uint64_t real_index = absolute_index - 1;
     auto entry =
-        header_table_->LookupEntry(/* is_static = */ false, real_index);
+        header_table_->LookupEntry(/* is_static = */ false, absolute_index);
     if (!entry) {
       OnError("Dynamic table entry not found.");
       return false;
@@ -203,16 +206,17 @@
     return false;
   }
 
-  if (absolute_index > largest_reference_) {
-    OnError("Index larger than Largest Reference.");
+  if (absolute_index >= required_insert_count_) {
+    OnError("Absolute Index must be smaller than Required Insert Count.");
     return false;
   }
 
-  largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+  DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+  required_insert_count_so_far_ =
+      std::max(required_insert_count_so_far_, absolute_index + 1);
 
-  DCHECK_NE(0u, absolute_index);
-  const uint64_t real_index = absolute_index - 1;
-  auto entry = header_table_->LookupEntry(/* is_static = */ false, real_index);
+  auto entry =
+      header_table_->LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
     OnError("Dynamic table entry not found.");
     return false;
@@ -231,17 +235,17 @@
       return false;
     }
 
-    if (absolute_index > largest_reference_) {
-      OnError("Index larger than Largest Reference.");
+    if (absolute_index >= required_insert_count_) {
+      OnError("Absolute Index must be smaller than Required Insert Count.");
       return false;
     }
 
-    largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+    DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+    required_insert_count_so_far_ =
+        std::max(required_insert_count_so_far_, absolute_index + 1);
 
-    DCHECK_NE(0u, absolute_index);
-    const uint64_t real_index = absolute_index - 1;
     auto entry =
-        header_table_->LookupEntry(/* is_static = */ false, real_index);
+        header_table_->LookupEntry(/* is_static = */ false, absolute_index);
     if (!entry) {
       OnError("Dynamic table entry not found.");
       return false;
@@ -270,16 +274,17 @@
     return false;
   }
 
-  if (absolute_index > largest_reference_) {
-    OnError("Index larger than Largest Reference.");
+  if (absolute_index >= required_insert_count_) {
+    OnError("Absolute Index must be smaller than Required Insert Count.");
     return false;
   }
 
-  largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+  DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+  required_insert_count_so_far_ =
+      std::max(required_insert_count_so_far_, absolute_index + 1);
 
-  DCHECK_NE(0u, absolute_index);
-  const uint64_t real_index = absolute_index - 1;
-  auto entry = header_table_->LookupEntry(/* is_static = */ false, real_index);
+  auto entry =
+      header_table_->LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
     OnError("Dynamic table entry not found.");
     return false;
@@ -299,17 +304,17 @@
 bool QpackProgressiveDecoder::DoPrefixInstruction() {
   DCHECK(!prefix_decoded_);
 
-  if (!DecodeLargestReference(
+  if (!DecodeRequiredInsertCount(
           prefix_decoder_->varint(), header_table_->max_entries(),
-          header_table_->inserted_entry_count(), &largest_reference_)) {
-    OnError("Error decoding Largest Reference.");
+          header_table_->inserted_entry_count(), &required_insert_count_)) {
+    OnError("Error decoding Required Insert Count.");
     return false;
   }
 
   const bool sign = prefix_decoder_->s_bit();
-  const uint64_t delta_base_index = prefix_decoder_->varint2();
-  if (!DeltaBaseIndexToBaseIndex(sign, delta_base_index, &base_index_)) {
-    OnError("Error calculating Base Index.");
+  const uint64_t delta_base = prefix_decoder_->varint2();
+  if (!DeltaBaseToBase(sign, delta_base, &base_)) {
+    OnError("Error calculating Base.");
     return false;
   }
 
@@ -318,24 +323,23 @@
   return true;
 }
 
-bool QpackProgressiveDecoder::DeltaBaseIndexToBaseIndex(
-    bool sign,
-    uint64_t delta_base_index,
-    uint64_t* base_index) {
+bool QpackProgressiveDecoder::DeltaBaseToBase(bool sign,
+                                              uint64_t delta_base,
+                                              uint64_t* base) {
   if (sign) {
-    if (delta_base_index == std::numeric_limits<uint64_t>::max() ||
-        largest_reference_ < delta_base_index + 1) {
+    if (delta_base == std::numeric_limits<uint64_t>::max() ||
+        required_insert_count_ < delta_base + 1) {
       return false;
     }
-    *base_index = largest_reference_ - delta_base_index - 1;
+    *base = required_insert_count_ - delta_base - 1;
     return true;
   }
 
-  if (delta_base_index >
-      std::numeric_limits<uint64_t>::max() - largest_reference_) {
+  if (delta_base >
+      std::numeric_limits<uint64_t>::max() - required_insert_count_) {
     return false;
   }
-  *base_index = largest_reference_ + delta_base_index;
+  *base = required_insert_count_ + delta_base;
   return true;
 }
 
@@ -343,22 +347,22 @@
     uint64_t relative_index,
     uint64_t* absolute_index) const {
   if (relative_index == std::numeric_limits<uint64_t>::max() ||
-      relative_index + 1 > base_index_) {
+      relative_index + 1 > base_) {
     return false;
   }
 
-  *absolute_index = base_index_ - relative_index;
+  *absolute_index = base_ - 1 - relative_index;
   return true;
 }
 
 bool QpackProgressiveDecoder::PostBaseIndexToAbsoluteIndex(
     uint64_t post_base_index,
     uint64_t* absolute_index) const {
-  if (post_base_index >= std::numeric_limits<uint64_t>::max() - base_index_) {
+  if (post_base_index >= std::numeric_limits<uint64_t>::max() - base_) {
     return false;
   }
 
-  *absolute_index = base_index_ + post_base_index + 1;
+  *absolute_index = base_ + post_base_index;
   return true;
 }
 
diff --git a/quic/core/qpack/qpack_progressive_decoder.h b/quic/core/qpack/qpack_progressive_decoder.h
index 7524411..7988861 100644
--- a/quic/core/qpack/qpack_progressive_decoder.h
+++ b/quic/core/qpack/qpack_progressive_decoder.h
@@ -56,14 +56,14 @@
   QpackProgressiveDecoder& operator=(const QpackProgressiveDecoder&) = delete;
   ~QpackProgressiveDecoder() override = default;
 
-  // Calculate actual Largest Reference from largest reference value sent on
-  // wire, MaxEntries, and total number of dynamic table insertions according to
-  // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#largest-reference
+  // Calculate Required Insert Count from Encoded Required Insert Count,
+  // MaxEntries, and total number of dynamic table insertions according to
+  // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#ric.
   // Returns true on success, false on invalid input or overflow/underflow.
-  static bool DecodeLargestReference(uint64_t wire_largest_reference,
-                                     uint64_t max_entries,
-                                     uint64_t total_number_of_inserts,
-                                     uint64_t* largest_reference);
+  static bool DecodeRequiredInsertCount(uint64_t encoded_required_insert_count,
+                                        uint64_t max_entries,
+                                        uint64_t total_number_of_inserts,
+                                        uint64_t* required_insert_count);
 
   // Provide a data fragment to decode.
   void Decode(QuicStringPiece data);
@@ -84,19 +84,18 @@
   bool DoLiteralHeaderFieldInstruction();
   bool DoPrefixInstruction();
 
-  // Calculates Base Index from |largest_reference_|, which must be set before
-  // calling this method, and sign bit and Delta Base Index in the Header Data
-  // Prefix, which are passed in as arguments.  Returns true on success, false
-  // on failure due to overflow/underflow.
-  bool DeltaBaseIndexToBaseIndex(bool sign,
-                                 uint64_t delta_base_index,
-                                 uint64_t* base_index);
+  // Calculates Base from |required_insert_count_|, which must be set before
+  // calling this method, and sign bit and Delta Base in the Header Data Prefix,
+  // which are passed in as arguments.  Returns true on success, false on
+  // failure due to overflow/underflow.
+  bool DeltaBaseToBase(bool sign, uint64_t delta_base, uint64_t* base);
 
   // The request stream can use relative index (but different from the kind of
   // relative index used on the encoder stream), and post-base index.
   // These methods convert relative index and post-base index to absolute index
   // (one based).  They return true on success, or false if conversion fails due
-  // to overflow/underflow.
+  // to overflow/underflow.  On success, |*absolute_index| is guaranteed to be
+  // strictly less than std::numeric_limits<uint64_t>::max().
   bool RequestStreamRelativeIndexToAbsoluteIndex(
       uint64_t relative_index,
       uint64_t* absolute_index) const;
@@ -115,14 +114,16 @@
   QpackDecoderStreamSender* const decoder_stream_sender_;
   HeadersHandlerInterface* const handler_;
 
-  // Largest Reference and Base Index are parsed from the Header Data Prefix.
-  // They are both absolute indices, that is, one based.
-  uint64_t largest_reference_;
-  uint64_t base_index_;
+  // Required Insert Count and Base are decoded from the Header Data Prefix.
+  uint64_t required_insert_count_;
+  uint64_t base_;
 
-  // Keep track of largest reference seen in this header block.
-  // After decoding is completed, this can be compared to |largest_reference_|.
-  uint64_t largest_reference_seen_;
+  // Required Insert Count is one larger than the largest absolute index of all
+  // referenced dynamic table entries, or zero if no dynamic table entries are
+  // referenced.  |required_insert_count_so_far_| starts out as zero and keeps
+  // track of the Required Insert Count based on entries decoded so far.
+  // After decoding is completed, it is compared to |required_insert_count_|.
+  uint64_t required_insert_count_so_far_;
 
   // False until prefix is fully read and decoded.
   bool prefix_decoded_;
diff --git a/quic/core/qpack/qpack_progressive_decoder_test.cc b/quic/core/qpack/qpack_progressive_decoder_test.cc
index c1722e5..b306702 100644
--- a/quic/core/qpack/qpack_progressive_decoder_test.cc
+++ b/quic/core/qpack/qpack_progressive_decoder_test.cc
@@ -11,12 +11,12 @@
 namespace test {
 namespace {
 
-// For testing valid decodings, the encoded (wire) largest reference value is
-// calculated for actual Largest Reference values, so that there is an expected
-// value to comparte the decoded value against, and so that intricate
-// inequalities can be documented.
+// For testing valid decodings, the Encoded Required Insert Count is calculated
+// from Required Insert Count, so that there is an expected value to compare
+// the decoded value against, and so that intricate inequalities can be
+// documented.
 struct {
-  uint64_t largest_reference;
+  uint64_t required_insert_count;
   uint64_t max_entries;
   uint64_t total_number_of_inserts;
 } kTestData[] = {
@@ -25,70 +25,72 @@
     // No dynamic entries in header.
     {0, 100, 0},
     {0, 100, 500},
-    // Largest Reference has not wrapped around yet, no entries evicted.
+    // Required Insert Count has not wrapped around yet, no entries evicted.
     {15, 100, 25},
     {20, 100, 10},
-    // Largest Reference has not wrapped around yet, some entries evicted.
+    // Required Insert Count has not wrapped around yet, some entries evicted.
     {90, 100, 110},
-    // Largest Reference has wrapped around.
+    // Required Insert Count has wrapped around.
     {234, 100, 180},
-    // Largest Reference has wrapped around many times.
+    // Required Insert Count has wrapped around many times.
     {5678, 100, 5701},
-    // Lowest and highest possible Largest Reference values
+    // Lowest and highest possible Required Insert Count values
     // for given MaxEntries and total number of insertions.
     {401, 100, 500},
     {600, 100, 500}};
 
-uint64_t EncodeLargestReference(uint64_t largest_reference,
-                                uint64_t max_entries) {
-  if (largest_reference == 0) {
+uint64_t EncodeRequiredInsertCount(uint64_t required_insert_count,
+                                   uint64_t max_entries) {
+  if (required_insert_count == 0) {
     return 0;
   }
 
-  return largest_reference % (2 * max_entries) + 1;
+  return required_insert_count % (2 * max_entries) + 1;
 }
 
-TEST(QpackProgressiveDecoderTest, DecodeLargestReference) {
+TEST(QpackProgressiveDecoderTest, DecodeRequiredInsertCount) {
   for (size_t i = 0; i < QUIC_ARRAYSIZE(kTestData); ++i) {
-    const uint64_t largest_reference = kTestData[i].largest_reference;
+    const uint64_t required_insert_count = kTestData[i].required_insert_count;
     const uint64_t max_entries = kTestData[i].max_entries;
     const uint64_t total_number_of_inserts =
         kTestData[i].total_number_of_inserts;
 
-    if (largest_reference != 0) {
+    if (required_insert_count != 0) {
       // Dynamic entries cannot be referenced if dynamic table capacity is zero.
       ASSERT_LT(0u, max_entries) << i;
-      // Entry |total_number_of_inserts - max_entries| and earlier entries are
-      // evicted.  Entry |largest_reference| is referenced.  No evicted entry
-      // can be referenced.
-      ASSERT_LT(total_number_of_inserts, largest_reference + max_entries) << i;
-      // Entry |largest_reference - max_entries| and earlier entries are
-      // evicted, entry |total_number_of_inserts| is the last acknowledged
+      // Entry |total_number_of_inserts - 1 - max_entries| and earlier entries
+      // are evicted.  Entry |required_insert_count - 1| is referenced.  No
+      // evicted entry can be referenced.
+      ASSERT_LT(total_number_of_inserts, required_insert_count + max_entries)
+          << i;
+      // Entry |required_insert_count - 1 - max_entries| and earlier entries are
+      // evicted, entry |total_number_of_inserts - 1| is the last acknowledged
       // entry.  Every evicted entry must be acknowledged.
-      ASSERT_LE(largest_reference, total_number_of_inserts + max_entries) << i;
+      ASSERT_LE(required_insert_count, total_number_of_inserts + max_entries)
+          << i;
     }
 
-    uint64_t wire_largest_reference =
-        EncodeLargestReference(largest_reference, max_entries);
+    uint64_t encoded_required_insert_count =
+        EncodeRequiredInsertCount(required_insert_count, max_entries);
 
     // Initialize to a value different from the expected output to confirm that
-    // DecodeLargestReference() modifies the value of
-    // |decoded_largest_reference|.
-    uint64_t decoded_largest_reference = largest_reference + 1;
-    EXPECT_TRUE(QpackProgressiveDecoder::DecodeLargestReference(
-        wire_largest_reference, max_entries, total_number_of_inserts,
-        &decoded_largest_reference))
+    // DecodeRequiredInsertCount() modifies the value of
+    // |decoded_required_insert_count|.
+    uint64_t decoded_required_insert_count = required_insert_count + 1;
+    EXPECT_TRUE(QpackProgressiveDecoder::DecodeRequiredInsertCount(
+        encoded_required_insert_count, max_entries, total_number_of_inserts,
+        &decoded_required_insert_count))
         << i;
 
-    EXPECT_EQ(decoded_largest_reference, largest_reference) << i;
+    EXPECT_EQ(decoded_required_insert_count, required_insert_count) << i;
   }
 }
 
-// Failures are tested with hardcoded values for the on-the-wire largest
-// reference field, to provide test coverage for values that would never be
-// produced by a well behaved encoding function.
+// Failures are tested with hardcoded values for encoded required insert count,
+// to provide test coverage for values that would never be produced by a well
+// behaved encoding function.
 struct {
-  uint64_t wire_largest_reference;
+  uint64_t encoded_required_insert_count;
   uint64_t max_entries;
   uint64_t total_number_of_inserts;
 } kInvalidTestData[] = {
@@ -100,19 +102,19 @@
     // https://github.com/quicwg/base-drafts/issues/2112#issue-389626872.
     {1, 10, 2},
     {18, 10, 2},
-    // Largest Reference value too small or too large
+    // Encoded Required Insert Count value too small or too large
     // for given MaxEntries and total number of insertions.
     {400, 100, 500},
     {601, 100, 500}};
 
-TEST(QpackProgressiveDecoderTest, DecodeLargestReferenceError) {
+TEST(QpackProgressiveDecoderTest, DecodeRequiredInsertCountError) {
   for (size_t i = 0; i < QUIC_ARRAYSIZE(kInvalidTestData); ++i) {
-    uint64_t decoded_largest_reference = 0;
-    EXPECT_FALSE(QpackProgressiveDecoder::DecodeLargestReference(
-        kInvalidTestData[i].wire_largest_reference,
+    uint64_t decoded_required_insert_count = 0;
+    EXPECT_FALSE(QpackProgressiveDecoder::DecodeRequiredInsertCount(
+        kInvalidTestData[i].encoded_required_insert_count,
         kInvalidTestData[i].max_entries,
         kInvalidTestData[i].total_number_of_inserts,
-        &decoded_largest_reference))
+        &decoded_required_insert_count))
         << i;
   }
 }
diff --git a/quic/core/qpack/qpack_progressive_encoder.cc b/quic/core/qpack/qpack_progressive_encoder.cc
index 4d2a3cf..41433ff 100644
--- a/quic/core/qpack/qpack_progressive_encoder.cc
+++ b/quic/core/qpack/qpack_progressive_encoder.cc
@@ -48,8 +48,8 @@
   DCHECK_LT(output->size(), max_length);
 
   if (!prefix_encoded_ && !instruction_encoder_.HasNext()) {
-    // TODO(bnc): Implement dynamic entries and set Largest Reference and
-    // Delta Base Index accordingly.
+    // TODO(bnc): Implement dynamic entries and set Required Insert Count and
+    // Delta Base accordingly.
     instruction_encoder_.set_varint(0);
     instruction_encoder_.set_varint2(0);
     instruction_encoder_.set_s_bit(false);
diff --git a/quic/core/quic_buffered_packet_store_test.cc b/quic/core/quic_buffered_packet_store_test.cc
index 027a26c..e214ff1 100644
--- a/quic/core/quic_buffered_packet_store_test.cc
+++ b/quic/core/quic_buffered_packet_store_test.cc
@@ -6,6 +6,7 @@
 
 #include <list>
 
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -53,7 +54,7 @@
         packet_content_("some encrypted content"),
         packet_time_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(42)),
         packet_(packet_content_.data(), packet_content_.size(), packet_time_),
-        invalid_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+        invalid_version_(UnsupportedQuicVersion()),
         valid_version_(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44) {}
 
  protected:
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index f3a6767..d4c13c4 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -23,6 +23,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_config.h"
 #include "net/third_party/quiche/src/quic/core/quic_packet_generator.h"
 #include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
@@ -42,10 +43,6 @@
 
 namespace {
 
-// The largest gap in packets we'll accept without closing the connection.
-// This will likely have to be tuned.
-const QuicPacketNumber kMaxPacketGap = 5000;
-
 // Maximum number of acks received before sending an ack in response.
 // TODO(fayang): Remove this constant when deprecating QUIC_VERSION_35.
 const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20;
@@ -74,7 +71,7 @@
 const int kMinReleaseTimeIntoFutureMs = 1;
 
 bool Near(QuicPacketNumber a, QuicPacketNumber b) {
-  QuicPacketNumber delta = (a > b) ? a - b : b - a;
+  QuicPacketCount delta = (a > b) ? a - b : b - a;
   return delta <= kMaxPacketGap;
 }
 
@@ -244,15 +241,12 @@
       peer_address_(initial_peer_address),
       direct_peer_address_(initial_peer_address),
       active_effective_peer_migration_type_(NO_CHANGE),
-      highest_packet_sent_before_effective_peer_migration_(0),
       last_packet_decrypted_(false),
       last_size_(0),
       current_packet_data_(nullptr),
       last_decrypted_packet_level_(ENCRYPTION_NONE),
       should_last_packet_instigate_acks_(false),
       was_last_packet_missing_(false),
-      largest_seen_packet_with_ack_(0),
-      largest_seen_packet_with_stop_waiting_(0),
       max_undecryptable_packets_(0),
       max_tracked_packets_(kMaxTrackedPackets),
       pending_version_negotiation_packet_(false),
@@ -344,10 +338,9 @@
       processing_ack_frame_(false),
       supports_release_time_(false),
       release_time_into_future_(QuicTime::Delta::Zero()),
-      donot_retransmit_old_window_updates_(false),
       no_version_negotiation_(supported_versions.size() == 1),
-      decrypt_packets_on_key_change_(
-          GetQuicReloadableFlag(quic_decrypt_packets_on_key_change)) {
+      clear_probing_mark_after_packet_processing_(GetQuicReloadableFlag(
+          quic_clear_probing_mark_after_packet_processing)) {
   if (ack_mode_ == ACK_DECIMATION) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_enable_ack_decimation);
   }
@@ -359,10 +352,12 @@
                   << "Created connection with connection_id: " << connection_id
                   << " and version: "
                   << QuicVersionToString(transport_version());
-  QUIC_BUG_IF(connection_id.length() != sizeof(uint64_t) &&
-              transport_version() < QUIC_VERSION_99)
-      << "Cannot use connection ID of length " << connection_id.length()
-      << " with version " << QuicVersionToString(transport_version());
+
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(connection_id,
+                                                        transport_version()))
+      << "QuicConnection: attempted to use connection ID " << connection_id
+      << " which is invalid with version "
+      << QuicVersionToString(transport_version());
 
   framer_.set_visitor(this);
   stats_.connection_creation_time = clock_->ApproximateNow();
@@ -441,16 +436,24 @@
   if (config.HasClientSentConnectionOption(kACKD, perspective_)) {
     ack_mode_ = ACK_DECIMATION;
   }
-  if (!GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+  if ((!GetQuicReloadableFlag(quic_enable_ack_decimation) ||
+       GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) &&
       config.HasClientSentConnectionOption(kAKD2, perspective_)) {
+    if (GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_keep_ack_decimation_reordering, 1, 2);
+    }
     ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
   }
   if (config.HasClientSentConnectionOption(kAKD3, perspective_)) {
     ack_mode_ = ACK_DECIMATION;
     ack_decimation_delay_ = kShortAckDecimationDelay;
   }
-  if (!GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+  if ((!GetQuicReloadableFlag(quic_enable_ack_decimation) ||
+       GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) &&
       config.HasClientSentConnectionOption(kAKD4, perspective_)) {
+    if (GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_keep_ack_decimation_reordering, 2, 2);
+    }
     ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
     ack_decimation_delay_ = kShortAckDecimationDelay;
   }
@@ -782,7 +785,7 @@
       // Packets should have the version flag till version negotiation is
       // done.
       QuicString error_details =
-          QuicStrCat(ENDPOINT, "Packet ", header.packet_number,
+          QuicStrCat(ENDPOINT, "Packet ", header.packet_number.ToUint64(),
                      " without version flag before version negotiated.");
       QUIC_DLOG(WARNING) << error_details;
       CloseConnection(QUIC_INVALID_VERSION, error_details,
@@ -840,7 +843,8 @@
   current_effective_peer_migration_type_ = NO_CHANGE;
 
   if (perspective_ == Perspective::IS_CLIENT) {
-    if (header.packet_number > received_packet_manager_.GetLargestObserved()) {
+    if (!received_packet_manager_.GetLargestObserved().IsInitialized() ||
+        header.packet_number > received_packet_manager_.GetLargestObserved()) {
       // Update peer_address_ and effective_peer_address_ immediately for
       // client connections.
       direct_peer_address_ = last_packet_source_address_;
@@ -944,22 +948,25 @@
   QUIC_DVLOG(1) << ENDPOINT
                 << "OnAckFrameStart, largest_acked: " << largest_acked;
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
 
-  if (largest_acked > sent_packet_manager_.GetLargestSentPacket()) {
+  if (!sent_packet_manager_.GetLargestSentPacket().IsInitialized() ||
+      largest_acked > sent_packet_manager_.GetLargestSentPacket()) {
     QUIC_DLOG(WARNING) << ENDPOINT
                        << "Peer's observed unsent packet:" << largest_acked
                        << " vs " << sent_packet_manager_.GetLargestSentPacket();
-    // We got an error for data we have not sent.
+    // We got an ack for data we have not sent.
     CloseConnection(QUIC_INVALID_ACK_DATA, "Largest observed too high.",
                     ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
     return false;
   }
 
-  if (largest_acked > sent_packet_manager_.GetLargestObserved()) {
+  if (!sent_packet_manager_.GetLargestObserved().IsInitialized() ||
+      largest_acked > sent_packet_manager_.GetLargestObserved()) {
     visitor_->OnForwardProgressConfirmed();
   } else if (largest_acked < sent_packet_manager_.GetLargestObserved()) {
     QUIC_LOG(INFO) << ENDPOINT << "Peer's largest_observed packet decreased:"
@@ -984,7 +991,8 @@
   DCHECK(connected_);
   QUIC_DVLOG(1) << ENDPOINT << "OnAckRange: [" << start << ", " << end << ")";
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
@@ -999,7 +1007,8 @@
   QUIC_DVLOG(1) << ENDPOINT << "OnAckTimestamp: [" << packet_number << ", "
                 << timestamp.ToDebuggingValue() << ")";
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
@@ -1012,7 +1021,8 @@
   DCHECK(connected_);
   QUIC_DVLOG(1) << ENDPOINT << "OnAckFrameEnd, start: " << start;
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
@@ -1051,7 +1061,8 @@
   if (no_stop_waiting_frames_) {
     return true;
   }
-  if (last_header_.packet_number <= largest_seen_packet_with_stop_waiting_) {
+  if (largest_seen_packet_with_stop_waiting_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_stop_waiting_) {
     QUIC_DLOG(INFO) << ENDPOINT
                     << "Received an old stop waiting frame: ignoring";
     return true;
@@ -1129,8 +1140,10 @@
 
 const char* QuicConnection::ValidateStopWaitingFrame(
     const QuicStopWaitingFrame& stop_waiting) {
-  if (stop_waiting.least_unacked <
-      received_packet_manager_.peer_least_packet_awaiting_ack()) {
+  if (received_packet_manager_.peer_least_packet_awaiting_ack()
+          .IsInitialized() &&
+      stop_waiting.least_unacked <
+          received_packet_manager_.peer_least_packet_awaiting_ack()) {
     QUIC_DLOG(ERROR)
         << ENDPOINT
         << "Peer's sent low least_unacked: " << stop_waiting.least_unacked
@@ -1179,7 +1192,22 @@
 }
 
 bool QuicConnection::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
-  return visitor_->OnStopSendingFrame(frame);
+  DCHECK(connected_);
+
+  // Since a reset stream frame was received, this is not a connectivity probe.
+  // A probe only contains a PING and full padding.
+  UpdatePacketContent(NOT_PADDED_PING);
+
+  if (debug_visitor_ != nullptr) {
+    debug_visitor_->OnStopSendingFrame(frame);
+  }
+
+  QUIC_DLOG(INFO) << ENDPOINT << "STOP_SENDING frame received for stream: "
+                  << frame.stream_id
+                  << " with error: " << frame.application_error_code;
+
+  visitor_->OnStopSendingFrame(frame);
+  return connected_;
 }
 
 bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
@@ -1439,8 +1467,10 @@
   if (was_missing) {
     // Only ack immediately if an ACK frame was sent with a larger
     // largest acked than the newly received packet number.
-    if (last_header_.packet_number <
-        sent_packet_manager_.unacked_packets().largest_sent_largest_acked()) {
+    const QuicPacketNumber largest_sent_largest_acked =
+        sent_packet_manager_.unacked_packets().largest_sent_largest_acked();
+    if (largest_sent_largest_acked.IsInitialized() &&
+        last_header_.packet_number < largest_sent_largest_acked) {
       ack_queued_ = true;
     }
   }
@@ -1448,7 +1478,10 @@
   if (should_last_packet_instigate_acks_ && !ack_queued_) {
     ++num_retransmittable_packets_received_since_last_ack_sent_;
     if (ack_mode_ != TCP_ACKING &&
-        last_header_.packet_number > min_received_before_ack_decimation_) {
+        // TODO(fayang): Fix this as this check assumes the first received
+        // packet is 1.
+        last_header_.packet_number >
+            QuicPacketNumber(min_received_before_ack_decimation_)) {
       // Ack up to 10 packets at once unless ack decimation is unlimited.
       if (!unlimited_ack_decimation_ &&
           num_retransmittable_packets_received_since_last_ack_sent_ >=
@@ -1497,7 +1530,8 @@
     // If there are new missing packets to report, send an ack immediately.
     if (received_packet_manager_.HasNewMissingPackets()) {
       if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) {
-        DCHECK(!GetQuicReloadableFlag(quic_enable_ack_decimation));
+        DCHECK(!GetQuicReloadableFlag(quic_enable_ack_decimation) ||
+               GetQuicReloadableFlag(quic_keep_ack_decimation_reordering));
         // Wait the minimum of an eighth min_rtt and the existing ack time.
         QuicTime ack_time =
             clock_->ApproximateNow() +
@@ -1527,8 +1561,9 @@
 void QuicConnection::CloseIfTooManyOutstandingSentPackets() {
   // This occurs if we don't discard old packets we've seen fast enough. It's
   // possible largest observed is less than leaset unacked.
-  if (sent_packet_manager_.GetLargestObserved() >
-      sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_) {
+  if (sent_packet_manager_.GetLargestObserved().IsInitialized() &&
+      sent_packet_manager_.GetLargestObserved() >
+          sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_) {
     CloseConnection(
         QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
         QuicStrCat("More than ", max_tracked_packets_, " outstanding."),
@@ -1602,9 +1637,9 @@
     OnWriteError(result.error_code);
     return;
   }
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     visitor_->OnWriteBlocked();
-    if (writer_->IsWriteBlockedDataBuffered()) {
+    if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
       pending_version_negotiation_packet_ = false;
     }
     return;
@@ -1676,6 +1711,8 @@
       ++packet_iterator;
       continue;
     }
+    // NOTE THAT RemoveFramesForStream removes only STREAM frames
+    // for the specified stream.
     RemoveFramesForStream(retransmittable_frames, id);
     if (!retransmittable_frames->empty()) {
       ++packet_iterator;
@@ -1776,6 +1813,13 @@
                   << "Unable to process packet.  Last packet processed: "
                   << last_header_.packet_number;
     current_packet_data_ = nullptr;
+    if (clear_probing_mark_after_packet_processing_) {
+      if (is_current_packet_connectivity_probing_) {
+        QUIC_RELOADABLE_FLAG_COUNT_N(
+            quic_clear_probing_mark_after_packet_processing, 1, 2);
+      }
+      is_current_packet_connectivity_probing_ = false;
+    }
     return;
   }
 
@@ -1787,8 +1831,10 @@
       << ", highest_packet_sent_before_effective_peer_migration_ = "
       << highest_packet_sent_before_effective_peer_migration_;
   if (active_effective_peer_migration_type_ != NO_CHANGE &&
-      sent_packet_manager_.GetLargestObserved() >
-          highest_packet_sent_before_effective_peer_migration_) {
+      sent_packet_manager_.GetLargestObserved().IsInitialized() &&
+      (!highest_packet_sent_before_effective_peer_migration_.IsInitialized() ||
+       sent_packet_manager_.GetLargestObserved() >
+           highest_packet_sent_before_effective_peer_migration_)) {
     if (perspective_ == Perspective::IS_SERVER) {
       OnEffectivePeerMigrationValidated();
     }
@@ -1798,6 +1844,13 @@
   MaybeSendInResponseToPacket();
   SetPingAlarm();
   current_packet_data_ = nullptr;
+  if (clear_probing_mark_after_packet_processing_) {
+    if (is_current_packet_connectivity_probing_) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(
+          quic_clear_probing_mark_after_packet_processing, 2, 2);
+    }
+    is_current_packet_connectivity_probing_ = false;
+  }
 }
 
 void QuicConnection::OnBlockedWriterCanWrite() {
@@ -1883,7 +1936,7 @@
     QUIC_RESTART_FLAG_COUNT_N(quic_enable_accept_random_ipn, 2, 2);
     // Configured to accept any packet number in range 1...0x7fffffff
     // as initial packet number.
-    if (last_header_.packet_number != kInvalidPacketNumber) {
+    if (last_header_.packet_number.IsInitialized()) {
       // The last packet's number is not 0. Ensure that this packet
       // is reasonably close to where it should be.
       if (!Near(header.packet_number, last_header_.packet_number)) {
@@ -1896,10 +1949,9 @@
       }
     } else {
       // The "last packet's number" is 0, meaning that this packet is the first
-      // one received. Ensure it is in range 1..kMaxRandomInitialPacketNumber,
+      // one received. Ensure it is in range 1..MaxRandomInitialPacketNumber(),
       // inclusive.
-      if ((header.packet_number == kInvalidPacketNumber) ||
-          (header.packet_number > kMaxRandomInitialPacketNumber)) {
+      if ((header.packet_number > MaxRandomInitialPacketNumber())) {
         // packet number is bad.
         QUIC_DLOG(INFO) << ENDPOINT << "Initial packet " << header.packet_number
                         << " out of bounds.  Discarding";
@@ -1913,21 +1965,29 @@
     // Count those that would have been accepted if FLAGS..random_ipn
     // were true -- to detect/diagnose potential issues prior to
     // enabling the flag.
-    if ((header.packet_number > 1) &&
-        (header.packet_number <= kMaxRandomInitialPacketNumber)) {
+    if ((header.packet_number > QuicPacketNumber(1)) &&
+        (header.packet_number <= MaxRandomInitialPacketNumber())) {
       QUIC_CODE_COUNT_N(had_possibly_random_ipn, 2, 2);
     }
-
-    if (!Near(header.packet_number, last_header_.packet_number)) {
+    bool out_of_bound =
+        last_header_.packet_number.IsInitialized()
+            ? !Near(header.packet_number, last_header_.packet_number)
+            // TODO(fayang): Fix this as this check assume the first received
+            // packet is 1.
+            : header.packet_number > QuicPacketNumber(kMaxPacketGap);
+    if (out_of_bound) {
       QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number
                       << " out of bounds.  Discarding";
       QuicStringPiece packet_data = GetCurrentPacket();
       const size_t kMaxPacketLengthInErrorDetails = 64;
       CloseConnection(
           QUIC_INVALID_PACKET_HEADER,
-          QuicStrCat("Packet number out of bounds. last_pkn=",
-                     last_header_.packet_number,
-                     ", current_pkn=", header.packet_number,
+          QuicStrCat("Packet number out of bounds. ",
+                     last_header_.packet_number.IsInitialized()
+                         ? QuicStrCat("last_pkn=",
+                                      last_header_.packet_number.ToUint64())
+                         : "first received packet",
+                     ", current_pkn=", header.packet_number.ToUint64(),
                      ", current_pkt_len=", packet_data.length(),
                      ", current_hdr=",
                      QuicTextUtils::HexEncode(
@@ -2127,7 +2187,8 @@
     ++stats_.packets_discarded;
     return true;
   }
-  if (packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) {
+  if (sent_packet_manager_.GetLargestSentPacket().IsInitialized() &&
+      packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) {
     QUIC_BUG << "Attempt to write packet:" << packet->packet_number
              << " after:" << sent_packet_manager_.GetLargestSentPacket();
     CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.",
@@ -2198,7 +2259,7 @@
       WRITE_STATUS_NUM_VALUES,
       "Status code returned by writer_->WritePacket() in QuicConnection.");
 
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     // Ensure the writer is still write blocked, otherwise QUIC may continue
     // trying to write when it will not be able to.
     DCHECK(writer_->IsWriteBlocked());
@@ -2207,7 +2268,7 @@
     // be queued and sent again, which would result in an unnecessary
     // duplicate packet being sent.  The helper must call OnCanWrite
     // when the write completes, and OnWriteError if an error occurs.
-    if (!writer_->IsWriteBlockedDataBuffered()) {
+    if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
       return false;
     }
   }
@@ -2314,6 +2375,14 @@
   }
 
   WriteResult result = writer_->Flush();
+
+  if (HandleWriteBlocked()) {
+    DCHECK_EQ(WRITE_STATUS_BLOCKED, result.status)
+        << "Unexpected flush result:" << result;
+    QUIC_DLOG(INFO) << ENDPOINT << "Write blocked in FlushPackets.";
+    return;
+  }
+
   if (IsWriteError(result.status)) {
     OnWriteError(result.error_code);
   }
@@ -2402,7 +2471,7 @@
 
   if (transport_version() != QUIC_VERSION_35) {
     if (serialized_packet->retransmittable_frames.empty() &&
-        serialized_packet->original_packet_number == kInvalidPacketNumber) {
+        !serialized_packet->original_packet_number.IsInitialized()) {
       // Increment consecutive_num_packets_with_no_retransmittable_frames_ if
       // this packet is a new transmission with no retransmittable frames.
       ++consecutive_num_packets_with_no_retransmittable_frames_;
@@ -2496,8 +2565,7 @@
   }
   consecutive_num_packets_with_no_retransmittable_frames_ = 0;
   if (packet_generator_.HasRetransmittableFrames() ||
-      (donot_retransmit_old_window_updates_ &&
-       visitor_->WillingAndAbleToWrite())) {
+      visitor_->WillingAndAbleToWrite()) {
     // There are pending retransmittable frames.
     return;
   }
@@ -2569,11 +2637,7 @@
 void QuicConnection::SetDecrypter(EncryptionLevel level,
                                   std::unique_ptr<QuicDecrypter> decrypter) {
   framer_.SetDecrypter(level, std::move(decrypter));
-  if (!decrypt_packets_on_key_change_) {
-    return;
-  }
 
-  QUIC_RELOADABLE_FLAG_COUNT_N(quic_decrypt_packets_on_key_change, 1, 3);
   if (!undecryptable_packets_.empty() &&
       !process_undecryptable_packets_alarm_->IsSet()) {
     process_undecryptable_packets_alarm_->Set(clock_->ApproximateNow());
@@ -2585,11 +2649,7 @@
     std::unique_ptr<QuicDecrypter> decrypter,
     bool latch_once_used) {
   framer_.SetAlternativeDecrypter(level, std::move(decrypter), latch_once_used);
-  if (!decrypt_packets_on_key_change_) {
-    return;
-  }
 
-  QUIC_RELOADABLE_FLAG_COUNT_N(quic_decrypt_packets_on_key_change, 2, 3);
   if (!undecryptable_packets_.empty() &&
       !process_undecryptable_packets_alarm_->IsSet()) {
     process_undecryptable_packets_alarm_->Set(clock_->ApproximateNow());
@@ -2611,10 +2671,7 @@
 }
 
 void QuicConnection::MaybeProcessUndecryptablePackets() {
-  if (decrypt_packets_on_key_change_) {
-    QUIC_RELOADABLE_FLAG_COUNT_N(quic_decrypt_packets_on_key_change, 3, 3);
-    process_undecryptable_packets_alarm_->Cancel();
-  }
+  process_undecryptable_packets_alarm_->Cancel();
 
   if (undecryptable_packets_.empty() || encryption_level_ == ENCRYPTION_NONE) {
     return;
@@ -3071,6 +3128,9 @@
   packet_generator_.GenerateMtuDiscoveryPacket(target_mtu);
 }
 
+// TODO(zhongyi): change this method to generate a connectivity probing packet
+// and let the caller to call writer to write the packet and handle write
+// status.
 bool QuicConnection::SendConnectivityProbingPacket(
     QuicPacketWriter* probing_writer,
     const QuicSocketAddress& peer_address) {
@@ -3186,13 +3246,13 @@
       packet_send_time, probing_packet->transmission_type,
       NO_RETRANSMITTABLE_DATA);
 
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     if (probing_writer == writer_) {
       // Visitor should not be write blocked if the probing writer is not the
       // default packet writer.
       visitor_->OnWriteBlocked();
     }
-    if (probing_writer->IsWriteBlockedDataBuffered()) {
+    if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
       QUIC_DLOG(INFO) << ENDPOINT << "Write probing packet blocked";
     }
   }
@@ -3228,7 +3288,7 @@
     QUIC_BUG << "No migration underway.";
     return;
   }
-  highest_packet_sent_before_effective_peer_migration_ = 0;
+  highest_packet_sent_before_effective_peer_migration_.Clear();
   active_effective_peer_migration_type_ = NO_CHANGE;
 }
 
@@ -3382,8 +3442,9 @@
   }
 
   current_packet_content_ = NOT_PADDED_PING;
-  if (last_header_.packet_number ==
-      received_packet_manager_.GetLargestObserved()) {
+  if (received_packet_manager_.GetLargestObserved().IsInitialized() &&
+      last_header_.packet_number ==
+          received_packet_manager_.GetLargestObserved()) {
     direct_peer_address_ = last_packet_source_address_;
     if (current_effective_peer_migration_type_ != NO_CHANGE) {
       // Start effective peer migration immediately when the current packet is
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 0f50e96..221754f 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -297,6 +297,9 @@
   // Called when RTT may have changed, including when an RTT is read from
   // the config.
   virtual void OnRttChanged(QuicTime::Delta rtt) const {}
+
+  // Called when a StopSendingFrame has been parsed.
+  virtual void OnStopSendingFrame(const QuicStopSendingFrame& frame) {}
 };
 
 class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface {
@@ -792,6 +795,20 @@
     fill_up_link_during_probing_ = new_value;
   }
 
+  // This setting may be changed during the crypto handshake in order to
+  // enable/disable padding of different packets in the crypto handshake.
+  //
+  // This setting should never be set to false in public facing endpoints. It
+  // can only be set to false if there is some other mechanism of preventing
+  // amplification attacks, such as ICE (plus its a non-standard quic).
+  void set_fully_pad_crypto_hadshake_packets(bool new_value) {
+    packet_generator_.set_fully_pad_crypto_hadshake_packets(new_value);
+  }
+
+  bool fully_pad_during_crypto_handshake() const {
+    return packet_generator_.fully_pad_crypto_handshake_packets();
+  }
+
   size_t min_received_before_ack_decimation() const {
     return min_received_before_ack_decimation_;
   }
@@ -803,7 +820,7 @@
     return ack_frequency_before_ack_decimation_;
   }
   void set_ack_frequency_before_ack_decimation(size_t new_value) {
-    DCHECK_GT(new_value, 0);
+    DCHECK_GT(new_value, 0u);
     ack_frequency_before_ack_decimation_ = new_value;
   }
 
@@ -827,20 +844,9 @@
 
   bool IsPathDegrading() const { return is_path_degrading_; }
 
-  // TODO(wub): Remove this function once
-  // quic_donot_retransmit_old_window_update flag is deprecated.
-  void set_donot_retransmit_old_window_updates(bool value) {
-    donot_retransmit_old_window_updates_ = value;
-  }
-
   // Attempts to process any queued undecryptable packets.
   void MaybeProcessUndecryptablePackets();
 
-  // Whether the handshake is confirmed from this connection's perspective.
-  bool IsHandshakeConfirmed() const {
-    return sent_packet_manager_.handshake_confirmed();
-  }
-
   enum PacketContent : uint8_t {
     NO_FRAMES_RECEIVED,
     // TODO(fkastenholz): Change name when we get rid of padded ping/
@@ -851,6 +857,11 @@
     NOT_PADDED_PING,  // Set if the packet is not {PING, PADDING}.
   };
 
+  // Whether the handshake is confirmed from this connection's perspective.
+  bool IsHandshakeConfirmed() const {
+    return sent_packet_manager_.handshake_confirmed();
+  }
+
  protected:
   // Calls cancel() on all the alarms owned by this connection.
   void CancelAllAlarms();
@@ -1076,10 +1087,9 @@
   // Contents received in the current packet, especially used to identify
   // whether the current packet is a padded PING packet.
   PacketContent current_packet_content_;
-  // True if the packet currently being processed is a connectivity probing
-  // packet. Is set to false when a new packet is received, and will be set to
-  // true as soon as |current_packet_content_| is set to
-  // SECOND_FRAME_IS_PADDING.
+  // Set to true as soon as the packet currently being processed has been
+  // detected as a connectivity probing.
+  // Always false outside the context of ProcessUdpPacket().
   bool is_current_packet_connectivity_probing_;
 
   // Caches the current effective peer migration type if a effective peer
@@ -1385,16 +1395,13 @@
   // Time this connection can release packets into the future.
   QuicTime::Delta release_time_into_future_;
 
-  // Latched value of quic_donot_retransmit_old_window_update flag.
-  bool donot_retransmit_old_window_updates_;
-
   // Indicates whether server connection does version negotiation. Server
   // connection does not support version negotiation if a single version is
   // provided in constructor.
   const bool no_version_negotiation_;
 
-  // Latched value of quic_decrypt_packets_on_key_change flag.
-  const bool decrypt_packets_on_key_change_;
+  // Latched value of --quic_clear_probing_mark_after_packet_processing.
+  const bool clear_probing_mark_after_packet_processing_;
 
   // Payload of most recently transmitted QUIC_VERSION_99 connectivity
   // probe packet (the PATH_CHALLENGE payload). This implementation transmits
diff --git a/quic/core/quic_connection_stats.h b/quic/core/quic_connection_stats.h
index 07ca80f..8123fb0 100644
--- a/quic/core/quic_connection_stats.h
+++ b/quic/core/quic_connection_stats.h
@@ -73,7 +73,7 @@
   // Number of packets received out of packet number order.
   QuicPacketCount packets_reordered;
   // Maximum reordering observed in packet number space.
-  QuicPacketNumber max_sequence_reordering;
+  QuicPacketCount max_sequence_reordering;
   // Maximum reordering observed in microseconds
   int64_t max_time_reordering_us;
 
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 63f4453..fe851fd 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -17,6 +17,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -102,7 +103,7 @@
   bool SetIV(QuicStringPiece iv) override { return true; }
 
   bool EncryptPacket(QuicTransportVersion /*version*/,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
@@ -167,7 +168,7 @@
   }
 
   bool DecryptPacket(QuicTransportVersion /*version*/,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
@@ -288,6 +289,7 @@
         last_packet_size_(0),
         write_blocked_(false),
         write_should_fail_(false),
+        block_on_next_flush_(false),
         block_on_next_write_(false),
         next_packet_too_large_(false),
         always_get_packet_too_large_(false),
@@ -336,11 +338,14 @@
       return WriteResult(WRITE_STATUS_ERROR, EMSGSIZE);
     }
     if (IsWriteBlocked()) {
-      return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+      return WriteResult(is_write_blocked_data_buffered_
+                             ? WRITE_STATUS_BLOCKED_DATA_BUFFERED
+                             : WRITE_STATUS_BLOCKED,
+                         0);
     }
 
     if (ShouldWriteFail()) {
-      return WriteResult(WRITE_STATUS_ERROR, EAGAIN);
+      return WriteResult(WRITE_STATUS_ERROR, 0);
     }
 
     last_packet_size_ = packet.length();
@@ -380,7 +385,16 @@
     return nullptr;
   }
 
-  WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
+  WriteResult Flush() override {
+    if (block_on_next_flush_) {
+      block_on_next_flush_ = false;
+      SetWriteBlocked();
+      return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1);
+    }
+    return WriteResult(WRITE_STATUS_OK, 0);
+  }
+
+  void BlockOnNextFlush() { block_on_next_flush_ = true; }
 
   void BlockOnNextWrite() { block_on_next_write_ = true; }
 
@@ -493,6 +507,8 @@
     supports_release_time_ = supports_release_time;
   }
 
+  SimpleQuicFramer* framer() { return &framer_; }
+
  private:
   ParsedQuicVersion version_;
   SimpleQuicFramer framer_;
@@ -500,6 +516,7 @@
   QuicPacketHeader last_packet_header_;
   bool write_blocked_;
   bool write_should_fail_;
+  bool block_on_next_flush_;
   bool block_on_next_write_;
   bool next_packet_too_large_;
   bool always_get_packet_too_large_;
@@ -554,7 +571,7 @@
   }
 
   void SendPacket(EncryptionLevel level,
-                  QuicPacketNumber packet_number,
+                  uint64_t packet_number,
                   std::unique_ptr<QuicPacket> packet,
                   HasRetransmittableData retransmittable,
                   bool has_ack,
@@ -562,10 +579,11 @@
     char buffer[kMaxPacketSize];
     size_t encrypted_length =
         QuicConnectionPeer::GetFramer(this)->EncryptPayload(
-            ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize);
+            ENCRYPTION_NONE, QuicPacketNumber(packet_number), *packet, buffer,
+            kMaxPacketSize);
     SerializedPacket serialized_packet(
-        packet_number, PACKET_4BYTE_PACKET_NUMBER, buffer, encrypted_length,
-        has_ack, has_pending_frames);
+        QuicPacketNumber(packet_number), PACKET_4BYTE_PACKET_NUMBER, buffer,
+        encrypted_length, has_ack, has_pending_frames);
     if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
       serialized_packet.retransmittable_frames.push_back(
           QuicFrame(QuicStreamFrame()));
@@ -580,7 +598,7 @@
                                          QuicStreamOffset offset,
                                          StreamSendingState state) {
     ScopedPacketFlusher flusher(this, NO_ACK);
-    producer_.SaveStreamData(id, iov, iov_count, 0u, offset, total_length);
+    producer_.SaveStreamData(id, iov, iov_count, 0u, total_length);
     if (notifier_ != nullptr) {
       return notifier_->WriteOrBufferData(id, total_length, state);
     }
@@ -902,14 +920,14 @@
 
   QuicPacketNumber least_unacked() {
     if (writer_->stop_waiting_frames().empty()) {
-      return 0;
+      return QuicPacketNumber();
     }
     return writer_->stop_waiting_frames()[0].least_unacked;
   }
 
   void use_tagging_decrypter() { writer_->use_tagging_decrypter(); }
 
-  void ProcessPacket(QuicPacketNumber number) {
+  void ProcessPacket(uint64_t number) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacket(number);
     if (connection_.GetSendAlarm()->IsSet()) {
@@ -984,7 +1002,7 @@
         QuicReceivedPacket(encrypted_buffer, encrypted_length, clock_.Now()));
   }
 
-  size_t ProcessFramePacketAtLevel(QuicPacketNumber number,
+  size_t ProcessFramePacketAtLevel(uint64_t number,
                                    QuicFrame frame,
                                    EncryptionLevel level) {
     QuicPacketHeader header;
@@ -995,32 +1013,43 @@
         peer_framer_.perspective() == Perspective::IS_SERVER) {
       header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
     }
-    header.packet_number = number;
+    header.packet_number = QuicPacketNumber(number);
     QuicFrames frames;
     frames.push_back(frame);
     std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
 
     char buffer[kMaxPacketSize];
-    size_t encrypted_length =
-        framer_.EncryptPayload(level, number, *packet, buffer, kMaxPacketSize);
+    size_t encrypted_length = framer_.EncryptPayload(
+        level, QuicPacketNumber(number), *packet, buffer, kMaxPacketSize);
     connection_.ProcessUdpPacket(
         kSelfAddress, kPeerAddress,
         QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
     return encrypted_length;
   }
 
-  size_t ProcessDataPacket(QuicPacketNumber number) {
+  size_t ProcessDataPacket(uint64_t number) {
     return ProcessDataPacketAtLevel(number, false, ENCRYPTION_NONE);
   }
 
-  size_t ProcessDataPacketAtLevel(QuicPacketNumber number,
+  size_t ProcessDataPacket(QuicPacketNumber packet_number) {
+    return ProcessDataPacketAtLevel(packet_number, false, ENCRYPTION_NONE);
+  }
+
+  size_t ProcessDataPacketAtLevel(QuicPacketNumber packet_number,
+                                  bool has_stop_waiting,
+                                  EncryptionLevel level) {
+    return ProcessDataPacketAtLevel(packet_number.ToUint64(), has_stop_waiting,
+                                    level);
+  }
+
+  size_t ProcessDataPacketAtLevel(uint64_t number,
                                   bool has_stop_waiting,
                                   EncryptionLevel level) {
     std::unique_ptr<QuicPacket> packet(
         ConstructDataPacket(number, has_stop_waiting));
     char buffer[kMaxPacketSize];
     size_t encrypted_length = peer_framer_.EncryptPayload(
-        level, number, *packet, buffer, kMaxPacketSize);
+        level, QuicPacketNumber(number), *packet, buffer, kMaxPacketSize);
     connection_.ProcessUdpPacket(
         kSelfAddress, kPeerAddress,
         QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
@@ -1030,11 +1059,12 @@
     return encrypted_length;
   }
 
-  void ProcessClosePacket(QuicPacketNumber number) {
+  void ProcessClosePacket(uint64_t number) {
     std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number));
     char buffer[kMaxPacketSize];
-    size_t encrypted_length = peer_framer_.EncryptPayload(
-        ENCRYPTION_NONE, number, *packet, buffer, kMaxPacketSize);
+    size_t encrypted_length =
+        peer_framer_.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(number),
+                                    *packet, buffer, kMaxPacketSize);
     connection_.ProcessUdpPacket(
         kSelfAddress, kPeerAddress,
         QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
@@ -1084,8 +1114,12 @@
     connection_.OnStreamReset(id, error);
   }
 
-  void ProcessAckPacket(QuicPacketNumber packet_number, QuicAckFrame* frame) {
-    QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, packet_number - 1);
+  void ProcessAckPacket(uint64_t packet_number, QuicAckFrame* frame) {
+    if (packet_number > 1) {
+      QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, packet_number - 1);
+    } else {
+      QuicPacketCreatorPeer::ClearPacketNumber(&peer_creator_);
+    }
     ProcessFramePacket(QuicFrame(frame));
   }
 
@@ -1097,7 +1131,7 @@
     ProcessFramePacket(QuicFrame(frame));
   }
 
-  size_t ProcessStopWaitingPacketAtLevel(QuicPacketNumber number,
+  size_t ProcessStopWaitingPacketAtLevel(uint64_t number,
                                          QuicStopWaitingFrame* frame,
                                          EncryptionLevel level) {
     return ProcessFramePacketAtLevel(number, QuicFrame(frame),
@@ -1108,8 +1142,9 @@
     ProcessFramePacket(QuicFrame(frame));
   }
 
-  bool IsMissing(QuicPacketNumber number) {
-    return IsAwaitingPacket(*outgoing_ack(), number, 0);
+  bool IsMissing(uint64_t number) {
+    return IsAwaitingPacket(*outgoing_ack(), QuicPacketNumber(number),
+                            QuicPacketNumber());
   }
 
   std::unique_ptr<QuicPacket> ConstructPacket(const QuicPacketHeader& header,
@@ -1119,7 +1154,7 @@
     return packet;
   }
 
-  std::unique_ptr<QuicPacket> ConstructDataPacket(QuicPacketNumber number,
+  std::unique_ptr<QuicPacket> ConstructDataPacket(uint64_t number,
                                                   bool has_stop_waiting) {
     QuicPacketHeader header;
     // Set connection_id to peer's in memory representation as this data packet
@@ -1131,7 +1166,7 @@
         peer_framer_.perspective() == Perspective::IS_SERVER) {
       header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
     }
-    header.packet_number = number;
+    header.packet_number = QuicPacketNumber(number);
 
     QuicFrames frames;
     frames.push_back(QuicFrame(frame1_));
@@ -1153,12 +1188,12 @@
         &peer_creator_);
   }
 
-  std::unique_ptr<QuicPacket> ConstructClosePacket(QuicPacketNumber number) {
+  std::unique_ptr<QuicPacket> ConstructClosePacket(uint64_t number) {
     QuicPacketHeader header;
     // Set connection_id to peer's in memory representation as this connection
     // close packet is created by peer_framer.
     header.destination_connection_id = connection_id_;
-    header.packet_number = number;
+    header.packet_number = QuicPacketNumber(number);
     if (peer_framer_.transport_version() > QUIC_VERSION_43 &&
         peer_framer_.perspective() == Perspective::IS_SERVER) {
       header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
@@ -1180,22 +1215,27 @@
     return QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
   }
 
-  const QuicStopWaitingFrame InitStopWaitingFrame(
-      QuicPacketNumber least_unacked) {
+  const QuicStopWaitingFrame InitStopWaitingFrame(uint64_t least_unacked) {
     QuicStopWaitingFrame frame;
-    frame.least_unacked = least_unacked;
+    frame.least_unacked = QuicPacketNumber(least_unacked);
     return frame;
   }
 
   // Construct a ack_frame that acks all packet numbers between 1 and
   // |largest_acked|, except |missing|.
   // REQUIRES: 1 <= |missing| < |largest_acked|
+  QuicAckFrame ConstructAckFrame(uint64_t largest_acked, uint64_t missing) {
+    return ConstructAckFrame(QuicPacketNumber(largest_acked),
+                             QuicPacketNumber(missing));
+  }
+
   QuicAckFrame ConstructAckFrame(QuicPacketNumber largest_acked,
                                  QuicPacketNumber missing) {
-    if (missing == 1) {
+    if (missing == QuicPacketNumber(1)) {
       return InitAckFrame({{missing + 1, largest_acked + 1}});
     }
-    return InitAckFrame({{1, missing}, {missing + 1, largest_acked + 1}});
+    return InitAckFrame(
+        {{QuicPacketNumber(1), missing}, {missing + 1, largest_acked + 1}});
   }
 
   // Undo nacking a packet within the frame.
@@ -1211,7 +1251,7 @@
     // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
     // packet call to the visitor.
     if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
-      ProcessDataPacket(kMaxRandomInitialPacketNumber + 6000);
+      ProcessDataPacket(MaxRandomInitialPacketNumber() + 6000);
     } else {
       ProcessDataPacket(6000);
     }
@@ -1256,8 +1296,8 @@
       const QuicPacketCount packets_between_probes_base) {
     QuicConnectionPeer::SetPacketsBetweenMtuProbes(&connection_,
                                                    packets_between_probes_base);
-    QuicConnectionPeer::SetNextMtuProbeAt(&connection_,
-                                          packets_between_probes_base);
+    QuicConnectionPeer::SetNextMtuProbeAt(
+        &connection_, QuicPacketNumber(packets_between_probes_base));
   }
 
   bool IsDefaultTestConfiguration() {
@@ -1577,9 +1617,15 @@
                           probing_packet->encrypted_length),
       clock_.Now()));
 
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
 
-  EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1673,9 +1719,15 @@
                           probing_packet->encrypted_length),
       clock_.Now()));
 
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received);
 
-  EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received + 1,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 
@@ -1730,9 +1782,15 @@
                           probing_packet->encrypted_length),
       clock_.Now()));
 
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received);
 
-  EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received + 1,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1819,9 +1877,15 @@
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
       clock_.Now()));
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
 
-  EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1861,9 +1925,15 @@
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
       clock_.Now()));
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received);
 
-  EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received + 1,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1923,7 +1993,7 @@
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
 
   QuicFrames frames;
   QuicPaddingFrame padding;
@@ -1932,7 +2002,7 @@
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
   EXPECT_EQ(kMaxPacketSize, encrypted_length);
 
   framer_.set_version(version());
@@ -1956,7 +2026,7 @@
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
 
   QuicFrames frames;
   QuicPaddingFrame padding;
@@ -1965,7 +2035,7 @@
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
   EXPECT_EQ(kMaxPacketSize, encrypted_length);
 
   framer_.set_version(version());
@@ -2005,15 +2075,15 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(1);
-  EXPECT_EQ(1u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(1u), LargestAcked(*outgoing_ack()));
   EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
 
   ProcessPacket(2);
-  EXPECT_EQ(2u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(*outgoing_ack()));
   EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
 }
 
@@ -2021,17 +2091,17 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(2);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_FALSE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(1);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_FALSE(IsMissing(2));
   EXPECT_FALSE(IsMissing(1));
 }
@@ -2040,14 +2110,14 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   // Send packet 3 again, but do not set the expectation that
   // the visitor OnStreamFrame() will be called.
   ProcessDataPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 }
@@ -2056,16 +2126,16 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(2);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(5);
-  EXPECT_EQ(5u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(5u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(1));
   EXPECT_TRUE(IsMissing(4));
 
@@ -2089,7 +2159,7 @@
   // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
   // packet call to the visitor.
   if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
-    ProcessDataPacket(kMaxRandomInitialPacketNumber + 6000);
+    ProcessDataPacket(MaxRandomInitialPacketNumber() + 6000);
   } else {
     ProcessDataPacket(6000);
   }
@@ -2264,7 +2334,8 @@
 }
 
 TEST_P(QuicConnectionTest, AckDecimationReducesAcks) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
 
@@ -2435,45 +2506,39 @@
   ProcessAckPacket(&frame);
 }
 
-TEST_P(QuicConnectionTest, AckAll) {
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  ProcessPacket(1);
-
-  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
-  QuicAckFrame frame1;
-  ProcessAckPacket(&frame1);
-}
-
 TEST_P(QuicConnectionTest, BasicSending) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
+  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);  // Packet 1
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
   SendAckPacketToPeer();  // Packet 2
 
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(1u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(1u), least_unacked());
   }
 
   SendAckPacketToPeer();  // Packet 3
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(1u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(1u), least_unacked());
   }
 
   SendStreamDataToPeer(1, "bar", 3, NO_FIN, &last_packet);  // Packet 4
-  EXPECT_EQ(4u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(4u), last_packet);
   SendAckPacketToPeer();  // Packet 5
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(1u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(1u), least_unacked());
   }
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -2487,9 +2552,9 @@
   // ack for 4.
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(4u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(4u), least_unacked());
   }
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -2499,34 +2564,34 @@
   ProcessAckPacket(&frame2);  // Acks don't instigate acks.
 
   // Verify that we did not send an ack.
-  EXPECT_EQ(6u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(6u), writer_->header().packet_number);
 
   // So the last ack has not changed.
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(4u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(4u), least_unacked());
   }
 
   // If we force an ack, we shouldn't change our retransmit state.
   SendAckPacketToPeer();  // Packet 7
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(7u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(7u), least_unacked());
   }
 
   // But if we send more data it should.
   SendStreamDataToPeer(1, "eep", 6, NO_FIN, &last_packet);  // Packet 8
-  EXPECT_EQ(8u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(8u), last_packet);
   SendAckPacketToPeer();  // Packet 9
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(7u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(7u), least_unacked());
   }
 }
 
@@ -2643,6 +2708,10 @@
   // Process a data packet to queue up a pending ack.
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   ProcessDataPacket(1);
+  QuicPacketNumber last_packet;
+  SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
+  // Verify ack is bundled with outging packet.
+  EXPECT_FALSE(writer_->ack_frames().empty());
 
   EXPECT_CALL(visitor_, OnCanWrite())
       .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs(
@@ -2652,9 +2721,9 @@
 
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
 
-  // Process an ack to cause the visitor's OnCanWrite to be invoked.
-  QuicAckFrame ack_one;
-  ProcessAckPacket(3, &ack_one);
+  // Process a data packet to cause the visitor's OnCanWrite to be invoked.
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(2);
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
@@ -2839,7 +2908,7 @@
   // Lose a packet and ensure it triggers retransmission.
   QuicAckFrame nack_two = ConstructAckFrame(3, 2);
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(2, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(2), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -3088,7 +3157,7 @@
   BlockOnNextWrite();
 
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(2, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(2), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -3103,7 +3172,8 @@
 
   // Unblock the socket and attempt to send the queued packets. We will always
   // send the retransmission.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
+      .Times(1);
 
   writer_->SetWritable();
   connection_.OnCanWrite();
@@ -3260,14 +3330,15 @@
   // Process packet number 1. Can not call ProcessPacket or ProcessDataPacket
   // here, because they will fire the alarm after QuicConnection::ProcessPacket
   // is returned.
-  const QuicPacketNumber received_packet_num = 1;
+  const uint64_t received_packet_num = 1;
   const bool has_stop_waiting = false;
   const EncryptionLevel level = ENCRYPTION_NONE;
   std::unique_ptr<QuicPacket> packet(
       ConstructDataPacket(received_packet_num, has_stop_waiting));
   char buffer[kMaxPacketSize];
-  size_t encrypted_length = peer_framer_.EncryptPayload(
-      level, received_packet_num, *packet, buffer, kMaxPacketSize);
+  size_t encrypted_length =
+      peer_framer_.EncryptPayload(level, QuicPacketNumber(received_packet_num),
+                                  *packet, buffer, kMaxPacketSize);
   connection_.ProcessUdpPacket(
       kSelfAddress, kPeerAddress,
       QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
@@ -3313,6 +3384,19 @@
   }
 }
 
+TEST_P(QuicConnectionTest, AddToWriteBlockedListIfBlockedOnFlushPackets) {
+  writer_->SetBatchMode(true);
+  writer_->BlockOnNextFlush();
+
+  EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1);
+  {
+    QuicConnection::ScopedPacketFlusher flusher(&connection_,
+                                                QuicConnection::NO_ACK);
+    // flusher's destructor will call connection_.FlushPackets, which should add
+    // the connection to the write blocked list.
+  }
+}
+
 TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   int offset = 0;
@@ -3324,12 +3408,13 @@
 
   // Ack 15, nack 1-14.
 
-  QuicAckFrame nack = InitAckFrame({{15, 16}});
+  QuicAckFrame nack =
+      InitAckFrame({{QuicPacketNumber(15), QuicPacketNumber(16)}});
 
   // 14 packets have been NACK'd and lost.
   LostPacketVector lost_packets;
   for (int i = 1; i < 15; ++i) {
-    lost_packets.push_back(LostPacket(i, kMaxPacketSize));
+    lost_packets.push_back(LostPacket(QuicPacketNumber(i), kMaxPacketSize));
   }
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
@@ -3344,23 +3429,26 @@
 
 // Test sending multiple acks from the connection to the session.
 TEST_P(QuicConnectionTest, MultipleAcks) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
+  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);  // Packet 1
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
   SendStreamDataToPeer(3, "foo", 0, NO_FIN, &last_packet);  // Packet 2
-  EXPECT_EQ(2u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(2u), last_packet);
   SendAckPacketToPeer();                                    // Packet 3
   SendStreamDataToPeer(5, "foo", 0, NO_FIN, &last_packet);  // Packet 4
-  EXPECT_EQ(4u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(4u), last_packet);
   SendStreamDataToPeer(1, "foo", 3, NO_FIN, &last_packet);  // Packet 5
-  EXPECT_EQ(5u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(5u), last_packet);
   SendStreamDataToPeer(3, "foo", 3, NO_FIN, &last_packet);  // Packet 6
-  EXPECT_EQ(6u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(6u), last_packet);
 
   // Client will ack packets 1, 2, [!3], 4, 5.
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   QuicAckFrame frame1 = ConstructAckFrame(5, 3);
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   ProcessAckPacket(&frame1);
 
   // Now the client implicitly acks 3, and explicitly acks 6.
@@ -3370,11 +3458,14 @@
 }
 
 TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
+  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr);  // Packet 1;
   // From now on, we send acks, so the send algorithm won't mark them pending.
   SendAckPacketToPeer();  // Packet 2
 
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   QuicAckFrame frame = InitAckFrame(1);
   ProcessAckPacket(&frame);
@@ -3382,25 +3473,25 @@
   // Verify that our internal state has least-unacked as 2, because we're still
   // waiting for a potential ack for 2.
 
-  EXPECT_EQ(2u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(2u), stop_waiting()->least_unacked);
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   frame = InitAckFrame(2);
   ProcessAckPacket(&frame);
-  EXPECT_EQ(3u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(3u), stop_waiting()->least_unacked);
 
   // When we send an ack, we make sure our least-unacked makes sense.  In this
   // case since we're not waiting on an ack for 2 and all packets are acked, we
   // set it to 3.
   SendAckPacketToPeer();  // Packet 3
   // Least_unacked remains at 3 until another ack is received.
-  EXPECT_EQ(3u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(3u), stop_waiting()->least_unacked);
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
     // Check that the outgoing ack had its packet number as least_unacked.
-    EXPECT_EQ(3u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(3u), least_unacked());
   }
 
   // Ack the ack, which updates the rtt and raises the least unacked.
@@ -3409,13 +3500,13 @@
   ProcessAckPacket(&frame);
 
   SendStreamDataToPeer(1, "bar", 3, NO_FIN, nullptr);  // Packet 4
-  EXPECT_EQ(4u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(4u), stop_waiting()->least_unacked);
   SendAckPacketToPeer();  // Packet 5
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(4u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(4u), least_unacked());
   }
 
   // Send two data packets at the end, and ensure if the last one is acked,
@@ -3424,30 +3515,31 @@
   SendStreamDataToPeer(1, "bar", 9, NO_FIN, nullptr);  // Packet 7
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{1, 5}, {7, 8}});
+  frame = InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(5)},
+                        {QuicPacketNumber(7), QuicPacketNumber(8)}});
   ProcessAckPacket(&frame);
 
-  EXPECT_EQ(6u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(6u), stop_waiting()->least_unacked);
 }
 
 TEST_P(QuicConnectionTest, TLP) {
   connection_.SetMaxTailLossProbes(1);
 
   SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
   QuicTime retransmission_time =
       connection_.GetRetransmissionAlarm()->deadline();
   EXPECT_NE(QuicTime::Zero(), retransmission_time);
 
-  EXPECT_EQ(1u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(1u), writer_->header().packet_number);
   // Simulate the retransmission alarm firing and sending a tlp,
   // so send algorithm's OnRetransmissionTimeout is not called.
   clock_.AdvanceTime(retransmission_time - clock_.Now());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
-  EXPECT_EQ(2u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(2u), writer_->header().packet_number);
   // We do not raise the high water mark yet.
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
 }
 
 TEST_P(QuicConnectionTest, RTO) {
@@ -3456,18 +3548,18 @@
   QuicTime default_retransmission_time =
       clock_.ApproximateNow() + DefaultRetransmissionTime();
   SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
 
-  EXPECT_EQ(1u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(1u), writer_->header().packet_number);
   EXPECT_EQ(default_retransmission_time,
             connection_.GetRetransmissionAlarm()->deadline());
   // Simulate the retransmission alarm firing.
   clock_.AdvanceTime(DefaultRetransmissionTime());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
-  EXPECT_EQ(2u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(2u), writer_->header().packet_number);
   // We do not raise the high water mark yet.
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
 }
 
 TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
@@ -3490,8 +3582,10 @@
 
   {
     InSequence s;
-    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 3, _, _));
-    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _));
+    EXPECT_CALL(*send_algorithm_,
+                OnPacketSent(_, _, QuicPacketNumber(3), _, _));
+    EXPECT_CALL(*send_algorithm_,
+                OnPacketSent(_, _, QuicPacketNumber(4), _, _));
   }
 
   // Manually mark both packets for retransmission.
@@ -3616,45 +3710,6 @@
   ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL);
 }
 
-TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
-  if (GetQuicReloadableFlag(quic_decrypt_packets_on_key_change)) {
-    return;
-  }
-
-  // SetFromConfig is always called after construction from InitializeSession.
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
-  QuicConfig config;
-  config.set_max_undecryptable_packets(100);
-  connection_.SetFromConfig(config);
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  use_tagging_decrypter();
-
-  const uint8_t tag = 0x07;
-  peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
-                            QuicMakeUnique<TaggingEncrypter>(tag));
-
-  // Process an encrypted packet which can not yet be decrypted which should
-  // result in the packet being buffered.
-  for (QuicPacketNumber i = 1; i <= 100; ++i) {
-    ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_INITIAL);
-  }
-
-  // Transition to the new encryption state and process another encrypted packet
-  // which should result in the original packets being processed.
-  connection_.SetDecrypter(ENCRYPTION_INITIAL,
-                           QuicMakeUnique<StrictTaggingDecrypter>(tag));
-  connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
-  connection_.SetEncrypter(ENCRYPTION_INITIAL,
-                           QuicMakeUnique<TaggingEncrypter>(tag));
-  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(101);
-  ProcessDataPacketAtLevel(101, !kHasStopWaiting, ENCRYPTION_INITIAL);
-
-  // Finally, process a third packet and note that we do not reprocess the
-  // buffered packet.
-  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
-  ProcessDataPacketAtLevel(102, !kHasStopWaiting, ENCRYPTION_INITIAL);
-}
-
 TEST_P(QuicConnectionTest, TestRetransmitOrder) {
   connection_.SetMaxTailLossProbes(0);
 
@@ -3688,10 +3743,6 @@
 }
 
 TEST_P(QuicConnectionTest, Buffer100NonDecryptablePacketsThenKeyChange) {
-  if (!GetQuicReloadableFlag(quic_decrypt_packets_on_key_change)) {
-    return;
-  }
-
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
   QuicConfig config;
@@ -3706,7 +3757,7 @@
 
   // Process an encrypted packet which can not yet be decrypted which should
   // result in the packet being buffered.
-  for (QuicPacketNumber i = 1; i <= 100; ++i) {
+  for (uint64_t i = 1; i <= 100; ++i) {
     ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_INITIAL);
   }
 
@@ -3848,7 +3899,7 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(20));
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
   // This will be the updated deadline for the connection to idle time out.
   QuicTime new_ddl = clock_.ApproximateNow() +
                      QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
@@ -3900,12 +3951,12 @@
   // execution until manually adjusted.
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
 
   // Advance the time and send the second packet to the peer.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
-  EXPECT_EQ(2u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(2u), last_packet);
 
   if (GetQuicReloadableFlag(
           quic_fix_time_of_first_packet_sent_after_receiving)) {
@@ -4092,7 +4143,7 @@
       .WillOnce(SaveArg<3>(&mtu_probe_size));
   connection_.SendMtuDiscoveryPacket(new_mtu);
   EXPECT_EQ(new_mtu, mtu_probe_size);
-  EXPECT_EQ(1u, creator_->packet_number());
+  EXPECT_EQ(QuicPacketNumber(1u), creator_->packet_number());
 
   // Send more than MTU worth of data.  No acknowledgement was received so far,
   // so the MTU should be at its old value.
@@ -4103,7 +4154,7 @@
       .WillOnce(SaveArg<3>(&size_before_mtu_change))
       .WillOnce(Return());
   connection_.SendStreamDataWithString(3, data, 0, FIN);
-  EXPECT_EQ(3u, creator_->packet_number());
+  EXPECT_EQ(QuicPacketNumber(3u), creator_->packet_number());
   EXPECT_EQ(kDefaultMaxPacketSize, size_before_mtu_change);
 
   // Acknowledge all packets so far.
@@ -4116,7 +4167,7 @@
   // Send the same data again.  Check that it fits into a single packet now.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
   connection_.SendStreamDataWithString(3, data, 0, FIN);
-  EXPECT_EQ(4u, creator_->packet_number());
+  EXPECT_EQ(QuicPacketNumber(4u), creator_->packet_number());
 }
 
 // Tests whether MTU discovery does not happen when it is not explicitly enabled
@@ -4161,7 +4212,8 @@
   connection_.GetMtuDiscoveryAlarm()->Fire();
   EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, probe_size);
 
-  const QuicPacketCount probe_packet_number = packets_between_probes_base + 1;
+  const QuicPacketNumber probe_packet_number =
+      FirstSendingPacketNumber() + packets_between_probes_base;
   ASSERT_EQ(probe_packet_number, creator_->packet_number());
 
   // Acknowledge all packets sent so far.
@@ -4223,12 +4275,13 @@
                                                  mtu_discovery_packets.end());
       QuicPacketNumber max_packet = *max_element(mtu_discovery_packets.begin(),
                                                  mtu_discovery_packets.end());
-      ack.packets.AddRange(1, min_packet);
-      ack.packets.AddRange(max_packet + 1, creator_->packet_number() + 1);
+      ack.packets.AddRange(QuicPacketNumber(1), min_packet);
+      ack.packets.AddRange(QuicPacketNumber(max_packet + 1),
+                           creator_->packet_number() + 1);
       ack.largest_acked = creator_->packet_number();
 
     } else {
-      ack.packets.AddRange(1, creator_->packet_number() + 1);
+      ack.packets.AddRange(QuicPacketNumber(1), creator_->packet_number() + 1);
       ack.largest_acked = creator_->packet_number();
     }
 
@@ -4250,11 +4303,12 @@
   // Ensure the number of packets between probes grows exponentially by checking
   // it against the closed-form expression for the packet number.
   ASSERT_EQ(kMtuDiscoveryAttempts, mtu_discovery_packets.size());
-  for (QuicPacketNumber i = 0; i < kMtuDiscoveryAttempts; i++) {
+  for (uint64_t i = 0; i < kMtuDiscoveryAttempts; i++) {
     // 2^0 + 2^1 + 2^2 + ... + 2^n = 2^(n + 1) - 1
     const QuicPacketCount packets_between_probes =
         packets_between_probes_base * ((1 << (i + 1)) - 1);
-    EXPECT_EQ(packets_between_probes + (i + 1), mtu_discovery_packets[i]);
+    EXPECT_EQ(QuicPacketNumber(packets_between_probes + (i + 1)),
+              mtu_discovery_packets[i]);
   }
 
   EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
@@ -4290,7 +4344,8 @@
   connection_.GetMtuDiscoveryAlarm()->Fire();
   EXPECT_EQ(mtu_limit, probe_size);
 
-  const QuicPacketCount probe_sequence_number = packets_between_probes_base + 1;
+  const QuicPacketNumber probe_sequence_number =
+      FirstSendingPacketNumber() + packets_between_probes_base;
   ASSERT_EQ(probe_sequence_number, creator_->packet_number());
 
   // Acknowledge all packets sent so far.
@@ -4485,7 +4540,7 @@
   const QuicTime final_timeout = rto_time + initial_idle_timeout;
   clock_.AdvanceTime(rto_time - clock_.Now());
   ASSERT_EQ(rto_time, clock_.Now());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2u), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
 
   // Advance to the original timeout and fire the alarm. The connection should
@@ -4622,7 +4677,7 @@
   // Retransmit the packet via tail loss probe.
   clock_.AdvanceTime(connection_.GetRetransmissionAlarm()->deadline() -
                      clock_.Now());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2u), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
 
   // This time, we should time out and send a connection close due to the TLP.
@@ -4839,6 +4894,7 @@
   // Test that if we send a packet without delay, it is not queued.
   QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT);
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
+  QuicPacketCreatorPeer::SetPacketNumber(creator_, 1);
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
@@ -4851,6 +4907,7 @@
   QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT);
   EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1);
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
+  QuicPacketCreatorPeer::SetPacketNumber(creator_, 1);
   writer_->SetShouldWriteFail();
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
@@ -4859,8 +4916,10 @@
 TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
   QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT);
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
+  QuicPacketCreatorPeer::SetPacketNumber(creator_, 1);
   BlockOnNextWrite();
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2u), _, _))
+      .Times(0);
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -5112,7 +5171,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5228,7 +5287,7 @@
   // default delayed ack time.
   ack_time = clock_.ApproximateNow() +
              QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 4; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5304,7 +5363,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5357,7 +5416,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5393,7 +5452,8 @@
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5419,7 +5479,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5461,7 +5521,8 @@
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5487,7 +5548,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5548,7 +5609,8 @@
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5575,7 +5637,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5620,7 +5682,8 @@
 
 TEST_P(QuicConnectionTest,
        SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5647,7 +5710,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5844,7 +5907,7 @@
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_EQ(1u, writer_->padding_frames().size());
   ASSERT_FALSE(writer_->ack_frames().empty());
-  EXPECT_EQ(2u, LargestAcked(writer_->ack_frames().front()));
+  EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
@@ -5873,7 +5936,7 @@
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_EQ(1u, writer_->padding_frames().size());
   ASSERT_FALSE(writer_->ack_frames().empty());
-  EXPECT_EQ(2u, LargestAcked(writer_->ack_frames().front()));
+  EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
@@ -5888,7 +5951,7 @@
   // Ack the second packet, which will retransmit the first packet.
   QuicAckFrame ack = ConstructAckFrame(2, 1);
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(1, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -5927,7 +5990,7 @@
     EXPECT_FALSE(writer_->stop_waiting_frames().empty());
   }
   EXPECT_FALSE(writer_->ack_frames().empty());
-  EXPECT_EQ(3u, LargestAcked(writer_->ack_frames().front()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(writer_->ack_frames().front()));
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
@@ -5950,7 +6013,8 @@
   EXPECT_FALSE(connection_.connected());
   EXPECT_FALSE(connection_.CanWriteStreamData());
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
 }
@@ -5969,7 +6033,8 @@
   EXPECT_FALSE(connection_.connected());
   EXPECT_FALSE(connection_.CanWriteStreamData());
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
 
   EXPECT_QUIC_BUG(connection_.SendConnectivityProbingPacket(
                       writer_.get(), connection_.peer_address()),
@@ -5987,7 +6052,8 @@
   // affects the probing_writer which is not the default.
   EXPECT_CALL(visitor_, OnWriteBlocked()).Times(0);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(1);
   connection_.SendConnectivityProbingPacket(&probing_writer,
                                             connection_.peer_address());
 }
@@ -6003,7 +6069,8 @@
   // writer to send connectivity probes.
   EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(1);
   connection_.SendConnectivityProbingPacket(writer_.get(),
                                             connection_.peer_address());
 }
@@ -6017,7 +6084,8 @@
   // sent.
   EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
   connection_.SendConnectivityProbingPacket(&probing_writer,
                                             connection_.peer_address());
 }
@@ -6031,7 +6099,8 @@
   // sent.
   EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
   connection_.SendConnectivityProbingPacket(writer_.get(),
                                             connection_.peer_address());
 }
@@ -6137,21 +6206,20 @@
     peer_framer_.set_version_for_tests(
         ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_99));
   } else {
-    peer_framer_.set_version_for_tests(
-        ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+    peer_framer_.set_version_for_tests(UnsupportedQuicVersion());
   }
 
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
 
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
-  size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet,
-                                                   buffer, kMaxPacketSize);
+  size_t encrypted_length = framer_.EncryptPayload(
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
 
   framer_.set_version(version());
   // Writer's framer's perspective is client, so that it needs to have the right
@@ -6183,21 +6251,20 @@
     peer_framer_.set_version_for_tests(
         ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_99));
   } else {
-    peer_framer_.set_version_for_tests(
-        ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+    peer_framer_.set_version_for_tests(UnsupportedQuicVersion());
   }
 
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
 
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
-  size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet,
-                                                   buffer, kMaxPacketSize);
+  size_t encrypted_length = framer_.EncryptPayload(
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
 
   framer_.set_version(version());
   BlockOnNextWrite();
@@ -6236,21 +6303,20 @@
     peer_framer_.set_version_for_tests(
         ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_99));
   } else {
-    peer_framer_.set_version_for_tests(
-        ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+    peer_framer_.set_version_for_tests(UnsupportedQuicVersion());
   }
 
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
 
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
-  size_t encryped_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet,
-                                                  buffer, kMaxPacketSize);
+  size_t encryped_length = framer_.EncryptPayload(
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
 
   framer_.set_version(version());
   set_perspective(Perspective::IS_SERVER);
@@ -6297,14 +6363,14 @@
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
   header.version_flag = false;
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
   ASSERT_NE(0u, encrypted_length);
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -6355,11 +6421,13 @@
   connection_.GetRetransmissionAlarm()->Fire();
 
   // Retransmit due to explicit nacks.
-  QuicAckFrame nack_three = InitAckFrame({{2, 3}, {4, 5}});
+  QuicAckFrame nack_three =
+      InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)},
+                    {QuicPacketNumber(4), QuicPacketNumber(5)}});
 
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(1, kMaxPacketSize));
-  lost_packets.push_back(LostPacket(3, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(3), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -6395,7 +6463,7 @@
   if (peer_framer_.transport_version() > QUIC_VERSION_43) {
     header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
   }
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
   header.version_flag = false;
 
   QuicConnectionCloseFrame qccf;
@@ -6408,7 +6476,7 @@
   EXPECT_TRUE(nullptr != packet);
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 1, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(1), *packet, buffer, kMaxPacketSize);
 
   EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
                                            ConnectionCloseSource::FROM_PEER));
@@ -6442,8 +6510,7 @@
 
   // Shouldn't be able to find a mutually supported version.
   ParsedQuicVersionVector unsupported_version;
-  unsupported_version.push_back(
-      ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+  unsupported_version.push_back(UnsupportedQuicVersion());
   EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version));
 }
 
@@ -6490,7 +6557,7 @@
 
 TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
   QuicPacketHeader header;
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
   if (GetParam().version.transport_version > QUIC_VERSION_43) {
     header.form = IETF_QUIC_LONG_HEADER_PACKET;
   }
@@ -6594,6 +6661,9 @@
 }
 
 TEST_P(QuicConnectionTest, SendAcksImmediately) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
   CongestionBlockWrites();
   SendAckPacketToPeer();
 }
@@ -6727,7 +6797,8 @@
       EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
     }
     EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-    QuicAckFrame frame = InitAckFrame({{1u + 2u * i, 2u + 2u * i}});
+    QuicAckFrame frame = InitAckFrame(
+        {{QuicPacketNumber(1u + 2u * i), QuicPacketNumber(2u + 2u * i)}});
     ProcessAckPacket(&frame);
     EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
     // Check the deadline of the path degrading alarm.
@@ -6742,7 +6813,7 @@
       // degrading alarm.
       clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
       EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-      frame = InitAckFrame({{2, 3}});
+      frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
       ProcessAckPacket(&frame);
       EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet());
     } else {
@@ -6797,7 +6868,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
   // No more retransmittable packets on the wire, so the path degrading alarm
   // should be cancelled, and the ping alarm should be set to the
@@ -6860,7 +6932,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1u, 2u}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1u), QuicPacketNumber(2u)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
   // Check the deadline of the path degrading alarm.
@@ -6925,7 +6998,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1u, 2u}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1u), QuicPacketNumber(2u)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
   // Check the deadline of the path degrading alarm.
@@ -6955,7 +7029,7 @@
   // degrading. And will set a timer to detect new path degrading.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_FALSE(connection_.IsPathDegrading());
   EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
@@ -6978,13 +7052,17 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1u, 2u}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1u), QuicPacketNumber(2u)}});
   ProcessAckPacket(&frame);
   EXPECT_FALSE(connection_.IsPathDegrading());
   EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet());
 }
 
 TEST_P(QuicConnectionTest, NoPathDegradingAfterSendingAck) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
   SendAckPacketToPeer();
   EXPECT_FALSE(connection_.sent_packet_manager().unacked_packets().empty());
   EXPECT_FALSE(connection_.sent_packet_manager().HasInFlightPackets());
@@ -7310,7 +7388,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.sent_packet_manager().HasInFlightPackets());
   // The ping alarm is set for the ping timeout, not the shorter
@@ -7327,7 +7406,7 @@
   // the wire.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout,
@@ -7337,7 +7416,7 @@
   // the ping alarm.
   QuicTime prev_deadline = connection_.GetPingAlarm()->deadline();
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(prev_deadline, connection_.GetPingAlarm()->deadline());
@@ -7394,7 +7473,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout,
@@ -7412,7 +7492,7 @@
   // the wire.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout,
@@ -7452,13 +7532,14 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
 
   // Ack packet 1 again. largest_acked remains at 1, so
   // OnForwardProgressConfirmed() should not be called.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  frame = InitAckFrame({{1, 2}});
+  frame = InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
 
   // Ack packet 2. This increases the largest_acked to 2, so
@@ -7466,7 +7547,7 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
 }
 
@@ -7655,7 +7736,7 @@
   std::unique_ptr<QuicPacket> packet(ConstructDataPacket(2, !kHasStopWaiting));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 2, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(2), *packet, buffer, kMaxPacketSize);
   // Make sure no stream frame is processed.
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(0);
   connection_.ProcessUdpPacket(
@@ -7666,6 +7747,29 @@
   EXPECT_EQ(1u, connection_.GetStats().packets_processed);
 }
 
+TEST_P(QuicConnectionTest, AcceptPacketNumberZero) {
+  if (!GetQuicRestartFlag(quic_uint64max_uninitialized_pn) ||
+      version().transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  // Set first_sending_packet_number to be 0 to allow successfully processing
+  // acks which ack packet number 0.
+  QuicFramerPeer::SetFirstSendingPacketNumber(writer_->framer()->framer(), 0);
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+  ProcessPacket(0);
+  EXPECT_EQ(QuicPacketNumber(0), LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+
+  ProcessPacket(1);
+  EXPECT_EQ(QuicPacketNumber(1), LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+
+  ProcessPacket(2);
+  EXPECT_EQ(QuicPacketNumber(2), LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_constants.cc b/quic/core/quic_constants.cc
index 344a94a..8e46f88 100644
--- a/quic/core/quic_constants.cc
+++ b/quic/core/quic_constants.cc
@@ -11,4 +11,15 @@
 const char* const kEPIDGoogleFrontEnd = "GFE";
 const char* const kEPIDGoogleFrontEnd0 = "GFE0";
 
+QuicPacketNumber MaxRandomInitialPacketNumber() {
+  static const QuicPacketNumber kMaxRandomInitialPacketNumber =
+      QuicPacketNumber(0x7fffffff);
+  return kMaxRandomInitialPacketNumber;
+}
+
+QuicPacketNumber FirstSendingPacketNumber() {
+  static const QuicPacketNumber kFirstSendingPacketNumber = QuicPacketNumber(1);
+  return kFirstSendingPacketNumber;
+}
+
 }  // namespace quic
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index fa76c21..cf27bef 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -181,7 +181,7 @@
 
 // The largest gap in packets we'll accept without closing the connection.
 // This will likely have to be tuned.
-const QuicPacketNumber kMaxPacketGap = 5000;
+const QuicPacketCount kMaxPacketGap = 5000;
 
 // The maximum number of random padding bytes to add.
 const QuicByteCount kMaxNumRandomPaddingBytes = 256;
@@ -193,7 +193,7 @@
 
 // For When using Random Initial Packet Numbers, they can start
 // anyplace in the range 1...((2^31)-1) or 0x7fffffff
-const QuicPacketNumber kMaxRandomInitialPacketNumber = 0x7fffffff;
+QUIC_EXPORT_PRIVATE QuicPacketNumber MaxRandomInitialPacketNumber();
 
 // Used to represent an invalid or no control frame id.
 const QuicControlFrameId kInvalidControlFrameId = 0;
@@ -224,8 +224,10 @@
 // Maximum length allowed for the token in a NEW_TOKEN frame.
 const size_t kMaxNewTokenTokenLength = 0xffff;
 
-// Used to represent an invalid packet number.
-const QuicPacketNumber kInvalidPacketNumber = 0;
+// Packet number of first sending packet of a connection. Please note, this
+// cannot be used as first received packet because peer can choose its starting
+// packet number.
+QUIC_EXPORT_PRIVATE QuicPacketNumber FirstSendingPacketNumber();
 
 // Used by clients to tell if a public reset is sent from a Google frontend.
 QUIC_EXPORT_PRIVATE extern const char* const kEPIDGoogleFrontEnd;
diff --git a/quic/core/quic_control_frame_manager.cc b/quic/core/quic_control_frame_manager.cc
index ece6324..c2b5192 100644
--- a/quic/core/quic_control_frame_manager.cc
+++ b/quic/core/quic_control_frame_manager.cc
@@ -17,9 +17,7 @@
     : last_control_frame_id_(kInvalidControlFrameId),
       least_unacked_(1),
       least_unsent_(1),
-      session_(session),
-      donot_retransmit_old_window_updates_(
-          GetQuicReloadableFlag(quic_donot_retransmit_old_window_update2)) {}
+      session_(session) {}
 
 QuicControlFrameManager::~QuicControlFrameManager() {
   while (!control_frames_.empty()) {
@@ -129,13 +127,11 @@
         << "Send or retransmit a control frame with invalid control frame id";
     return;
   }
-  if (donot_retransmit_old_window_updates_ &&
-      frame.type == WINDOW_UPDATE_FRAME) {
+  if (frame.type == WINDOW_UPDATE_FRAME) {
     QuicStreamId stream_id = frame.window_update_frame->stream_id;
     if (QuicContainsKey(window_update_frames_, stream_id) &&
         id > window_update_frames_[stream_id]) {
       // Consider the older window update of the same stream as acked.
-      QUIC_RELOADABLE_FLAG_COUNT(quic_donot_retransmit_old_window_update2);
       OnControlFrameIdAcked(window_update_frames_[stream_id]);
     }
     window_update_frames_[stream_id] = id;
@@ -161,8 +157,7 @@
   if (!OnControlFrameIdAcked(id)) {
     return false;
   }
-  if (donot_retransmit_old_window_updates_ &&
-      frame.type == WINDOW_UPDATE_FRAME) {
+  if (frame.type == WINDOW_UPDATE_FRAME) {
     QuicStreamId stream_id = frame.window_update_frame->stream_id;
     if (QuicContainsKey(window_update_frames_, stream_id) &&
         window_update_frames_[stream_id] == id) {
diff --git a/quic/core/quic_control_frame_manager.h b/quic/core/quic_control_frame_manager.h
index a08d5c3..ace08c6 100644
--- a/quic/core/quic_control_frame_manager.h
+++ b/quic/core/quic_control_frame_manager.h
@@ -102,12 +102,6 @@
   // sent.
   bool WillingToWrite() const;
 
-  // TODO(wub): Remove this function once
-  // quic_donot_retransmit_old_window_update flag is deprecated.
-  bool donot_retransmit_old_window_updates() const {
-    return donot_retransmit_old_window_updates_;
-  }
-
  private:
   friend class test::QuicControlFrameManagerPeer;
 
@@ -158,9 +152,6 @@
 
   // Last sent window update frame for each stream.
   QuicSmallMap<QuicStreamId, QuicControlFrameId, 10> window_update_frames_;
-
-  // Latched value of quic_donot_retransmit_old_window_update2 flag.
-  const bool donot_retransmit_old_window_updates_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_control_frame_manager_test.cc b/quic/core/quic_control_frame_manager_test.cc
index a0e0b33..ccddadd 100644
--- a/quic/core/quic_control_frame_manager_test.cc
+++ b/quic/core/quic_control_frame_manager_test.cc
@@ -235,7 +235,6 @@
 }
 
 TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
-  SetQuicReloadableFlag(quic_donot_retransmit_old_window_update2, true);
   Initialize();
   // Send two more window updates of the same stream.
   manager_->WriteOrBufferWindowUpdate(kTestStreamId, 200);
@@ -271,7 +270,6 @@
 }
 
 TEST_F(QuicControlFrameManagerTest, RetransmitWindowUpdateOfDifferentStreams) {
-  SetQuicReloadableFlag(quic_donot_retransmit_old_window_update2, true);
   Initialize();
   // Send two more window updates of different streams.
   manager_->WriteOrBufferWindowUpdate(kTestStreamId + 2, 200);
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc
index 88bfccd..81487df 100644
--- a/quic/core/quic_crypto_client_handshaker.cc
+++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -338,11 +338,10 @@
                                           "CHLO too large");
       return;
     }
-    // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag.
-    out.set_minimum_size(
-        static_cast<size_t>(max_packet_size - kFramingOverhead));
     next_state_ = STATE_RECV_REJ;
     CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT);
+    session()->connection()->set_fully_pad_crypto_hadshake_packets(
+        crypto_config_->pad_inchoate_hello());
     SendHandshakeMessage(out);
     return;
   }
@@ -377,6 +376,8 @@
         *cached->proof_verify_details());
   }
   next_state_ = STATE_RECV_SHLO;
+  session()->connection()->set_fully_pad_crypto_hadshake_packets(
+      crypto_config_->pad_full_hello());
   SendHandshakeMessage(out);
   // Be prepared to decrypt with the new server write key.
   session()->connection()->SetAlternativeDecrypter(
diff --git a/quic/core/quic_crypto_client_handshaker_test.cc b/quic/core/quic_crypto_client_handshaker_test.cc
new file mode 100644
index 0000000..389be97
--- /dev/null
+++ b/quic/core/quic_crypto_client_handshaker_test.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.proto.h"
+#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
+#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace {
+
+using ::testing::Test;
+
+class TestProofHandler : public QuicCryptoClientStream::ProofHandler {
+ public:
+  ~TestProofHandler() override {}
+  void OnProofValid(
+      const QuicCryptoClientConfig::CachedState& cached) override {}
+  void OnProofVerifyDetailsAvailable(
+      const ProofVerifyDetails& verify_details) override {}
+};
+
+class InsecureProofVerifier : public ProofVerifier {
+ public:
+  InsecureProofVerifier() {}
+  ~InsecureProofVerifier() override {}
+
+  // ProofVerifier override.
+  QuicAsyncStatus VerifyProof(
+      const QuicString& hostname,
+      const uint16_t port,
+      const QuicString& server_config,
+      QuicTransportVersion transport_version,
+      QuicStringPiece chlo_hash,
+      const std::vector<QuicString>& certs,
+      const QuicString& cert_sct,
+      const QuicString& signature,
+      const ProofVerifyContext* context,
+      QuicString* error_details,
+      std::unique_ptr<ProofVerifyDetails>* verify_details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    return QUIC_SUCCESS;
+  }
+
+  QuicAsyncStatus VerifyCertChain(
+      const QuicString& hostname,
+      const std::vector<QuicString>& certs,
+      const ProofVerifyContext* context,
+      QuicString* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    return QUIC_SUCCESS;
+  }
+
+  std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
+    return nullptr;
+  }
+};
+
+class DummyProofSource : public ProofSource {
+ public:
+  DummyProofSource() {}
+  ~DummyProofSource() override {}
+
+  // ProofSource override.
+  void GetProof(const QuicSocketAddress& server_address,
+                const QuicString& hostname,
+                const QuicString& server_config,
+                QuicTransportVersion transport_version,
+                QuicStringPiece chlo_hash,
+                std::unique_ptr<Callback> callback) override {
+    QuicReferenceCountedPointer<ProofSource::Chain> chain =
+        GetCertChain(server_address, hostname);
+    QuicCryptoProof proof;
+    proof.signature = "Dummy signature";
+    proof.leaf_cert_scts = "Dummy timestamp";
+    callback->Run(true, chain, proof, nullptr /* details */);
+  }
+
+  QuicReferenceCountedPointer<Chain> GetCertChain(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname) override {
+    std::vector<QuicString> certs;
+    certs.push_back("Dummy cert");
+    return QuicReferenceCountedPointer<ProofSource::Chain>(
+        new ProofSource::Chain(certs));
+  }
+
+  void ComputeTlsSignature(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname,
+      uint16_t signature_algorithm,
+      QuicStringPiece in,
+      std::unique_ptr<SignatureCallback> callback) override {
+    callback->Run(true, "Dummy signature");
+  }
+};
+
+class Handshaker : public QuicCryptoClientHandshaker {
+ public:
+  Handshaker(const QuicServerId& server_id,
+             QuicCryptoClientStream* stream,
+             QuicSession* session,
+             std::unique_ptr<ProofVerifyContext> verify_context,
+             QuicCryptoClientConfig* crypto_config,
+             QuicCryptoClientStream::ProofHandler* proof_handler)
+      : QuicCryptoClientHandshaker(server_id,
+                                   stream,
+                                   session,
+                                   std::move(verify_context),
+                                   crypto_config,
+                                   proof_handler) {}
+
+  void DoSendCHLOTest(QuicCryptoClientConfig::CachedState* cached) {
+    QuicCryptoClientHandshaker::DoSendCHLO(cached);
+  }
+};
+
+class QuicCryptoClientHandshakerTest : public Test {
+ protected:
+  QuicCryptoClientHandshakerTest()
+      : proof_handler_(),
+        helper_(),
+        alarm_factory_(),
+        server_id_("host", 123),
+        connection_(new test::MockQuicConnection(&helper_,
+                                                 &alarm_factory_,
+                                                 Perspective::IS_CLIENT)),
+        session_(connection_, false),
+        crypto_client_config_(QuicMakeUnique<InsecureProofVerifier>(),
+                              quic::TlsClientHandshaker::CreateSslCtx()),
+        client_stream_(new QuicCryptoClientStream(server_id_,
+                                                  &session_,
+                                                  nullptr,
+                                                  &crypto_client_config_,
+                                                  &proof_handler_)),
+        handshaker_(server_id_,
+                    client_stream_,
+                    &session_,
+                    nullptr,
+                    &crypto_client_config_,
+                    &proof_handler_),
+        state_() {
+    // Session takes the ownership of the client stream! (but handshaker also
+    // takes a reference to it, but doesn't take the ownership).
+    session_.SetCryptoStream(client_stream_);
+    session_.Initialize();
+  }
+
+  void InitializeServerParametersToEnableFullHello() {
+    QuicCryptoServerConfig::ConfigOptions options;
+    std::unique_ptr<QuicServerConfigProtobuf> config =
+        QuicCryptoServerConfig::GenerateConfig(helper_.GetRandomGenerator(),
+                                               helper_.GetClock(), options);
+    state_.Initialize(
+        config->config(), "sourcetoken", std::vector<QuicString>{"Dummy cert"},
+        "", "chlo_hash", "signature", helper_.GetClock()->WallNow(),
+        helper_.GetClock()->WallNow().Add(QuicTime::Delta::FromSeconds(30)));
+
+    state_.SetProofValid();
+  }
+
+  TestProofHandler proof_handler_;
+  test::MockQuicConnectionHelper helper_;
+  test::MockAlarmFactory alarm_factory_;
+  QuicServerId server_id_;
+  // Session takes the ownership of the connection.
+  test::MockQuicConnection* connection_;
+  test::MockQuicSession session_;
+  QuicCryptoClientConfig crypto_client_config_;
+  QuicCryptoClientStream* client_stream_;
+  Handshaker handshaker_;
+  QuicCryptoClientConfig::CachedState state_;
+};
+
+TEST_F(QuicCryptoClientHandshakerTest, TestSendFullPaddingInInchoateHello) {
+  handshaker_.DoSendCHLOTest(&state_);
+
+  EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake());
+}
+
+TEST_F(QuicCryptoClientHandshakerTest, TestDisabledPaddingInInchoateHello) {
+  crypto_client_config_.set_pad_inchoate_hello(false);
+  handshaker_.DoSendCHLOTest(&state_);
+  EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake());
+}
+
+TEST_F(QuicCryptoClientHandshakerTest,
+       TestPaddingInFullHelloEvenIfInchoateDisabled) {
+  // Disable inchoate, but full hello should still be padded.
+  crypto_client_config_.set_pad_inchoate_hello(false);
+
+  InitializeServerParametersToEnableFullHello();
+
+  handshaker_.DoSendCHLOTest(&state_);
+  EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake());
+}
+
+TEST_F(QuicCryptoClientHandshakerTest, TestNoPaddingInFullHelloWhenDisabled) {
+  crypto_client_config_.set_pad_full_hello(false);
+
+  InitializeServerParametersToEnableFullHello();
+
+  handshaker_.DoSendCHLOTest(&state_);
+  EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake());
+}
+
+}  // namespace
+}  // namespace quic
diff --git a/quic/core/quic_crypto_client_stream_test.cc b/quic/core/quic_crypto_client_stream_test.cc
index 14f34a7..d9b344a 100644
--- a/quic/core/quic_crypto_client_stream_test.cc
+++ b/quic/core/quic_crypto_client_stream_test.cc
@@ -329,54 +329,6 @@
   EXPECT_FALSE(stream()->WasChannelIDSourceCallbackRun());
 }
 
-TEST_F(QuicCryptoClientStreamTest, TokenBindingNegotiation) {
-  server_options_.token_binding_params = QuicTagVector{kTB10, kP256};
-  crypto_config_.tb_key_params = QuicTagVector{kTB10};
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(kTB10,
-            stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutServerSupport) {
-  crypto_config_.tb_key_params = QuicTagVector{kTB10, kP256};
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutClientSupport) {
-  server_options_.token_binding_params = QuicTagVector{kTB10, kP256};
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, TokenBindingNotNegotiated) {
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingInPrivacyMode) {
-  server_options_.token_binding_params = QuicTagVector{kTB10};
-  crypto_config_.tb_key_params = QuicTagVector{kTB10};
-  server_id_ = QuicServerId(kServerHostname, kServerPort, true);
-  CreateConnection();
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
 TEST_F(QuicCryptoClientStreamTest, PreferredVersion) {
   // This mimics the case where client receives version negotiation packet, such
   // that, the preferred version is different from the packets' version.
@@ -440,7 +392,7 @@
     client_session_->GetMutableCryptoStream()->CryptoConnect();
     EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
         .Times(testing::AnyNumber());
-    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_))
+    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _))
         .Times(testing::AnyNumber());
     crypto_test_utils::AdvanceHandshake(
         client_connection_, client_session_->GetMutableCryptoStream(), 0,
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc
index 2b38c4b..e79a60c 100644
--- a/quic/core/quic_crypto_server_handshaker.cc
+++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -184,6 +184,8 @@
       // retransmitted.
       session()->connection()->EnableSavingCryptoPackets();
     }
+    session()->connection()->set_fully_pad_crypto_hadshake_packets(
+        crypto_config_->pad_rej());
     SendHandshakeMessage(*reply);
 
     if (reply->tag() == kSREJ) {
@@ -233,6 +235,8 @@
       std::move(crypto_negotiated_params_->initial_crypters.decrypter));
   session()->connection()->SetDiversificationNonce(*diversification_nonce);
 
+  session()->connection()->set_fully_pad_crypto_hadshake_packets(
+      crypto_config_->pad_shlo());
   SendHandshakeMessage(*reply);
 
   session()->connection()->SetEncrypter(
@@ -463,7 +467,7 @@
     return EmptyQuicConnectionId();
   }
   return helper_->GenerateConnectionIdForReject(
-      session()->connection()->connection_id());
+      transport_version(), session()->connection()->connection_id());
 }
 
 const QuicSocketAddress QuicCryptoServerHandshaker::GetClientAddress() {
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h
index 63de376..c4de9b0 100644
--- a/quic/core/quic_crypto_server_stream.h
+++ b/quic/core/quic_crypto_server_stream.h
@@ -141,6 +141,7 @@
     // Given the current connection_id, generates a new ConnectionId to
     // be returned with a stateless reject.
     virtual QuicConnectionId GenerateConnectionIdForReject(
+        QuicTransportVersion version,
         QuicConnectionId connection_id) const = 0;
 
     // Returns true if |message|, which was received on |self_address| is
diff --git a/quic/core/quic_crypto_server_stream_test.cc b/quic/core/quic_crypto_server_stream_test.cc
index 027e412..33635d8 100644
--- a/quic/core/quic_crypto_server_stream_test.cc
+++ b/quic/core/quic_crypto_server_stream_test.cc
@@ -104,7 +104,7 @@
     server_session_.reset(server_session);
     EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
         .Times(testing::AnyNumber());
-    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_))
+    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _))
         .Times(testing::AnyNumber());
     crypto_test_utils::FakeServerOptions options;
     options.token_binding_params = QuicTagVector{kTB10};
@@ -489,28 +489,6 @@
       QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
 }
 
-TEST_P(QuicCryptoServerStreamTest, TokenBindingNegotiated) {
-  Initialize();
-
-  client_options_.token_binding_params = QuicTagVector{kTB10, kP256};
-  CompleteCryptoHandshake();
-  EXPECT_EQ(
-      kTB10,
-      server_stream()->crypto_negotiated_params().token_binding_key_param);
-  EXPECT_TRUE(server_stream()->encryption_established());
-  EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, NoTokenBindingWithoutClientSupport) {
-  Initialize();
-
-  CompleteCryptoHandshake();
-  EXPECT_EQ(
-      0u, server_stream()->crypto_negotiated_params().token_binding_key_param);
-  EXPECT_TRUE(server_stream()->encryption_established());
-  EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
 class QuicCryptoServerStreamTestWithFailingProofSource
     : public QuicCryptoServerStreamTest {
  public:
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index 440a480..8199571 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -111,19 +111,6 @@
       result);
 }
 
-bool QuicCryptoStream::ExportTokenBindingKeyingMaterial(
-    QuicString* result) const {
-  if (!encryption_established()) {
-    QUIC_BUG << "ExportTokenBindingKeyingMaterial was called before initial"
-             << "encryption was established.";
-    return false;
-  }
-  return CryptoUtils::ExportKeyingMaterial(
-      crypto_negotiated_params().initial_subkey_secret,
-      "EXPORTER-Token-Binding",
-      /* context= */ "", 32, result);
-}
-
 void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
                                        QuicStringPiece data) {
   // TODO(nharper): This approach to writing data, by setting the encryption
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h
index a2cf9fe..0593f44 100644
--- a/quic/core/quic_crypto_stream.h
+++ b/quic/core/quic_crypto_stream.h
@@ -56,16 +56,6 @@
                             size_t result_len,
                             QuicString* result) const;
 
-  // Performs key extraction for Token Binding. Unlike ExportKeyingMaterial,
-  // this function can be called before forward-secure encryption is
-  // established. Returns false if initial encryption has not been established,
-  // and true on success.
-  //
-  // Since this depends only on the initial keys, a signature over it can be
-  // repurposed by an attacker who obtains the client's or server's DH private
-  // value.
-  bool ExportTokenBindingKeyingMaterial(QuicString* result) const;
-
   // Writes |data| to the QuicStream at level |level|.
   virtual void WriteCryptoData(EncryptionLevel level, QuicStringPiece data);
 
diff --git a/quic/core/quic_default_packet_writer.cc b/quic/core/quic_default_packet_writer.cc
index 6e8e833..2c162e0 100644
--- a/quic/core/quic_default_packet_writer.cc
+++ b/quic/core/quic_default_packet_writer.cc
@@ -24,7 +24,7 @@
       << "QuicDefaultPacketWriter does not accept any options.";
   WriteResult result = QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
                                                     self_address, peer_address);
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     write_blocked_ = true;
   }
   return result;
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index f476a47..0cb03aa 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -92,6 +92,13 @@
     }
     return WRITE_FAILED;
   }
+  bool WriteCryptoData(EncryptionLevel level,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override {
+    QUIC_BUG << "PacketCollector::WriteCryptoData is unimplemented.";
+    return false;
+  }
 
   std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() {
     return &packets_;
@@ -235,9 +242,9 @@
     if (helper_->CanAcceptClientHello(chlo, client_address_, peer_address_,
                                       self_address_, &error_details_)) {
       can_accept_ = true;
-      rejector_->OnChlo(version, connection_id,
-                        helper_->GenerateConnectionIdForReject(connection_id),
-                        chlo);
+      rejector_->OnChlo(
+          version, connection_id,
+          helper_->GenerateConnectionIdForReject(version, connection_id), chlo);
     }
   }
 
@@ -506,27 +513,29 @@
   }
 
   // initial packet number of 0 is always invalid.
-  if (header.packet_number == kInvalidPacketNumber) {
+  if (!header.packet_number.IsInitialized()) {
     return kFateTimeWait;
   }
   if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
     QUIC_RESTART_FLAG_COUNT_N(quic_enable_accept_random_ipn, 1, 2);
     // Accepting Initial Packet Numbers in 1...((2^31)-1) range... check
     // maximum accordingly.
-    if (header.packet_number > kMaxRandomInitialPacketNumber) {
+    if (header.packet_number > MaxRandomInitialPacketNumber()) {
       return kFateTimeWait;
     }
   } else {
     // Count those that would have been accepted if FLAGS..random_ipn
     // were true -- to detect/diagnose potential issues prior to
     // enabling the flag.
-    if ((header.packet_number > kMaxReasonableInitialPacketNumber) &&
-        (header.packet_number <= kMaxRandomInitialPacketNumber)) {
+    if ((header.packet_number >
+         QuicPacketNumber(kMaxReasonableInitialPacketNumber)) &&
+        (header.packet_number <= MaxRandomInitialPacketNumber())) {
       QUIC_CODE_COUNT_N(had_possibly_random_ipn, 1, 2);
     }
     // Check that the sequence number is within the range that the client is
     // expected to send before receiving a response from the server.
-    if (header.packet_number > kMaxReasonableInitialPacketNumber) {
+    if (header.packet_number >
+        QuicPacketNumber(kMaxReasonableInitialPacketNumber)) {
       return kFateTimeWait;
     }
   }
@@ -552,9 +561,7 @@
     // expediency. Stop doing this when removing flag
     // quic_always_reset_ietf_connections.
     if (!GetQuicReloadableFlag(quic_always_reset_ietf_connections) &&
-        (!GetQuicReloadableFlag(
-             quic_send_reset_for_post_handshake_connections_without_termination_packets) ||  // NOLINT
-         (source == ConnectionCloseSource::FROM_PEER))) {
+        source == ConnectionCloseSource::FROM_PEER) {
       action = QuicTimeWaitListManager::DO_NOTHING;
     } else if (!connection->IsHandshakeConfirmed()) {
       QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed);
@@ -727,6 +734,8 @@
 
 void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& frame) {}
 
+void QuicDispatcher::OnStopSendingReceived(const QuicStopSendingFrame& frame) {}
+
 void QuicDispatcher::OnConnectionAddedToTimeWaitList(
     QuicConnectionId connection_id) {
   QUIC_DLOG(INFO) << "Connection " << connection_id
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index 3597a97..d6eb35b 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -91,6 +91,11 @@
   // Collects reset error code received on streams.
   void OnRstStreamReceived(const QuicRstStreamFrame& frame) override;
 
+  // QuicSession::Visitor interface implementation (via inheritance of
+  // QuicTimeWaitListManager::Visitor):
+  // Collects reset error code received on streams.
+  void OnStopSendingReceived(const QuicStopSendingFrame& frame) override;
+
   // QuicTimeWaitListManager::Visitor interface implementation
   // Called whenever the time wait list manager adds a new connection to the
   // time-wait list.
@@ -110,7 +115,7 @@
   // send a handshake and then up to 50 or so data packets, and then it may
   // resend the handshake packet up to 10 times.  (Retransmitted packets are
   // sent with unique packet numbers.)
-  static const QuicPacketNumber kMaxReasonableInitialPacketNumber = 100;
+  static const uint64_t kMaxReasonableInitialPacketNumber = 100;
   static_assert(kMaxReasonableInitialPacketNumber >=
                     kInitialCongestionWindow + 10,
                 "kMaxReasonableInitialPacketNumber is unreasonably small "
@@ -348,7 +353,7 @@
 
   // Please do not use this method.
   // TODO(fayang): Remove this method when deprecating
-  // quic_proxy_use_real_packet_format_when_reject flag.
+  // quic_fix_last_packet_is_ietf_quic flag.
   PacketHeaderFormat GetLastPacketFormat() const;
 
  private:
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index afc4687..0381cf5 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -268,7 +268,7 @@
                      const QuicString& data,
                      QuicConnectionIdLength connection_id_length,
                      QuicPacketNumberLength packet_number_length,
-                     QuicPacketNumber packet_number) {
+                     uint64_t packet_number) {
     ProcessPacket(peer_address, connection_id, has_version_flag,
                   CurrentSupportedVersions().front(), data,
                   connection_id_length, packet_number_length, packet_number);
@@ -282,7 +282,7 @@
                      const QuicString& data,
                      QuicConnectionIdLength connection_id_length,
                      QuicPacketNumberLength packet_number_length,
-                     QuicPacketNumber packet_number) {
+                     uint64_t packet_number) {
     ParsedQuicVersionVector versions(SupportedVersions(version));
     std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
         connection_id, EmptyQuicConnectionId(), has_version_flag, false,
@@ -676,18 +676,19 @@
   SetQuicRestartFlag(quic_enable_accept_random_ipn, true);
   ProcessPacket(client_address, connection_id, true, SerializeCHLO(),
                 PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER,
-                kMaxRandomInitialPacketNumber +
+                MaxRandomInitialPacketNumber().ToUint64() +
                     QuicDispatcher::kMaxReasonableInitialPacketNumber + 1);
 }
 
 TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
   SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_99, true);
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
@@ -741,6 +742,39 @@
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
                 PACKET_4BYTE_PACKET_NUMBER, 1);
 
+  // Turn off version 47.
+  SetQuicReloadableFlag(quic_enable_version_47, false);
+  connection_id = TestConnectionId(++conn_id);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq"), _))
+      .Times(0);
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
+  // Turn on version 47.
+  SetQuicReloadableFlag(quic_enable_version_47, true);
+  connection_id = TestConnectionId(++conn_id);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq"), _))
+      .WillOnce(testing::Return(CreateSession(
+          dispatcher_.get(), config_, connection_id, client_address,
+          &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+  EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+              ProcessUdpPacket(_, _, _))
+      .WillOnce(WithArg<2>(
+          Invoke([this, connection_id](const QuicEncryptedPacket& packet) {
+            ValidatePacket(connection_id, packet);
+          })));
+  EXPECT_CALL(*dispatcher_,
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
   // Turn off version 46.
   SetQuicReloadableFlag(quic_enable_version_46, false);
   connection_id = TestConnectionId(++conn_id);
@@ -1956,7 +1990,7 @@
 
   // Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The
   // last one should be dropped.
-  for (QuicPacketNumber packet_number = 2;
+  for (uint64_t packet_number = 2;
        packet_number <= kDefaultMaxUndecryptablePackets + 2; ++packet_number) {
     ProcessPacket(client_addr_, last_connection_id, true, "data packet");
   }
diff --git a/quic/core/quic_epoll_alarm_factory.cc b/quic/core/quic_epoll_alarm_factory.cc
index 550ee13..2ec2f6f 100644
--- a/quic/core/quic_epoll_alarm_factory.cc
+++ b/quic/core/quic_epoll_alarm_factory.cc
@@ -14,7 +14,7 @@
 
 class QuicEpollAlarm : public QuicAlarm {
  public:
-  QuicEpollAlarm(gfe2::EpollServer* epoll_server,
+  QuicEpollAlarm(QuicEpollServer* epoll_server,
                  QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
       : QuicAlarm(std::move(delegate)),
         epoll_server_(epoll_server),
@@ -44,13 +44,13 @@
   }
 
  private:
-  class EpollAlarmImpl : public gfe2::EpollAlarm {
+  class EpollAlarmImpl : public QuicEpollAlarmBase {
    public:
     explicit EpollAlarmImpl(QuicEpollAlarm* alarm) : alarm_(alarm) {}
 
     // Use the same integer type as the base class.
     int64 /* allow-non-std-int */ OnAlarm() override {
-      EpollAlarm::OnAlarm();
+      QuicEpollAlarmBase::OnAlarm();
       alarm_->Fire();
       // Fire will take care of registering the alarm, if needed.
       return 0;
@@ -60,13 +60,13 @@
     QuicEpollAlarm* alarm_;
   };
 
-  gfe2::EpollServer* epoll_server_;
+  QuicEpollServer* epoll_server_;
   EpollAlarmImpl epoll_alarm_impl_;
 };
 
 }  // namespace
 
-QuicEpollAlarmFactory::QuicEpollAlarmFactory(gfe2::EpollServer* epoll_server)
+QuicEpollAlarmFactory::QuicEpollAlarmFactory(QuicEpollServer* epoll_server)
     : epoll_server_(epoll_server) {}
 
 QuicEpollAlarmFactory::~QuicEpollAlarmFactory() {}
diff --git a/quic/core/quic_epoll_alarm_factory.h b/quic/core/quic_epoll_alarm_factory.h
index d1ec7ca..fc9b45c 100644
--- a/quic/core/quic_epoll_alarm_factory.h
+++ b/quic/core/quic_epoll_alarm_factory.h
@@ -5,17 +5,17 @@
 #ifndef QUICHE_QUIC_CORE_QUIC_EPOLL_ALARM_FACTORY_H_
 #define QUICHE_QUIC_CORE_QUIC_EPOLL_ALARM_FACTORY_H_
 
-#include "gfe/gfe2/base/epoll_server.h"
 #include "net/third_party/quiche/src/quic/core/quic_alarm.h"
 #include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
 #include "net/third_party/quiche/src/quic/core/quic_one_block_arena.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 
 namespace quic {
 
 // Creates alarms that use the supplied EpollServer for timing and firing.
 class QuicEpollAlarmFactory : public QuicAlarmFactory {
  public:
-  explicit QuicEpollAlarmFactory(gfe2::EpollServer* eps);
+  explicit QuicEpollAlarmFactory(QuicEpollServer* eps);
   QuicEpollAlarmFactory(const QuicEpollAlarmFactory&) = delete;
   QuicEpollAlarmFactory& operator=(const QuicEpollAlarmFactory&) = delete;
   ~QuicEpollAlarmFactory() override;
@@ -27,7 +27,7 @@
       QuicConnectionArena* arena) override;
 
  private:
-  gfe2::EpollServer* epoll_server_;  // Not owned.
+  QuicEpollServer* epoll_server_;  // Not owned.
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_epoll_connection_helper.cc b/quic/core/quic_epoll_connection_helper.cc
index 3070c99..49002f6 100644
--- a/quic/core/quic_epoll_connection_helper.cc
+++ b/quic/core/quic_epoll_connection_helper.cc
@@ -16,7 +16,7 @@
 namespace quic {
 
 QuicEpollConnectionHelper::QuicEpollConnectionHelper(
-    gfe2::EpollServer* epoll_server,
+    QuicEpollServer* epoll_server,
     QuicAllocator type)
     : clock_(epoll_server),
       random_generator_(QuicRandom::GetInstance()),
diff --git a/quic/core/quic_epoll_connection_helper.h b/quic/core/quic_epoll_connection_helper.h
index 858954a..62e030c 100644
--- a/quic/core/quic_epoll_connection_helper.h
+++ b/quic/core/quic_epoll_connection_helper.h
@@ -18,6 +18,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
 #include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
 #include "net/quic/platform/impl/quic_epoll_clock.h"
 
@@ -43,7 +44,7 @@
 
 class QuicEpollConnectionHelper : public QuicConnectionHelperInterface {
  public:
-  QuicEpollConnectionHelper(gfe2::EpollServer* eps, QuicAllocator allocator);
+  QuicEpollConnectionHelper(QuicEpollServer* eps, QuicAllocator allocator);
   QuicEpollConnectionHelper(const QuicEpollConnectionHelper&) = delete;
   QuicEpollConnectionHelper& operator=(const QuicEpollConnectionHelper&) =
       delete;
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index e659b38..1b93074 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -130,7 +130,7 @@
 const uint8_t kSourceConnectionIdLengthMask = 0x0F;
 
 // Returns the absolute value of the difference between |a| and |b|.
-QuicPacketNumber Delta(QuicPacketNumber a, QuicPacketNumber b) {
+uint64_t Delta(uint64_t a, uint64_t b) {
   // Since these are unsigned numbers, we can't just return abs(a - b)
   if (a < b) {
     return b - a;
@@ -138,12 +138,18 @@
   return a - b;
 }
 
-QuicPacketNumber ClosestTo(QuicPacketNumber target,
-                           QuicPacketNumber a,
-                           QuicPacketNumber b) {
+uint64_t ClosestTo(uint64_t target, uint64_t a, uint64_t b) {
   return (Delta(target, a) < Delta(target, b)) ? a : b;
 }
 
+uint64_t PacketNumberIntervalLength(
+    const QuicInterval<QuicPacketNumber>& interval) {
+  if (interval.Empty()) {
+    return 0u;
+  }
+  return interval.max() - interval.min();
+}
+
 QuicPacketNumberLength ReadSequenceNumberLength(uint8_t flags) {
   switch (flags & PACKET_FLAGS_8BYTE_PACKET) {
     case PACKET_FLAGS_8BYTE_PACKET:
@@ -180,7 +186,7 @@
 uint8_t PacketNumberLengthToOnWireValue(
     QuicTransportVersion version,
     QuicPacketNumberLength packet_number_length) {
-  if (version == QUIC_VERSION_99) {
+  if (version > QUIC_VERSION_46) {
     return packet_number_length - 1;
   }
   switch (packet_number_length) {
@@ -203,7 +209,7 @@
     QuicPacketNumberLength* packet_number_length) {
   DCHECK(!(type & FLAGS_LONG_HEADER));
   const bool two_bits_packet_number_length =
-      infer_packet_header_type_from_version ? version == QUIC_VERSION_99
+      infer_packet_header_type_from_version ? version > QUIC_VERSION_46
                                             : (type & FLAGS_FIXED_BIT);
   if (two_bits_packet_number_length) {
     *packet_number_length =
@@ -231,13 +237,13 @@
                                     QuicLongHeaderType type) {
   switch (type) {
     case INITIAL:
-      return version == QUIC_VERSION_99 ? 0 : 0x7F;
+      return version > QUIC_VERSION_46 ? 0 : 0x7F;
     case ZERO_RTT_PROTECTED:
-      return version == QUIC_VERSION_99 ? 1 << 4 : 0x7C;
+      return version > QUIC_VERSION_46 ? 1 << 4 : 0x7C;
     case HANDSHAKE:
-      return version == QUIC_VERSION_99 ? 2 << 4 : 0x7D;
+      return version > QUIC_VERSION_46 ? 2 << 4 : 0x7D;
     case RETRY:
-      return version == QUIC_VERSION_99 ? 3 << 4 : 0x7E;
+      return version > QUIC_VERSION_46 ? 3 << 4 : 0x7E;
     case VERSION_NEGOTIATION:
       return 0xF0;  // Value does not matter
     default:
@@ -250,7 +256,7 @@
                        uint8_t type,
                        QuicLongHeaderType* long_header_type) {
   DCHECK((type & FLAGS_LONG_HEADER) && version != QUIC_VERSION_UNSUPPORTED);
-  if (version == QUIC_VERSION_99) {
+  if (version > QUIC_VERSION_46) {
     switch ((type & 0x30) >> 4) {
       case 0:
         *long_header_type = INITIAL;
@@ -297,7 +303,7 @@
 QuicPacketNumberLength GetLongHeaderPacketNumberLength(
     QuicTransportVersion version,
     uint8_t type) {
-  if (version == QUIC_VERSION_99) {
+  if (version > QUIC_VERSION_46) {
     return static_cast<QuicPacketNumberLength>((type & 0x03) + 1);
   }
   return PACKET_4BYTE_PACKET_NUMBER;
@@ -324,6 +330,19 @@
   return static_cast<uint8_t>(length - kConnectionIdLengthAdjustment);
 }
 
+bool IsValidPacketNumberLength(QuicPacketNumberLength packet_number_length) {
+  size_t length = packet_number_length;
+  return length == 1 || length == 2 || length == 4 || length == 6 ||
+         length == 8;
+}
+
+bool IsValidFullPacketNumber(uint64_t full_packet_number,
+                             QuicTransportVersion version) {
+  return full_packet_number > 0 ||
+         (GetQuicRestartFlag(quic_uint64max_uninitialized_pn) &&
+          version == QUIC_VERSION_99);
+}
+
 }  // namespace
 
 QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
@@ -331,7 +350,6 @@
                        Perspective perspective)
     : visitor_(nullptr),
       error_(QUIC_NO_ERROR),
-      largest_packet_number_(0),
       last_serialized_connection_id_(EmptyQuicConnectionId()),
       last_version_label_(0),
       last_header_form_(GOOGLE_QUIC_PACKET),
@@ -345,9 +363,8 @@
       process_timestamps_(false),
       creation_time_(creation_time),
       last_timestamp_(QuicTime::Delta::Zero()),
+      first_sending_packet_number_(FirstSendingPacketNumber()),
       data_producer_(nullptr),
-      process_stateless_reset_at_client_only_(
-          GetQuicReloadableFlag(quic_process_stateless_reset_at_client_only)),
       infer_packet_header_type_from_version_(perspective ==
                                              Perspective::IS_CLIENT) {
   DCHECK(!supported_versions.empty());
@@ -377,6 +394,13 @@
 }
 
 // static
+size_t QuicFramer::GetMinCryptoFrameSize(QuicStreamOffset offset,
+                                         QuicPacketLength data_length) {
+  return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(offset) +
+         QuicDataWriter::GetVarInt62Len(data_length);
+}
+
+// static
 size_t QuicFramer::GetMessageFrameSize(QuicTransportVersion version,
                                        bool last_frame_in_packet,
                                        QuicByteCount length) {
@@ -500,6 +524,9 @@
   if (version != QUIC_VERSION_99) {
     return kQuicFrameTypeSize + kQuicMaxStreamIdSize;
   }
+  // TODO(fkastenholz): This should be converted to use
+  // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+  // and not rely on 0.
   if (frame.stream_id == 0) {
     // return size of IETF QUIC Blocked frame
     return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.offset);
@@ -869,7 +896,6 @@
         set_detailed_error(
             "Attempt to append CRYPTO frame and not in version 99.");
         return RaiseError(QUIC_INTERNAL_ERROR);
-
       default:
         RaiseError(QUIC_INVALID_FRAME_DATA);
         QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
@@ -1050,10 +1076,30 @@
   return writer.length();
 }
 
+size_t QuicFramer::BuildIetfConnectivityProbingPacket(
+    const QuicPacketHeader& header,
+    char* buffer,
+    size_t packet_length) {
+  QuicFrames frames;
+
+  // Write a PING frame, which has no data payload.
+  QuicPingFrame ping_frame;
+  frames.push_back(QuicFrame(ping_frame));
+
+  // Add padding to the rest of the packet.
+  QuicPaddingFrame padding_frame;
+  frames.push_back(QuicFrame(padding_frame));
+
+  return BuildIetfDataPacket(header, frames, buffer, packet_length);
+}
+
 size_t QuicFramer::BuildConnectivityProbingPacket(
     const QuicPacketHeader& header,
     char* buffer,
     size_t packet_length) {
+  if (version_.transport_version == QUIC_VERSION_99) {
+    return BuildIetfConnectivityProbingPacket(header, buffer, packet_length);
+  }
   QuicDataWriter writer(packet_length, buffer, endianness());
 
   if (!AppendPacketHeader(header, &writer)) {
@@ -1088,47 +1134,25 @@
     size_t packet_length,
     QuicPathFrameBuffer* payload,
     QuicRandom* randomizer) {
-  QuicDataWriter writer(packet_length, buffer, endianness());
-  DCHECK_EQ(version_.transport_version, QUIC_VERSION_99)
-      << "Attempt to build a PATH_CHALLENGE Connectivity Probing packet and "
-         "not doing IETF QUIC";
-
-  if (!AppendPacketHeader(header, &writer)) {
-    QUIC_BUG << "AppendPacketHeader failed";
+  if (version_.transport_version != QUIC_VERSION_99) {
+    QUIC_BUG << "Attempt to build a PATH_CHALLENGE Connectivity Probing "
+                "packet and not doing IETF QUIC";
     return 0;
   }
+  QuicFrames frames;
 
   // Write a PATH_CHALLENGE frame, which has a random 8-byte payload
   randomizer->RandBytes(payload->data(), payload->size());
 
   QuicPathChallengeFrame path_challenge_frame(0, *payload);
-  if (!AppendTypeByte(QuicFrame(&path_challenge_frame),
-                      /* last_frame_in_packet = */ false, &writer)) {
-    QUIC_BUG
-        << "AppendTypeByte failed for PATH_CHALLENGE frame in probing packet";
-    return 0;
-  }
-
-  if (!AppendPathChallengeFrame(path_challenge_frame, &writer)) {
-    QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in "
-                "probing packet";
-    return 0;
-  }
+  frames.push_back(QuicFrame(&path_challenge_frame));
 
   // Add padding to the rest of the packet in order to assess Path MTU
   // characteristics.
   QuicPaddingFrame padding_frame;
-  if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) {
-    QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet";
-    return 0;
-  }
-  if (!AppendPaddingFrame(padding_frame, &writer)) {
-    QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes
-             << " failed";
-    return 0;
-  }
+  frames.push_back(QuicFrame(padding_frame));
 
-  return writer.length();
+  return BuildIetfDataPacket(header, frames, buffer, packet_length);
 }
 
 size_t QuicFramer::BuildPathResponsePacket(
@@ -1142,53 +1166,33 @@
         << "Attempt to generate connectivity response with no request payloads";
     return 0;
   }
-
-  QuicDataWriter writer(packet_length, buffer, endianness());
-
-  DCHECK_EQ(version_.transport_version, QUIC_VERSION_99)
-      << "Attempt to build a PATH_RESPONSE Connectivity Probing packet and "
-         "not doing IETF QUIC";
-
-  if (!AppendPacketHeader(header, &writer)) {
-    QUIC_BUG << "AppendPacketHeader failed";
+  if (version_.transport_version != QUIC_VERSION_99) {
+    QUIC_BUG << "Attempt to build a PATH_RESPONSE Connectivity Probing "
+                "packet and not doing IETF QUIC";
     return 0;
   }
 
-  // Write a set of PATH_RESPONSE frames to a single packet, each with the
-  // 8-byte payload of the corresponding PATH_REQUEST frame from a single
-  // received packet.
+  std::vector<std::unique_ptr<QuicPathResponseFrame>> path_response_frames;
   for (const QuicPathFrameBuffer& payload : payloads) {
     // Note that the control frame ID can be 0 since this is not retransmitted.
-    QuicPathResponseFrame path_response_frame(0, payload);
+    path_response_frames.push_back(
+        QuicMakeUnique<QuicPathResponseFrame>(0, payload));
+  }
 
-    if (!AppendTypeByte(QuicFrame(&path_response_frame), false, &writer)) {
-      QUIC_BUG
-          << "AppendTypeByte failed for PATH_RESPONSE frame in probing packet";
-      return 0;
-    }
-
-    if (!AppendPathResponseFrame(path_response_frame, &writer)) {
-      QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in "
-                  "probing packet";
-      return 0;
-    }
+  QuicFrames frames;
+  for (const std::unique_ptr<QuicPathResponseFrame>& path_response_frame :
+       path_response_frames) {
+    frames.push_back(QuicFrame(path_response_frame.get()));
   }
 
   if (is_padded) {
     // Add padding to the rest of the packet in order to assess Path MTU
     // characteristics.
     QuicPaddingFrame padding_frame;
-    if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) {
-      QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet";
-      return 0;
-    }
-    if (!AppendPaddingFrame(padding_frame, &writer)) {
-      QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes
-               << " failed";
-      return 0;
-    }
+    frames.push_back(QuicFrame(padding_frame));
   }
-  return writer.length();
+
+  return BuildIetfDataPacket(header, frames, buffer, packet_length);
 }
 
 // static
@@ -1274,7 +1278,7 @@
   } else {
     // Append an random packet number.
     QuicPacketNumber random_packet_number =
-        QuicRandom::GetInstance()->RandUint64() % 255 + 1;
+        QuicPacketNumber(QuicRandom::GetInstance()->RandUint64() % 255 + 1);
     if (!AppendPacketNumber(PACKET_1BYTE_PACKET_NUMBER, random_packet_number,
                             &writer)) {
       return nullptr;
@@ -1470,35 +1474,17 @@
                                        size_t buffer_length) {
   DCHECK_NE(GOOGLE_QUIC_PACKET, header->form);
   DCHECK(!header->has_possible_stateless_reset_token);
-  if (header->form == IETF_QUIC_SHORT_HEADER_PACKET) {
-    if (!process_stateless_reset_at_client_only_) {
-      // Peak possible stateless reset token. Will only be used on decryption
-      // failure.
-      QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
-      if (remaining.length() >=
-          sizeof(header->possible_stateless_reset_token)) {
-        remaining.copy(
-            reinterpret_cast<char*>(&header->possible_stateless_reset_token),
-            sizeof(header->possible_stateless_reset_token),
-            remaining.length() -
-                sizeof(header->possible_stateless_reset_token));
-      }
-    } else {
-      QUIC_RELOADABLE_FLAG_COUNT(quic_process_stateless_reset_at_client_only);
-      if (perspective_ == Perspective::IS_CLIENT) {
-        // Peek possible stateless reset token. Will only be used on decryption
-        // failure.
-        QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
-        if (remaining.length() >=
-            sizeof(header->possible_stateless_reset_token)) {
-          header->has_possible_stateless_reset_token = true;
-          memcpy(
-              &header->possible_stateless_reset_token,
-              &remaining.data()[remaining.length() -
-                                sizeof(header->possible_stateless_reset_token)],
-              sizeof(header->possible_stateless_reset_token));
-        }
-      }
+  if (header->form == IETF_QUIC_SHORT_HEADER_PACKET &&
+      perspective_ == Perspective::IS_CLIENT) {
+    // Peek possible stateless reset token. Will only be used on decryption
+    // failure.
+    QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
+    if (remaining.length() >= sizeof(header->possible_stateless_reset_token)) {
+      header->has_possible_stateless_reset_token = true;
+      memcpy(&header->possible_stateless_reset_token,
+             &remaining.data()[remaining.length() -
+                               sizeof(header->possible_stateless_reset_token)],
+             sizeof(header->possible_stateless_reset_token));
     }
   }
 
@@ -1506,15 +1492,15 @@
       header->long_packet_type != VERSION_NEGOTIATION) {
     // Process packet number.
     QuicPacketNumber base_packet_number = largest_packet_number_;
-
+    uint64_t full_packet_number;
     if (!ProcessAndCalculatePacketNumber(
             encrypted_reader, header->packet_number_length, base_packet_number,
-            &header->packet_number)) {
+            &full_packet_number)) {
       set_detailed_error("Unable to read packet number.");
       return RaiseError(QUIC_INVALID_PACKET_HEADER);
     }
 
-    if (header->packet_number == kInvalidPacketNumber) {
+    if (!IsValidFullPacketNumber(full_packet_number, transport_version())) {
       if (IsIetfStatelessResetPacket(*header)) {
         // This is a stateless reset packet.
         QuicIetfStatelessResetPacket packet(
@@ -1525,6 +1511,7 @@
       set_detailed_error("packet numbers cannot be 0.");
       return RaiseError(QUIC_INVALID_PACKET_HEADER);
     }
+    header->packet_number = QuicPacketNumber(full_packet_number);
   }
 
   // A nonce should only present in SHLO from the server to the client when
@@ -1567,8 +1554,12 @@
 
   // Update the largest packet number after we have decrypted the packet
   // so we are confident is not attacker controlled.
-  largest_packet_number_ =
-      std::max(header->packet_number, largest_packet_number_);
+  if (largest_packet_number_.IsInitialized()) {
+    largest_packet_number_ =
+        std::max(header->packet_number, largest_packet_number_);
+  } else {
+    largest_packet_number_ = header->packet_number;
+  }
 
   if (!visitor_->OnPacketHeader(*header)) {
     // The visitor suppresses further processing of the packet.
@@ -1629,8 +1620,12 @@
 
   // Update the largest packet number after we have decrypted the packet
   // so we are confident is not attacker controlled.
-  largest_packet_number_ =
-      std::max(header->packet_number, largest_packet_number_);
+  if (largest_packet_number_.IsInitialized()) {
+    largest_packet_number_ =
+        std::max(header->packet_number, largest_packet_number_);
+  } else {
+    largest_packet_number_ = header->packet_number;
+  }
 
   if (!visitor_->OnPacketHeader(*header)) {
     // The visitor suppresses further processing of the packet.
@@ -1699,10 +1694,11 @@
 
 bool QuicFramer::IsIetfStatelessResetPacket(
     const QuicPacketHeader& header) const {
-  return perspective_ == Perspective::IS_CLIENT &&
-         header.form == IETF_QUIC_SHORT_HEADER_PACKET &&
-         (!process_stateless_reset_at_client_only_ ||
-          header.has_possible_stateless_reset_token) &&
+  QUIC_BUG_IF(header.has_possible_stateless_reset_token &&
+              perspective_ != Perspective::IS_CLIENT)
+      << "has_possible_stateless_reset_token can only be true at client side.";
+  return header.form == IETF_QUIC_SHORT_HEADER_PACKET &&
+         header.has_possible_stateless_reset_token &&
          visitor_->IsValidStatelessResetToken(
              header.possible_stateless_reset_token);
 }
@@ -1737,12 +1733,13 @@
       }
       break;
     case PACKET_8BYTE_CONNECTION_ID:
-      QUIC_BUG_IF(header.destination_connection_id.length() !=
-                      kQuicDefaultConnectionIdLength &&
-                  transport_version() < QUIC_VERSION_99)
-          << "Cannot use connection ID of length "
-          << header.destination_connection_id.length() << " with version "
+      QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+          header.destination_connection_id, transport_version()))
+          << "AppendPacketHeader: attempted to use connection ID "
+          << header.destination_connection_id
+          << " which is invalid with version "
           << QuicVersionToString(transport_version());
+
       public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
       if (perspective_ == Perspective::IS_CLIENT) {
         public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD;
@@ -1784,7 +1781,7 @@
 bool QuicFramer::AppendIetfHeaderTypeByte(const QuicPacketHeader& header,
                                           QuicDataWriter* writer) {
   uint8_t type = 0;
-  if (transport_version() == QUIC_VERSION_99) {
+  if (transport_version() > QUIC_VERSION_46) {
     if (header.version_flag) {
       type = static_cast<uint8_t>(
           FLAGS_LONG_HEADER | FLAGS_FIXED_BIT |
@@ -1819,11 +1816,10 @@
 bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header,
                                         QuicDataWriter* writer) {
   QUIC_DVLOG(1) << ENDPOINT << "Appending IETF header: " << header;
-  QUIC_BUG_IF(header.destination_connection_id.length() !=
-                  kQuicDefaultConnectionIdLength &&
-              transport_version() < QUIC_VERSION_99)
-      << "Cannot use connection ID of length "
-      << header.destination_connection_id.length() << " with version "
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      header.destination_connection_id, transport_version()))
+      << "AppendIetfPacketHeader: attempted to use connection ID "
+      << header.destination_connection_id << " which is invalid with version "
       << QuicVersionToString(transport_version());
   if (!AppendIetfHeaderTypeByte(header, writer)) {
     return false;
@@ -1892,10 +1888,10 @@
   return QuicTime::Delta::FromMicroseconds(time);
 }
 
-QuicPacketNumber QuicFramer::CalculatePacketNumberFromWire(
+uint64_t QuicFramer::CalculatePacketNumberFromWire(
     QuicPacketNumberLength packet_number_length,
     QuicPacketNumber base_packet_number,
-    QuicPacketNumber packet_number) const {
+    uint64_t packet_number) const {
   // The new packet number might have wrapped to the next epoch, or
   // it might have reverse wrapped to the previous epoch, or it might
   // remain in the same epoch.  Select the packet number closest to the
@@ -1904,12 +1900,14 @@
   // epoch_delta is the delta between epochs the packet number was serialized
   // with, so the correct value is likely the same epoch as the last sequence
   // number or an adjacent epoch.
-  const QuicPacketNumber epoch_delta = UINT64_C(1)
-                                       << (8 * packet_number_length);
-  QuicPacketNumber next_packet_number = base_packet_number + 1;
-  QuicPacketNumber epoch = base_packet_number & ~(epoch_delta - 1);
-  QuicPacketNumber prev_epoch = epoch - epoch_delta;
-  QuicPacketNumber next_epoch = epoch + epoch_delta;
+  if (!base_packet_number.IsInitialized()) {
+    return packet_number;
+  }
+  const uint64_t epoch_delta = UINT64_C(1) << (8 * packet_number_length);
+  uint64_t next_packet_number = base_packet_number.ToUint64() + 1;
+  uint64_t epoch = base_packet_number.ToUint64() & ~(epoch_delta - 1);
+  uint64_t prev_epoch = epoch - epoch_delta;
+  uint64_t next_epoch = epoch + epoch_delta;
 
   return ClosestTo(next_packet_number, epoch + packet_number,
                    ClosestTo(next_packet_number, prev_epoch + packet_number,
@@ -2009,11 +2007,15 @@
 QuicPacketNumberLength QuicFramer::GetMinPacketNumberLength(
     QuicTransportVersion version,
     QuicPacketNumber packet_number) {
-  if (packet_number < 1 << (PACKET_1BYTE_PACKET_NUMBER * 8)) {
+  DCHECK(packet_number.IsInitialized());
+  if (packet_number < QuicPacketNumber(1 << (PACKET_1BYTE_PACKET_NUMBER * 8))) {
     return PACKET_1BYTE_PACKET_NUMBER;
-  } else if (packet_number < 1 << (PACKET_2BYTE_PACKET_NUMBER * 8)) {
+  } else if (packet_number <
+             QuicPacketNumber(1 << (PACKET_2BYTE_PACKET_NUMBER * 8))) {
     return PACKET_2BYTE_PACKET_NUMBER;
-  } else if (packet_number < UINT64_C(1) << (PACKET_4BYTE_PACKET_NUMBER * 8)) {
+  } else if (packet_number <
+             QuicPacketNumber(UINT64_C(1)
+                              << (PACKET_4BYTE_PACKET_NUMBER * 8))) {
     return PACKET_4BYTE_PACKET_NUMBER;
   } else {
     return PACKET_6BYTE_PACKET_NUMBER;
@@ -2051,7 +2053,7 @@
   new_ack_info.first_block_length = frame.packets.LastIntervalLength();
   auto itr = frame.packets.rbegin();
   QuicPacketNumber previous_start = itr->min();
-  new_ack_info.max_block_length = itr->Length();
+  new_ack_info.max_block_length = PacketNumberIntervalLength(*itr);
   ++itr;
 
   // Don't do any more work after getting information for 256 ACK blocks; any
@@ -2060,12 +2062,12 @@
          new_ack_info.num_ack_blocks < std::numeric_limits<uint8_t>::max();
        previous_start = itr->min(), ++itr) {
     const auto& interval = *itr;
-    const QuicPacketNumber total_gap = previous_start - interval.max();
+    const QuicPacketCount total_gap = previous_start - interval.max();
     new_ack_info.num_ack_blocks +=
         (total_gap + std::numeric_limits<uint8_t>::max() - 1) /
         std::numeric_limits<uint8_t>::max();
-    new_ack_info.max_block_length =
-        std::max(new_ack_info.max_block_length, interval.Length());
+    new_ack_info.max_block_length = std::max(
+        new_ack_info.max_block_length, PacketNumberIntervalLength(interval));
   }
   return new_ack_info;
 }
@@ -2073,18 +2075,19 @@
 bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader,
                                               QuicPacketHeader* header) {
   QuicPacketNumber base_packet_number = largest_packet_number_;
-
+  uint64_t full_packet_number;
   if (!ProcessAndCalculatePacketNumber(
           encrypted_reader, header->packet_number_length, base_packet_number,
-          &header->packet_number)) {
+          &full_packet_number)) {
     set_detailed_error("Unable to read packet number.");
     return RaiseError(QUIC_INVALID_PACKET_HEADER);
   }
 
-  if (header->packet_number == kInvalidPacketNumber) {
+  if (!IsValidFullPacketNumber(full_packet_number, transport_version())) {
     set_detailed_error("packet numbers cannot be 0.");
     return RaiseError(QUIC_INVALID_PACKET_HEADER);
   }
+  header->packet_number = QuicPacketNumber(full_packet_number);
 
   if (!visitor_->OnUnauthenticatedHeader(*header)) {
     set_detailed_error(
@@ -2130,7 +2133,7 @@
     } else {
       header->version = ParseQuicVersionLabel(version_label);
       if (header->version.transport_version != QUIC_VERSION_UNSUPPORTED) {
-        if (header->version.transport_version == QUIC_VERSION_99 &&
+        if (header->version.transport_version > QUIC_VERSION_46 &&
             !(type & FLAGS_FIXED_BIT)) {
           set_detailed_error("Fixed bit is 0 in long header.");
           return false;
@@ -2167,7 +2170,7 @@
     header->destination_connection_id = last_serialized_connection_id_;
   }
   if (infer_packet_header_type_from_version_ &&
-      transport_version() == QUIC_VERSION_99 && !(type & FLAGS_FIXED_BIT)) {
+      transport_version() > QUIC_VERSION_46 && !(type & FLAGS_FIXED_BIT)) {
     set_detailed_error("Fixed bit is 0 in short header.");
     return false;
   }
@@ -2240,8 +2243,8 @@
     QuicDataReader* reader,
     QuicPacketNumberLength packet_number_length,
     QuicPacketNumber base_packet_number,
-    QuicPacketNumber* packet_number) {
-  QuicPacketNumber wire_packet_number;
+    uint64_t* packet_number) {
+  uint64_t wire_packet_number;
   if (!reader->ReadBytesToUInt64(packet_number_length, &wire_packet_number)) {
     return false;
   }
@@ -2459,7 +2462,8 @@
     encoded_bytes -= reader->BytesRemaining();
 
     // Check that the frame type is minimally encoded.
-    if (encoded_bytes != QuicDataWriter::GetVarInt62Len(frame_type)) {
+    if (encoded_bytes !=
+        static_cast<size_t>(QuicDataWriter::GetVarInt62Len(frame_type))) {
       // The frame type was not minimally encoded.
       set_detailed_error("Frame type not minimally encoded.");
       return RaiseError(IETF_QUIC_PROTOCOL_VIOLATION);
@@ -2917,12 +2921,21 @@
       ExtractBits(frame_type, kQuicSequenceNumberLengthNumBits,
                   kLargestAckedOffset));
 
-  QuicPacketNumber largest_acked;
+  uint64_t largest_acked;
   if (!reader->ReadBytesToUInt64(largest_acked_length, &largest_acked)) {
     set_detailed_error("Unable to read largest acked.");
     return false;
   }
 
+  if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+      largest_acked < first_sending_packet_number_.ToUint64()) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 1, 3);
+    // Connection always sends packet starting from kFirstSendingPacketNumber >
+    // 0, peer has observed an unsent packet.
+    set_detailed_error("Largest acked is 0.");
+    return false;
+  }
+
   uint64_t ack_delay_time_us;
   if (!reader->ReadUFloat16(&ack_delay_time_us)) {
     set_detailed_error("Unable to read ack delay time.");
@@ -2930,7 +2943,7 @@
   }
 
   if (!visitor_->OnAckFrameStart(
-          largest_acked,
+          QuicPacketNumber(largest_acked),
           ack_delay_time_us == kUFloat16MaxValue
               ? QuicTime::Delta::Infinite()
               : QuicTime::Delta::FromMicroseconds(ack_delay_time_us))) {
@@ -2954,6 +2967,8 @@
 
   if (first_block_length == 0) {
     // For non-empty ACKs, the first block length must be non-zero.
+    // TODO(fayang): remove this if and return false directly when deprecating
+    // gfe2_reloadable_flag_quic_disallow_peer_ack_0.
     if (largest_acked != 0 || num_ack_blocks != 0) {
       set_detailed_error(
           QuicStrCat("First block length is zero but ACK is "
@@ -2963,9 +2978,16 @@
               .c_str());
       return false;
     }
+    DCHECK(!GetQuicReloadableFlag(quic_disallow_peer_ack_0));
   }
-
-  if (first_block_length > largest_acked + 1) {
+  bool first_ack_block_underflow = first_block_length > largest_acked + 1;
+  if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+      first_block_length + first_sending_packet_number_.ToUint64() >
+          largest_acked + 1) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 2, 3);
+    first_ack_block_underflow = true;
+  }
+  if (first_ack_block_underflow) {
     set_detailed_error(QuicStrCat("Underflow with first ack block length ",
                                   first_block_length, " largest acked is ",
                                   largest_acked, ".")
@@ -2973,8 +2995,9 @@
     return false;
   }
 
-  QuicPacketNumber first_received = largest_acked + 1 - first_block_length;
-  if (!visitor_->OnAckRange(first_received, largest_acked + 1)) {
+  uint64_t first_received = largest_acked + 1 - first_block_length;
+  if (!visitor_->OnAckRange(QuicPacketNumber(first_received),
+                            QuicPacketNumber(largest_acked + 1))) {
     // The visitor suppresses further processing of the packet. Although
     // this is not a parsing error, returns false as this is in middle
     // of processing an ack frame,
@@ -2994,7 +3017,14 @@
         set_detailed_error("Unable to ack block length.");
         return false;
       }
-      if (first_received < gap + current_block_length) {
+      bool ack_block_underflow = first_received < gap + current_block_length;
+      if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+          first_received < gap + current_block_length +
+                               first_sending_packet_number_.ToUint64()) {
+        QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 3, 3);
+        ack_block_underflow = true;
+      }
+      if (ack_block_underflow) {
         set_detailed_error(
             QuicStrCat("Underflow with ack block length ", current_block_length,
                        ", end of block is ", first_received - gap, ".")
@@ -3004,8 +3034,9 @@
 
       first_received -= (gap + current_block_length);
       if (current_block_length > 0) {
-        if (!visitor_->OnAckRange(first_received,
-                                  first_received + current_block_length)) {
+        if (!visitor_->OnAckRange(
+                QuicPacketNumber(first_received),
+                QuicPacketNumber(first_received) + current_block_length)) {
           // The visitor suppresses further processing of the packet. Although
           // this is not a parsing error, returns false as this is in middle
           // of processing an ack frame,
@@ -3022,13 +3053,13 @@
     return false;
   }
 
-  if (!ProcessTimestampsInAckFrame(num_received_packets, largest_acked,
-                                   reader)) {
+  if (!ProcessTimestampsInAckFrame(num_received_packets,
+                                   QuicPacketNumber(largest_acked), reader)) {
     return false;
   }
 
   // Done processing the ACK frame.
-  return visitor_->OnAckFrameEnd(first_received);
+  return visitor_->OnAckFrameEnd(QuicPacketNumber(first_received));
 }
 
 bool QuicFramer::ProcessTimestampsInAckFrame(uint8_t num_received_packets,
@@ -3084,11 +3115,17 @@
 bool QuicFramer::ProcessIetfAckFrame(QuicDataReader* reader,
                                      uint64_t frame_type,
                                      QuicAckFrame* ack_frame) {
-  QuicPacketNumber largest_acked;
+  uint64_t largest_acked;
   if (!reader->ReadVarInt62(&largest_acked)) {
     set_detailed_error("Unable to read largest acked.");
     return false;
   }
+  if (largest_acked < first_sending_packet_number_.ToUint64()) {
+    // Connection always sends packet starting from kFirstSendingPacketNumber >
+    // 0, peer has observed an unsent packet.
+    set_detailed_error("Largest acked is 0.");
+    return false;
+  }
   ack_frame->largest_acked = static_cast<QuicPacketNumber>(largest_acked);
   uint64_t ack_delay_time_in_us;
   if (!reader->ReadVarInt62(&ack_delay_time_in_us)) {
@@ -3125,7 +3162,8 @@
     ack_frame->ect_1_count = 0;
     ack_frame->ecn_ce_count = 0;
   }
-  if (!visitor_->OnAckFrameStart(largest_acked, ack_frame->ack_delay_time)) {
+  if (!visitor_->OnAckFrameStart(QuicPacketNumber(largest_acked),
+                                 ack_frame->ack_delay_time)) {
     // The visitor suppresses further processing of the packet. Although this is
     // not a parsing error, returns false as this is in middle of processing an
     // ACK frame.
@@ -3150,14 +3188,15 @@
   }
   // Calculate the packets being acked in the first block.
   //  +1 because AddRange implementation requires [low,high)
-  QuicPacketNumber block_high = largest_acked + 1;
-  QuicPacketNumber block_low = largest_acked - ack_block_value;
+  uint64_t block_high = largest_acked + 1;
+  uint64_t block_low = largest_acked - ack_block_value;
 
   // ack_block_value is the number of packets preceding the
   // largest_acked packet which are in the block being acked. Thus,
   // its maximum value is largest_acked-1. Test this, reporting an
   // error if the value is wrong.
-  if (ack_block_value > largest_acked) {
+  if (ack_block_value + first_sending_packet_number_.ToUint64() >
+      largest_acked) {
     set_detailed_error(QuicStrCat("Underflow with first ack block length ",
                                   ack_block_value + 1, " largest acked is ",
                                   largest_acked, ".")
@@ -3165,7 +3204,8 @@
     return false;
   }
 
-  if (!visitor_->OnAckRange(block_low, block_high)) {
+  if (!visitor_->OnAckRange(QuicPacketNumber(block_low),
+                            QuicPacketNumber(block_high))) {
     // The visitor suppresses further processing of the packet. Although
     // this is not a parsing error, returns false as this is in middle
     // of processing an ACK frame.
@@ -3208,7 +3248,8 @@
       set_detailed_error("Unable to read ack block value.");
       return false;
     }
-    if (ack_block_value > (block_high - 1)) {
+    if (ack_block_value + first_sending_packet_number_.ToUint64() >
+        (block_high - 1)) {
       set_detailed_error(
           QuicStrCat("Underflow with ack block length ", ack_block_value + 1,
                      " latest ack block end is ", block_high - 1, ".")
@@ -3218,7 +3259,8 @@
     // Calculate the low end of the new nth ack block. The +1 is
     // because the encoded value is the blocksize-1.
     block_low = block_high - 1 - ack_block_value;
-    if (!visitor_->OnAckRange(block_low, block_high)) {
+    if (!visitor_->OnAckRange(QuicPacketNumber(block_low),
+                              QuicPacketNumber(block_high))) {
       // The visitor suppresses further processing of the packet. Although
       // this is not a parsing error, returns false as this is in middle
       // of processing an ACK frame.
@@ -3230,19 +3272,22 @@
     ack_block_count--;
   }
 
-  return visitor_->OnAckFrameEnd(block_low);
+  return visitor_->OnAckFrameEnd(QuicPacketNumber(block_low));
 }
 
 bool QuicFramer::ProcessStopWaitingFrame(QuicDataReader* reader,
                                          const QuicPacketHeader& header,
                                          QuicStopWaitingFrame* stop_waiting) {
-  QuicPacketNumber least_unacked_delta;
+  uint64_t least_unacked_delta;
   if (!reader->ReadBytesToUInt64(header.packet_number_length,
                                  &least_unacked_delta)) {
     set_detailed_error("Unable to read least unacked delta.");
     return false;
   }
-  if (header.packet_number < least_unacked_delta) {
+  if (header.packet_number.ToUint64() < least_unacked_delta ||
+      (GetQuicReloadableFlag(
+           quic_close_connection_with_zero_least_unacked_stop_waiting) &&
+       header.packet_number.ToUint64() == least_unacked_delta)) {
     set_detailed_error("Invalid unacked delta.");
     return false;
   }
@@ -3461,9 +3506,10 @@
                                   size_t total_len,
                                   size_t buffer_len,
                                   char* buffer) {
+  DCHECK(packet_number.IsInitialized());
   size_t output_length = 0;
   if (!encrypter_[level]->EncryptPacket(
-          version_.transport_version, packet_number,
+          version_.transport_version, packet_number.ToUint64(),
           QuicStringPiece(buffer, ad_len),  // Associated data
           QuicStringPiece(buffer + ad_len, total_len - ad_len),  // Plaintext
           buffer + ad_len,  // Destination buffer
@@ -3480,6 +3526,7 @@
                                   const QuicPacket& packet,
                                   char* buffer,
                                   size_t buffer_len) {
+  DCHECK(packet_number.IsInitialized());
   DCHECK(encrypter_[level] != nullptr);
 
   QuicStringPiece associated_data =
@@ -3491,7 +3538,7 @@
   // Encrypt the plaintext into the buffer.
   size_t output_length = 0;
   if (!encrypter_[level]->EncryptPacket(
-          version_.transport_version, packet_number, associated_data,
+          version_.transport_version, packet_number.ToUint64(), associated_data,
           packet.Plaintext(version_.transport_version), buffer + ad_len,
           &output_length, buffer_len - ad_len)) {
     RaiseError(QUIC_ENCRYPTION_FAILURE);
@@ -3533,8 +3580,9 @@
       header.nonce != nullptr, header.packet_number_length);
 
   bool success = decrypter_->DecryptPacket(
-      version_.transport_version, header.packet_number, associated_data,
-      encrypted, decrypted_buffer, decrypted_length, buffer_length);
+      version_.transport_version, header.packet_number.ToUint64(),
+      associated_data, encrypted, decrypted_buffer, decrypted_length,
+      buffer_length);
   if (success) {
     visitor_->OnDecryptedPacket(decrypter_level_);
   } else if (alternative_decrypter_ != nullptr) {
@@ -3556,8 +3604,9 @@
 
     if (try_alternative_decryption) {
       success = alternative_decrypter_->DecryptPacket(
-          version_.transport_version, header.packet_number, associated_data,
-          encrypted, decrypted_buffer, decrypted_length, buffer_length);
+          version_.transport_version, header.packet_number.ToUint64(),
+          associated_data, encrypted, decrypted_buffer, decrypted_length,
+          buffer_length);
     }
     if (success) {
       visitor_->OnDecryptedPacket(alternative_decrypter_level_);
@@ -3590,7 +3639,7 @@
   // Type byte, largest_acked, and delay_time are straight-forward.
   size_t ack_frame_size = kQuicFrameTypeSize;
   QuicPacketNumber largest_acked = LargestAcked(frame);
-  ack_frame_size += QuicDataWriter::GetVarInt62Len(largest_acked);
+  ack_frame_size += QuicDataWriter::GetVarInt62Len(largest_acked.ToUint64());
   uint64_t ack_delay_time_us;
   ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
   ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift;
@@ -3650,18 +3699,18 @@
   size_t ack_block_count_size = QuicDataWriter::GetVarInt62Len(ack_block_count);
   ack_frame_size += ack_block_count_size;
 
-  QuicPacketNumber first_ack_block = ack_block_largest - ack_block_smallest;
+  uint64_t first_ack_block = ack_block_largest - ack_block_smallest;
   size_t first_ack_block_size = QuicDataWriter::GetVarInt62Len(first_ack_block);
   ack_frame_size += first_ack_block_size;
 
   // Account for the remaining Intervals, if any.
   while (ack_block_count != 0) {
-    QuicPacketNumber gap_size = ack_block_smallest - itr->max();
+    uint64_t gap_size = ack_block_smallest - itr->max();
     // Decrement per the protocol specification
     size_t size_of_gap_size = QuicDataWriter::GetVarInt62Len(gap_size - 1);
     ack_frame_size += size_of_gap_size;
 
-    QuicPacketNumber block_size = itr->max() - itr->min();
+    uint64_t block_size = itr->max() - itr->min();
     // Decrement per the protocol specification
     size_t size_of_block_size = QuicDataWriter::GetVarInt62Len(block_size - 1);
     ack_frame_size += size_of_block_size;
@@ -3677,6 +3726,7 @@
 size_t QuicFramer::GetAckFrameSize(
     const QuicAckFrame& ack,
     QuicPacketNumberLength packet_number_length) {
+  DCHECK(!ack.packets.Empty());
   size_t ack_size = 0;
 
   if (version_.transport_version == QUIC_VERSION_99) {
@@ -3686,7 +3736,7 @@
   QuicPacketNumberLength largest_acked_length =
       GetMinPacketNumberLength(version_.transport_version, LargestAcked(ack));
   QuicPacketNumberLength ack_block_length = GetMinPacketNumberLength(
-      version_.transport_version, ack_info.max_block_length);
+      version_.transport_version, QuicPacketNumber(ack_info.max_block_length));
 
   ack_size =
       GetMinAckFrameSize(version_.transport_version, largest_acked_length);
@@ -3727,7 +3777,10 @@
                  frame.stream_frame.offset, last_frame_in_packet,
                  frame.stream_frame.data_length) +
              frame.stream_frame.data_length;
-    // TODO(nharper): Add a case for CRYPTO_FRAME here?
+    case CRYPTO_FRAME:
+      return GetMinCryptoFrameSize(frame.crypto_frame->offset,
+                                   frame.crypto_frame->data_length) +
+             frame.crypto_frame->data_length;
     case ACK_FRAME: {
       return GetAckFrameSize(*frame.ack_frame, packet_number_length);
     }
@@ -3913,12 +3966,13 @@
 bool QuicFramer::AppendPacketNumber(QuicPacketNumberLength packet_number_length,
                                     QuicPacketNumber packet_number,
                                     QuicDataWriter* writer) {
-  size_t length = packet_number_length;
-  if (length != 1 && length != 2 && length != 4 && length != 6 && length != 8) {
-    QUIC_BUG << "Invalid packet_number_length: " << length;
+  DCHECK(packet_number.IsInitialized());
+  if (!IsValidPacketNumberLength(packet_number_length)) {
+    QUIC_BUG << "Invalid packet_number_length: " << packet_number_length;
     return false;
   }
-  return writer->WriteBytesToUInt64(packet_number_length, packet_number);
+  return writer->WriteBytesToUInt64(packet_number_length,
+                                    packet_number.ToUint64());
 }
 
 // static
@@ -3947,10 +4001,18 @@
 // static
 bool QuicFramer::AppendAckBlock(uint8_t gap,
                                 QuicPacketNumberLength length_length,
-                                QuicPacketNumber length,
+                                uint64_t length,
                                 QuicDataWriter* writer) {
+  if (length == 0) {
+    if (!IsValidPacketNumberLength(length_length)) {
+      QUIC_BUG << "Invalid packet_number_length: " << length_length;
+      return false;
+    }
+    return writer->WriteUInt8(gap) &&
+           writer->WriteBytesToUInt64(length_length, length);
+  }
   return writer->WriteUInt8(gap) &&
-         AppendPacketNumber(length_length, length, writer);
+         AppendPacketNumber(length_length, QuicPacketNumber(length), writer);
 }
 
 bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame,
@@ -4120,8 +4182,20 @@
     set_detailed_error("Writing data length failed.");
     return false;
   }
-  // TODO(nharper): Append stream frame contents.
-  return false;
+  if (data_producer_ == nullptr) {
+    if (frame.data_buffer == nullptr ||
+        !writer->WriteBytes(frame.data_buffer, frame.data_length)) {
+      set_detailed_error("Writing frame data failed.");
+      return false;
+    }
+  } else {
+    DCHECK_EQ(nullptr, frame.data_buffer);
+    if (!data_producer_->WriteCryptoData(frame.level, frame.offset,
+                                         frame.data_length, writer)) {
+      return false;
+    }
+  }
+  return true;
 }
 
 void QuicFramer::set_version(const ParsedQuicVersion version) {
@@ -4139,8 +4213,9 @@
   QuicPacketNumber largest_acked = LargestAcked(frame);
   QuicPacketNumberLength largest_acked_length =
       GetMinPacketNumberLength(version_.transport_version, largest_acked);
-  QuicPacketNumberLength ack_block_length = GetMinPacketNumberLength(
-      version_.transport_version, new_ack_info.max_block_length);
+  QuicPacketNumberLength ack_block_length =
+      GetMinPacketNumberLength(version_.transport_version,
+                               QuicPacketNumber(new_ack_info.max_block_length));
   // Calculate available bytes for timestamps and ack blocks.
   int32_t available_timestamp_and_ack_block_bytes =
       writer->capacity() - writer->length() - ack_block_length -
@@ -4199,7 +4274,8 @@
   }
 
   // First ack block length.
-  if (!AppendPacketNumber(ack_block_length, new_ack_info.first_block_length,
+  if (!AppendPacketNumber(ack_block_length,
+                          QuicPacketNumber(new_ack_info.first_block_length),
                           writer)) {
     return false;
   }
@@ -4223,7 +4299,7 @@
          itr != frame.packets.rend() && num_ack_blocks_written < num_ack_blocks;
          previous_start = itr->min(), ++itr) {
       const auto& interval = *itr;
-      const QuicPacketNumber total_gap = previous_start - interval.max();
+      const uint64_t total_gap = previous_start - interval.max();
       const size_t num_encoded_gaps =
           (total_gap + std::numeric_limits<uint8_t>::max() - 1) /
           std::numeric_limits<uint8_t>::max();
@@ -4251,8 +4327,8 @@
           total_gap -
           (num_encoded_gaps - 1) * std::numeric_limits<uint8_t>::max();
       // Append the final ACK block with a non-empty size.
-      if (!AppendAckBlock(last_gap, ack_block_length, interval.Length(),
-                          writer)) {
+      if (!AppendAckBlock(last_gap, ack_block_length,
+                          PacketNumberIntervalLength(interval), writer)) {
         return false;
       }
       ++num_ack_blocks_written;
@@ -4297,8 +4373,7 @@
 
   auto it = frame.received_packet_times.begin();
   QuicPacketNumber packet_number = it->first;
-  QuicPacketNumber delta_from_largest_observed =
-      LargestAcked(frame) - packet_number;
+  uint64_t delta_from_largest_observed = LargestAcked(frame) - packet_number;
 
   DCHECK_GE(std::numeric_limits<uint8_t>::max(), delta_from_largest_observed);
   if (delta_from_largest_observed > std::numeric_limits<uint8_t>::max()) {
@@ -4345,10 +4420,11 @@
                                         const QuicStopWaitingFrame& frame,
                                         QuicDataWriter* writer) {
   DCHECK_GE(QUIC_VERSION_43, version_.transport_version);
-  DCHECK_GE(header.packet_number, frame.least_unacked);
-  const QuicPacketNumber least_unacked_delta =
+  DCHECK(frame.least_unacked.IsInitialized() &&
+         header.packet_number >= frame.least_unacked);
+  const uint64_t least_unacked_delta =
       header.packet_number - frame.least_unacked;
-  const QuicPacketNumber length_shift = header.packet_number_length * 8;
+  const uint64_t length_shift = header.packet_number_length * 8;
 
   if (least_unacked_delta >> length_shift > 0) {
     QUIC_BUG << "packet_number_length " << header.packet_number_length
@@ -4358,8 +4434,12 @@
              << " version:" << version_.transport_version;
     return false;
   }
-  if (!AppendPacketNumber(header.packet_number_length, least_unacked_delta,
-                          writer)) {
+  if (least_unacked_delta == 0) {
+    return writer->WriteBytesToUInt64(header.packet_number_length,
+                                      least_unacked_delta);
+  }
+  if (!AppendPacketNumber(header.packet_number_length,
+                          QuicPacketNumber(least_unacked_delta), writer)) {
     QUIC_BUG << " seq failed: " << header.packet_number_length;
     return false;
   }
@@ -4382,7 +4462,7 @@
     return 0;
   }
   available_space -= encoded_size;
-  uint64_t previous_ack_end = itr->min();
+  QuicPacketNumber previous_ack_end = itr->min();
   ack_block_count--;
 
   while (ack_block_count) {
@@ -4426,7 +4506,7 @@
   }
 
   QuicPacketNumber largest_acked = LargestAcked(frame);
-  if (!writer->WriteVarInt62(largest_acked)) {
+  if (!writer->WriteVarInt62(largest_acked.ToUint64())) {
     set_detailed_error("No room for largest-acked in ack frame");
     return false;
   }
@@ -4480,9 +4560,9 @@
   // Case 2 or 3
   auto itr = frame.packets.rbegin();
 
-  QuicPacketNumber ack_block_largest = largest_acked;
+  QuicPacketNumber ack_block_largest(largest_acked);
   QuicPacketNumber ack_block_smallest;
-  if ((itr->max() - 1) == largest_acked) {
+  if ((itr->max() - 1) == QuicPacketNumber(largest_acked)) {
     // If largest_acked + 1 is equal to the Max() of the first Interval
     // in the QuicAckFrame then the first Interval is the first ack block of the
     // frame; remaining Intervals are additional ack blocks.  The QuicAckFrame's
@@ -4513,7 +4593,7 @@
     return false;
   }
 
-  QuicPacketNumber first_ack_block = ack_block_largest - ack_block_smallest;
+  uint64_t first_ack_block = ack_block_largest - ack_block_smallest;
   if (!writer->WriteVarInt62(first_ack_block)) {
     set_detailed_error("No room for first ack block in ack frame");
     return false;
@@ -4521,13 +4601,13 @@
 
   // For the remaining QuicAckFrame Intervals, if any
   while (ack_block_count != 0) {
-    QuicPacketNumber gap_size = ack_block_smallest - itr->max();
+    uint64_t gap_size = ack_block_smallest - itr->max();
     if (!writer->WriteVarInt62(gap_size - 1)) {
       set_detailed_error("No room for gap block in ack frame");
       return false;
     }
 
-    QuicPacketNumber block_size = itr->max() - itr->min();
+    uint64_t block_size = itr->max() - itr->min();
     if (!writer->WriteVarInt62(block_size - 1)) {
       set_detailed_error("No room for nth ack block in ack frame");
       return false;
@@ -4608,6 +4688,9 @@
 bool QuicFramer::AppendBlockedFrame(const QuicBlockedFrame& frame,
                                     QuicDataWriter* writer) {
   if (version_.transport_version == QUIC_VERSION_99) {
+    // TODO(fkastenholz): This should be converted to use
+    // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+    // and not rely on 0.
     if (frame.stream_id == 0) {
       return AppendIetfBlockedFrame(frame, writer);
     }
@@ -4985,6 +5068,9 @@
 bool QuicFramer::ProcessIetfBlockedFrame(QuicDataReader* reader,
                                          QuicBlockedFrame* frame) {
   // Indicates that it is a BLOCKED frame (as opposed to STREAM_BLOCKED).
+  // TODO(fkastenholz): This should be converted to use
+  // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+  // and not rely on 0.
   frame->stream_id = 0;
   if (!reader->ReadVarInt62(&frame->offset)) {
     set_detailed_error("Can not read blocked offset.");
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 828daa0..46280c5 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -270,6 +270,10 @@
                                       QuicStreamOffset offset,
                                       bool last_frame_in_packet,
                                       QuicPacketLength data_length);
+  // Returns the overhead of framing a CRYPTO frame with the specific offset and
+  // data length provided, but not counting the size of the data payload.
+  static size_t GetMinCryptoFrameSize(QuicStreamOffset offset,
+                                      QuicPacketLength data_length);
   static size_t GetMessageFrameSize(QuicTransportVersion version,
                                     bool last_frame_in_packet,
                                     QuicByteCount length);
@@ -374,6 +378,12 @@
                                         char* buffer,
                                         size_t packet_length);
 
+  // Serializes an IETF probing packet, which is a padded PING packet.
+  // Returns the length of the packet. Returns 0 if it fails to serialize.
+  size_t BuildIetfConnectivityProbingPacket(const QuicPacketHeader& header,
+                                            char* buffer,
+                                            size_t packet_length);
+
   // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also
   // fills the packet with padding.
   size_t BuildPaddedPathChallengePacket(const QuicPacketHeader& header,
@@ -506,7 +516,7 @@
   // Returns header wire format of last received packet.
   // Please do not use this method.
   // TODO(fayang): Remove last_header_form_ when deprecating
-  // quic_proxy_use_real_packet_format_when_reject flag.
+  // quic_fix_last_packet_is_ietf_quic flag.
   PacketHeaderFormat GetLastPacketFormat() const;
 
   void set_validate_flags(bool value) { validate_flags_ = value; }
@@ -534,6 +544,10 @@
 
   QuicTime creation_time() const { return creation_time_; }
 
+  QuicPacketNumber first_sending_packet_number() const {
+    return first_sending_packet_number_;
+  }
+
  private:
   friend class test::QuicFramerPeer;
 
@@ -545,9 +559,9 @@
     ~AckFrameInfo();
 
     // The maximum ack block length.
-    QuicPacketNumber max_block_length;
+    QuicPacketCount max_block_length;
     // Length of first ack block.
-    QuicPacketNumber first_block_length;
+    QuicPacketCount first_block_length;
     // Number of ACK blocks needed for the ACK frame.
     size_t num_ack_blocks;
   };
@@ -597,7 +611,7 @@
       QuicDataReader* reader,
       QuicPacketNumberLength packet_number_length,
       QuicPacketNumber base_packet_number,
-      QuicPacketNumber* packet_number);
+      uint64_t* packet_number);
   bool ProcessFrameData(QuicDataReader* reader, const QuicPacketHeader& header);
   bool ProcessIetfFrameData(QuicDataReader* reader,
                             const QuicPacketHeader& header);
@@ -635,10 +649,10 @@
 
   // Returns the full packet number from the truncated
   // wire format version and the last seen packet number.
-  QuicPacketNumber CalculatePacketNumberFromWire(
+  uint64_t CalculatePacketNumberFromWire(
       QuicPacketNumberLength packet_number_length,
       QuicPacketNumber base_packet_number,
-      QuicPacketNumber packet_number) const;
+      uint64_t packet_number) const;
 
   // Returns the QuicTime::Delta corresponding to the time from when the framer
   // was created.
@@ -675,7 +689,7 @@
   // successfully appended.
   static bool AppendAckBlock(uint8_t gap,
                              QuicPacketNumberLength length_length,
-                             QuicPacketNumber length,
+                             uint64_t length,
                              QuicDataWriter* writer);
 
   static uint8_t GetPacketNumberFlags(
@@ -869,13 +883,15 @@
   // The last timestamp received if process_timestamps_ is true.
   QuicTime::Delta last_timestamp_;
 
+  // If this is a framer of a connection, this is the packet number of first
+  // sending packet. If this is a framer of a framer of dispatcher, this is the
+  // packet number of sent packets (for those which have packet number).
+  const QuicPacketNumber first_sending_packet_number_;
+
   // If not null, framer asks data_producer_ to write stream frame data. Not
   // owned. TODO(fayang): Consider add data producer to framer's constructor.
   QuicStreamFrameDataProducer* data_producer_;
 
-  // Latched value of quic_process_stateless_reset_at_client_only flag.
-  const bool process_stateless_reset_at_client_only_;
-
   // If true, framer infers packet header type (IETF/GQUIC) from version_.
   // Otherwise, framer infers packet header type from first byte of a received
   // packet.
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index a75bceb..888c87e 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -36,8 +36,8 @@
 namespace test {
 namespace {
 
-const QuicPacketNumber kEpoch = UINT64_C(1) << 32;
-const QuicPacketNumber kMask = kEpoch - 1;
+const uint64_t kEpoch = UINT64_C(1) << 32;
+const uint64_t kMask = kEpoch - 1;
 
 const QuicUint128 kTestStatelessResetToken = 1010101;  // 0x0F69B5
 
@@ -51,10 +51,11 @@
   return TestConnectionId(UINT64_C(0xFEDCBA9876543211));
 }
 
-const QuicPacketNumber kPacketNumber = UINT64_C(0x12345678);
-const QuicPacketNumber kSmallLargestObserved = UINT16_C(0x1234);
-const QuicPacketNumber kSmallMissingPacket = UINT16_C(0x1233);
-const QuicPacketNumber kLeastUnacked = UINT64_C(0x012345670);
+const QuicPacketNumber kPacketNumber = QuicPacketNumber(UINT64_C(0x12345678));
+const QuicPacketNumber kSmallLargestObserved =
+    QuicPacketNumber(UINT16_C(0x1234));
+const QuicPacketNumber kSmallMissingPacket = QuicPacketNumber(UINT16_C(0x1233));
+const QuicPacketNumber kLeastUnacked = QuicPacketNumber(UINT64_C(0x012345670));
 const QuicStreamId kStreamId = UINT64_C(0x01020304);
 // Note that the high 4 bits of the stream offset must be less than 0x40
 // in order to ensure that the value can be encoded using VarInt62 encoding.
@@ -65,7 +66,7 @@
 // This is the largest packet number that can be represented in IETF QUIC
 // varint62 format.
 const QuicPacketNumber kLargestIetfLargestObserved =
-    UINT64_C(0x3fffffffffffffff);
+    QuicPacketNumber(UINT64_C(0x3fffffffffffffff));
 // Encodings for the two bits in a VarInt62 that
 // describe the length of the VarInt61. For binary packet
 // formats in this file, the convention is to code the
@@ -83,14 +84,14 @@
   bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; }
   bool SetIV(QuicStringPiece iv) override { return true; }
   bool EncryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
                      size_t* output_length,
                      size_t max_output_length) override {
     version_ = version;
-    packet_number_ = packet_number;
+    packet_number_ = QuicPacketNumber(packet_number);
     associated_data_ = QuicString(associated_data);
     plaintext_ = QuicString(plaintext);
     memcpy(output, plaintext.data(), plaintext.length());
@@ -129,14 +130,14 @@
     return true;
   }
   bool DecryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
                      size_t* output_length,
                      size_t max_output_length) override {
     version_ = version;
-    packet_number_ = packet_number;
+    packet_number_ = QuicPacketNumber(packet_number);
     associated_data_ = QuicString(associated_data);
     ciphertext_ = QuicString(ciphertext);
     memcpy(output, ciphertext.data(), ciphertext.length());
@@ -223,7 +224,13 @@
   }
 
   bool OnCryptoFrame(const QuicCryptoFrame& frame) override {
-    // TODO(nharper): Implement.
+    ++frame_count_;
+    // Save a copy of the data so it is valid after the packet is processed.
+    QuicString* string_data =
+        new QuicString(frame.data_buffer, frame.data_length);
+    crypto_data_.push_back(QuicWrapUnique(string_data));
+    crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>(
+        ENCRYPTION_NONE, frame.offset, *string_data));
     return true;
   }
 
@@ -373,6 +380,7 @@
   std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_;
   std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
   std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_;
+  std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_;
   std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_;
   std::vector<std::unique_ptr<QuicStopWaitingFrame>> stop_waiting_frames_;
   std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_;
@@ -393,6 +401,7 @@
   QuicRetireConnectionIdFrame retire_connection_id_;
   QuicNewTokenFrame new_token_;
   std::vector<std::unique_ptr<QuicString>> stream_data_;
+  std::vector<std::unique_ptr<QuicString>> crypto_data_;
 };
 
 // Simple struct for defining a packet's content, and associated
@@ -428,6 +437,7 @@
                          std::unique_ptr<QuicEncrypter>(encrypter_));
 
     framer_.set_visitor(&visitor_);
+    framer_.InferPacketHeaderTypeFromVersion();
   }
 
   // Helper function to get unsigned char representation of the handshake
@@ -577,9 +587,9 @@
     EXPECT_EQ(str, QuicString(frame->data_buffer, frame->data_length));
   }
 
-  void CheckCalculatePacketNumber(QuicPacketNumber expected_packet_number,
+  void CheckCalculatePacketNumber(uint64_t expected_packet_number,
                                   QuicPacketNumber last_packet_number) {
-    QuicPacketNumber wire_packet_number = expected_packet_number & kMask;
+    uint64_t wire_packet_number = expected_packet_number & kMask;
     EXPECT_EQ(expected_packet_number,
               QuicFramerPeer::CalculatePacketNumberFromWire(
                   &framer_, PACKET_4BYTE_PACKET_NUMBER, last_packet_number,
@@ -623,12 +633,17 @@
 
 TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) {
   // A few quick manual sanity checks.
-  CheckCalculatePacketNumber(UINT64_C(1), UINT64_C(0));
-  CheckCalculatePacketNumber(kEpoch + 1, kMask);
-  CheckCalculatePacketNumber(kEpoch, kMask);
+  CheckCalculatePacketNumber(UINT64_C(1), QuicPacketNumber());
+  CheckCalculatePacketNumber(kEpoch + 1, QuicPacketNumber(kMask));
+  CheckCalculatePacketNumber(kEpoch, QuicPacketNumber(kMask));
+  for (uint64_t j = 0; j < 10; j++) {
+    CheckCalculatePacketNumber(j, QuicPacketNumber());
+    CheckCalculatePacketNumber(kEpoch - 1 - j, QuicPacketNumber());
+  }
 
   // Cases where the last number was close to the start of the range.
-  for (uint64_t last = 0; last < 10; last++) {
+  for (QuicPacketNumber last = QuicPacketNumber(1); last < QuicPacketNumber(10);
+       last++) {
     // Small numbers should not wrap (even if they're out of order).
     for (uint64_t j = 0; j < 10; j++) {
       CheckCalculatePacketNumber(j, last);
@@ -644,7 +659,7 @@
 TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochEnd) {
   // Cases where the last number was close to the end of the range
   for (uint64_t i = 0; i < 10; i++) {
-    QuicPacketNumber last = kEpoch - i;
+    QuicPacketNumber last = QuicPacketNumber(kEpoch - i);
 
     // Small numbers should wrap.
     for (uint64_t j = 0; j < 10; j++) {
@@ -665,7 +680,7 @@
   const uint64_t cur_epoch = 2 * kEpoch;
   // Cases where the last number was close to the start of the range
   for (uint64_t i = 0; i < 10; i++) {
-    uint64_t last = cur_epoch + i;
+    QuicPacketNumber last = QuicPacketNumber(cur_epoch + i);
     // Small number should not wrap (even if they're out of order).
     for (uint64_t j = 0; j < 10; j++) {
       CheckCalculatePacketNumber(cur_epoch + j, last);
@@ -684,7 +699,7 @@
   const uint64_t next_epoch = 3 * kEpoch;
   // Cases where the last number was close to the end of the range
   for (uint64_t i = 0; i < 10; i++) {
-    QuicPacketNumber last = next_epoch - 1 - i;
+    QuicPacketNumber last = QuicPacketNumber(next_epoch - 1 - i);
 
     // Small numbers should wrap.
     for (uint64_t j = 0; j < 10; j++) {
@@ -707,7 +722,7 @@
   for (uint64_t i = 0; i < 10; i++) {
     // Subtract 1, because the expected next packet number is 1 more than the
     // last packet number.
-    QuicPacketNumber last = max_number - i - 1;
+    QuicPacketNumber last = QuicPacketNumber(max_number - i - 1);
 
     // Small numbers should not wrap, because they have nowhere to go.
     for (uint64_t j = 0; j < 10; j++) {
@@ -749,10 +764,21 @@
     // packet number
     0x78, 0x56, 0x34, 0x12,
   };
+  unsigned char packet47[kMaxPacketSize + 1] = {
+    // type (short header 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x78, 0x56, 0x34, 0x12,
+  };
   // clang-format on
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() > QUIC_VERSION_43) {
+  if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
   }
@@ -826,9 +852,9 @@
 
 TEST_P(QuicFramerTest, LongPacketHeader) {
   // clang-format off
-  PacketFragments packet = {
+  PacketFragments packet44 = {
     // type (long header with packet type INITIAL)
-    {"Unable to read public flags.",
+    {"Unable to read type.",
      {0xFF}},
     // version tag
     {"Unable to read protocol version.",
@@ -843,14 +869,33 @@
     {"Unable to read packet number.",
      {0x12, 0x34, 0x56, 0x78}},
   };
+  PacketFragments packet47 = {
+    // type (long header with packet type INITIAL)
+    {"Unable to read type.",
+     {0xC3}},
+    // version tag
+    {"Unable to read protocol version.",
+     {QUIC_VERSION_BYTES}},
+    // connection_id length
+    {"Unable to read ConnectionId length.",
+     {0x50}},
+    // connection_id
+    {"Unable to read Destination ConnectionId.",
+     {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+    // packet number
+    {"Unable to read packet number.",
+     {0x12, 0x34, 0x56, 0x78}},
+  };
   // clang-format on
 
   if (framer_.transport_version() <= QUIC_VERSION_43) {
     return;
   }
 
+  PacketFragments& fragments =
+      framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44;
   std::unique_ptr<QuicEncryptedPacket> encrypted(
-      AssemblePacketFromFragments(packet));
+      AssemblePacketFromFragments(fragments));
 
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
   EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
@@ -861,7 +906,9 @@
   EXPECT_TRUE(visitor_.header_->version_flag);
   EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
 
-  CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER);
+  CheckFramingBoundaries(
+      framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44,
+      QUIC_INVALID_PACKET_HEADER);
 }
 
 TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
@@ -900,7 +947,7 @@
          {0x12, 0x34, 0x56, 0x78}},
    };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
         // type (short header, 4 byte packet number)
         {"Unable to read type.",
          {0x43}},
@@ -912,8 +959,8 @@
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() == QUIC_VERSION_99
-          ? packet99
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
           : (framer_.transport_version() > QUIC_VERSION_43
                  ? packet44
                  : (framer_.transport_version() == QUIC_VERSION_35 ? packet
@@ -966,7 +1013,7 @@
 
   PacketFragments packet44 = {
       // type (long header with packet type ZERO_RTT_PROTECTED)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0xFC}},
       // version tag
       {"Unable to read protocol version.",
@@ -982,10 +1029,10 @@
        {0x12, 0x34, 0x56, 0x78}},
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
       // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes
       // packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0xD3}},
       // version tag
       {"Unable to read protocol version.",
@@ -1003,8 +1050,8 @@
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() == QUIC_VERSION_99
-          ? packet99
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
           : (framer_.transport_version() > QUIC_VERSION_43
                  ? packet44
                  : (framer_.transport_version() == QUIC_VERSION_35 ? packet
@@ -1054,7 +1101,7 @@
 
   PacketFragments packet44 = {
       // type (short header, 4 byte packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0x32}},
       // connection_id
       {"Unable to read Destination ConnectionId.",
@@ -1063,13 +1110,27 @@
       {"Unable to read packet number.",
        {0x12, 0x34, 0x56, 0x78}},
   };
+
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"Unable to read type.",
+       {0x43}},
+      // connection_id
+      {"Unable to read Destination ConnectionId.",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"Unable to read packet number.",
+       {0x12, 0x34, 0x56, 0x78}},
+  };
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() == QUIC_VERSION_35 ? packet
-                                                            : packet39);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() == QUIC_VERSION_35 ? packet
+                                                                   : packet39));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1114,7 +1175,7 @@
 
   PacketFragments packet44 = {
       // type (short header, 2 byte packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0x31}},
       // connection_id
       {"Unable to read Destination ConnectionId.",
@@ -1123,13 +1184,27 @@
       {"Unable to read packet number.",
        {0x56, 0x78}},
   };
+
+  PacketFragments packet47 = {
+      // type (short header, 2 byte packet number)
+      {"Unable to read type.",
+       {0x41}},
+      // connection_id
+      {"Unable to read Destination ConnectionId.",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"Unable to read packet number.",
+       {0x56, 0x78}},
+  };
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() == QUIC_VERSION_35 ? packet
-                                                            : packet39);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() == QUIC_VERSION_35 ? packet
+                                                                   : packet39));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1163,7 +1238,7 @@
 
   PacketFragments packet44 = {
       // type (8 byte connection_id and 1 byte packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0x30}},
       // connection_id
       {"Unable to read Destination ConnectionId.",
@@ -1173,10 +1248,24 @@
        {0x78}},
   };
 
+  PacketFragments packet47 = {
+      // type (8 byte connection_id and 1 byte packet number)
+      {"Unable to read type.",
+       {0x40}},
+      // connection_id
+      {"Unable to read Destination ConnectionId.",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"Unable to read packet number.",
+       {0x78}},
+  };
+
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet;
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1318,7 +1407,7 @@
     0x00, 0x00, 0x00, 0x00
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet
     // number.
     0xD0,
@@ -1344,9 +1433,9 @@
 
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_size = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -1571,9 +1660,9 @@
     0x00, 0x00,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
-    0x32,
+    0x43,
     // connection_id
     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
     // packet number
@@ -1581,8 +1670,35 @@
 
     // paddings
     0x00, 0x00,
-    // frame type - Stream with FIN, LEN, and OFFSET bits set.
-    0x10 | 0x01 | 0x02 | 0x04,
+    // frame type (stream frame with fin)
+    0xFF,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // offset
+    0x3A, 0x98, 0xFE, 0xDC,
+    0x32, 0x10, 0x76, 0x54,
+    // data length
+    0x00, 0x0c,
+    // data
+    'h',  'e',  'l',  'l',
+    'o',  ' ',  'w',  'o',
+    'r',  'l',  'd',  '!',
+    // paddings
+    0x00, 0x00,
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // paddings
+    0x00, 0x00,
+    // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set.
+    0x08 | 0x01 | 0x02 | 0x04,
 
     // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
@@ -1608,6 +1724,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -1726,6 +1845,36 @@
          'r',  'l',  'd',  '!'}},
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (stream frame with fin)
+      {"",
+       {0xFF}},
+      // stream id
+      {"Unable to read stream_id.",
+       {0x01, 0x02, 0x03, 0x04}},
+      // offset
+      {"Unable to read offset.",
+       {0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+      {"Unable to read frame data.",
+       {
+         // data length
+         0x00, 0x0c,
+         // data
+         'h',  'e',  'l',  'l',
+         'o',  ' ',  'w',  'o',
+         'r',  'l',  'd',  '!'}},
+  };
+
   PacketFragments packet99 = {
       // type (short header, 4 byte packet number)
       {"",
@@ -1736,9 +1885,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type - Stream with FIN, LEN, and OFFSET bits set.
+      // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set.
       {"",
-       { 0x10 | 0x01 | 0x02 | 0x04 }},
+       { 0x08 | 0x01 | 0x02 | 0x04 }},
       // stream id
       {"Unable to read stream_id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -1760,10 +1909,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -1802,9 +1954,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type - Stream with FIN, LEN, and OFFSET bits set.
+      // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set.
       {"",
-       { 0x10 | 0x01 | 0x02 | 0x04 }},
+       { 0x08 | 0x01 | 0x02 | 0x04 }},
       // stream id
       {"Unable to read stream_id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -2123,6 +2275,36 @@
           'r',  'l',  'd',  '!'}},
   };
 
+  PacketFragments packet47 = {<