From 6e4b280e9365b09aca8c75af8ba340a2baf1fc7b Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Thu, 15 Aug 2019 09:34:44 -0400
Subject: [PATCH] Do not update leases on every mutable write.

---
 src/_zkapauthorizer/_storage_server.py        |  8 +++-
 .../tests/test_storage_protocol.py            | 42 +++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py
index a3364f5..e917100 100644
--- a/src/_zkapauthorizer/_storage_server.py
+++ b/src/_zkapauthorizer/_storage_server.py
@@ -230,7 +230,13 @@ class ZKAPAuthorizerStorageServer(Referenceable):
             same from the perspective of token validation.
         """
         self._validate_tokens(tokens)
-        return self._original.remote_slot_testv_and_readv_and_writev(*a, **kw)
+        # Skip over the remotely exposed method and jump to the underlying
+        # implementation which accepts one additional parameter that we know
+        # about (and don't expose over the network): renew_leases.  We always
+        # pass False for this because we want to manage leases completely
+        # separately from writes.
+        kw["renew_leases"] = False
+        return self._original.slot_testv_and_readv_and_writev(*a, **kw)
 
     def remote_slot_readv(self, *a, **kw):
         """
diff --git a/src/_zkapauthorizer/tests/test_storage_protocol.py b/src/_zkapauthorizer/tests/test_storage_protocol.py
index d5fc174..e98e64e 100644
--- a/src/_zkapauthorizer/tests/test_storage_protocol.py
+++ b/src/_zkapauthorizer/tests/test_storage_protocol.py
@@ -437,6 +437,48 @@ class ShareTests(TestCase):
                     sharenum,
                 ),
             )
+    @given(
+        storage_index=storage_indexes(),
+        secrets=tuples(
+            write_enabler_secrets(),
+            lease_renew_secrets(),
+            lease_cancel_secrets(),
+        ),
+        test_and_write_vectors_for_shares=test_and_write_vectors_for_shares(),
+    )
+    def test_mutable_write_preserves_lease(self, storage_index, secrets, test_and_write_vectors_for_shares):
+        """
+        When mutable share data is written using *slot_testv_and_readv_and_writev*
+        any leases on the corresponding slot remain the same.
+        """
+        # Hypothesis causes our storage server to be used many times.  Clean
+        # up between iterations.
+        cleanup_storage_server(self.anonymous_storage_server)
+
+        wrote, read = extract_result(
+            self.client.slot_testv_and_readv_and_writev(
+                storage_index,
+                secrets=secrets,
+                tw_vectors={
+                    k: v.for_call()
+                    for (k, v)
+                    in test_and_write_vectors_for_shares.items()
+                },
+                r_vector=[],
+            ),
+        )
+
+        self.assertThat(
+            wrote,
+            Equals(True),
+            u"Server rejected a write to a new mutable slot",
+        )
+
+        # There are *no* leases on this newly written slot!
+        self.assertThat(
+            list(self.anonymous_storage_server.get_slot_leases(storage_index)),
+            Equals([]),
+        )
 
 
 def write_vector_to_read_vector(write_vector):
-- 
GitLab