diff --git a/.circleci/config.yml b/.circleci/config.yml
index 4cb017e96e66ed558b786ab5375e725c3bbe3f4e..d477118ab06beb28edc6d95b03a6d2767342e67b 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -135,10 +135,23 @@ jobs:
             ZKAPAUTHORIZER_HYPOTHESIS_PROFILE: "ci"
 
   linux-tests: &LINUX_TESTS
+    parameters:
+      tahoe-version:
+        # A Tahoe-LAFS version number string like "1.15.0" which corresponds
+        # to a version known by default.nix .  This is the version that will
+        # be declared as a dependency of the Nix package of ZKAPAuthorizer
+        # (and therefore used in the test run and pulled in should you install
+        # this package).
+        type: "string"
+
     docker:
       # Run in a highly Nix-capable environment.
       - image: "nixos/nix:latest"
 
+    # Tahoe-LAFS requires more memory than we get from the default resource
+    # class and sometimes we have to build it.
+    resource_class: "large"
+
     environment:
       # CACHIX_AUTH_TOKEN is manually set in the CircleCI web UI and allows us to push to CACHIX_NAME.
       CACHIX_NAME: "privatestorage-opensource"
@@ -150,7 +163,7 @@ jobs:
       # somewhat current as of the time of this comment.  We can bump it to a
       # newer version when that makes sense.  Meanwhile, the platform won't
       # shift around beneath us unexpectedly.
-      NIX_PATH: "nixpkgs=https://github.com/PrivateStorageio/nixpkgs/archive/730129887a84a8f84f3b78ffac7add72aeb551b6.tar.gz"
+      NIX_PATH: "nixpkgs=https://github.com/PrivateStorageio/nixpkgs/archive/c12c213c1c96bd1fea9f83f9e9e1fea28d0eaec6.tar.gz"
 
     steps:
       - run:
@@ -178,6 +191,7 @@ jobs:
             nix-build \
               --argstr hypothesisProfile ci \
               --arg collectCoverage true \
+              --argstr tahoe-lafs << parameters.tahoe-version >> \
               --attr doc
 
       - run:
@@ -209,7 +223,13 @@ workflows:
   everything:
     jobs:
     - "documentation"
-    - "linux-tests"
+    - "linux-tests":
+        matrix:
+          parameters:
+            tahoe-version:
+            - "1.14.0"
+            - "1.16.0rc1"
+
     - "macos-tests":
         matrix:
           parameters:
diff --git a/default.nix b/default.nix
index 9910ed370f3e0a4562f94beddde68cb87e240120..6d24dab31df44598c1baff1feefa9e2e836cf724 100644
--- a/default.nix
+++ b/default.nix
@@ -3,12 +3,17 @@
 , collectCoverage ? false
 , testSuite ? null
 , trialArgs ? null
-, tahoe-lafs ? null
+, tahoe-lafs ? "1.14.0"
 }:
 let
+  tahoe-packages = {
+    "1.14.0"    = pkgs.python2Packages.tahoe-lafs-1_14;
+    "1.16.0rc1" = pkgs.python2Packages.callPackage ./nix/tahoe-lafs-1_16.nix { };
+  };
+  tahoe-lafs' = builtins.getAttr tahoe-lafs tahoe-packages;
+
   pkgs' = pkgs.extend (import ./overlays.nix);
   callPackage = pkgs'.python27Packages.callPackage;
-  tahoe-lafs' = if tahoe-lafs == null then pkgs.python2Packages.tahoe-lafs-1_14 else tahoe-lafs;
 in
 callPackage ./zkapauthorizer.nix {
   challenge-bypass-ristretto = callPackage ./python-challenge-bypass-ristretto.nix { };
diff --git a/nix/repo-1_16_0_rc1.nix b/nix/repo-1_16_0_rc1.nix
new file mode 100644
index 0000000000000000000000000000000000000000..4dce852de07a9ae2116b6ef3a813e44aca8d5d15
--- /dev/null
+++ b/nix/repo-1_16_0_rc1.nix
@@ -0,0 +1,7 @@
+{ fetchFromGitHub }:
+fetchFromGitHub {
+  owner = "fenn-cs";
+  repo = "tahoe-lafs";
+  rev = "f6a96ae3976ee21ad0376f7b6a22fc3d12110dce";
+  sha256 = "sha256:127z83c388mvxkz1qdjqdnlj5xgshyn5w5v40vda6mpyy7k9bpb4";
+}
diff --git a/nix/setup.cfg.patch b/nix/setup.cfg.patch
index c2cdeea1617d10691e9b151d1b3b1308c451952f..3a2762bdb9f3e03979393e1c79f09b3ed4b67970 100644
--- a/nix/setup.cfg.patch
+++ b/nix/setup.cfg.patch
@@ -2,11 +2,11 @@ diff --git a/setup.cfg b/setup.cfg
 index dfc49607..822ea8dd 100644
 --- a/setup.cfg
 +++ b/setup.cfg
-@@ -40,7 +40,7 @@ install_requires =
+@@ -40,5 +40,5 @@ install_requires =
      # incompatible with Tahoe-LAFS'.  So duplicate them here (the ones that
      # have been observed to cause problems).
      Twisted[tls,conch]>=18.4.0
--    tahoe-lafs==1.14.0
+-    tahoe-lafs >=1.14, <1.17, !=1.15.*
 +    tahoe-lafs
      treq
  
diff --git a/nix/tahoe-lafs-1_16.nix b/nix/tahoe-lafs-1_16.nix
new file mode 100644
index 0000000000000000000000000000000000000000..0aed9bd9b1b83c3ff40bf33c5597c10cfd46c28e
--- /dev/null
+++ b/nix/tahoe-lafs-1_16.nix
@@ -0,0 +1,6 @@
+{ callPackage }:
+let
+  repo = callPackage ./repo-1_16_0_rc1.nix { };
+  tahoe-lafs = callPackage "${repo}/nix" { };
+in
+  tahoe-lafs
diff --git a/setup.cfg b/setup.cfg
index ba14ff202611a712c8411bf50b935341c865ac9f..6b99b460b88f7e7f96e14f84f65be7da50a5bee9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -38,7 +38,7 @@ install_requires =
     # incompatible with Tahoe-LAFS'.  So duplicate them here (the ones that
     # have been observed to cause problems).
     Twisted[tls,conch]>=18.4.0
-    tahoe-lafs==1.14.0
+    tahoe-lafs >=1.14, <1.17, !=1.15.*
     treq
     pyutil
 
diff --git a/src/_zkapauthorizer/_storage_client.py b/src/_zkapauthorizer/_storage_client.py
index a9cced29fa16c610492e53c1f9622ed9eadd6610..656679768f898ae67a4a63ea2bac01f88bf9ec80 100644
--- a/src/_zkapauthorizer/_storage_client.py
+++ b/src/_zkapauthorizer/_storage_client.py
@@ -66,7 +66,6 @@ from .storage_common import (
     required_passes,
     allocate_buckets_message,
     add_lease_message,
-    renew_lease_message,
     slot_testv_and_readv_and_writev_message,
     has_writes,
     get_required_new_passes_for_mutable_write,
@@ -403,33 +402,6 @@ class ZKAPAuthorizerStorageClient(object):
         )
         returnValue(result)
 
-    @inline_callbacks
-    @with_rref
-    def renew_lease(
-            self,
-            rref,
-            storage_index,
-            renew_secret,
-    ):
-        share_sizes = (yield rref.callRemote(
-            "share_sizes",
-            storage_index,
-            None,
-        )).values()
-        num_passes = required_passes(self._pass_value, share_sizes)
-
-        result = yield call_with_passes(
-            lambda passes: rref.callRemote(
-                "renew_lease",
-                _encode_passes(passes),
-                storage_index,
-                renew_secret,
-            ),
-            num_passes,
-            partial(self._get_passes, renew_lease_message(storage_index).encode("utf-8")),
-        )
-        returnValue(result)
-
     @with_rref
     def stat_shares(self, rref, storage_indexes):
         return rref.callRemote(
diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py
index ffe74b8e024cd51e81d3d7ef25257e776ac42f15..a7a5616f35ee934868c5a3ae3b33c1953bbbb98a 100644
--- a/src/_zkapauthorizer/_storage_server.py
+++ b/src/_zkapauthorizer/_storage_server.py
@@ -103,7 +103,6 @@ from .storage_common import (
     required_passes,
     allocate_buckets_message,
     add_lease_message,
-    renew_lease_message,
     slot_testv_and_readv_and_writev_message,
     has_writes,
     get_required_new_passes_for_mutable_write,
@@ -302,24 +301,6 @@ class ZKAPAuthorizerStorageServer(Referenceable):
         )
         return self._original.remote_add_lease(storage_index, *a, **kw)
 
-    def remote_renew_lease(self, passes, storage_index, *a, **kw):
-        """
-        Pass-through after a pass check to ensure clients can only extend the
-        duration of share storage if they present valid passes.
-        """
-        valid_passes = _ValidationResult.validate_passes(
-            renew_lease_message(storage_index),
-            passes,
-            self._signing_key,
-        )
-        check_pass_quantity_for_lease(
-            self._pass_value,
-            storage_index,
-            valid_passes,
-            self._original,
-        )
-        return self._original.remote_renew_lease(storage_index, *a, **kw)
-
     def remote_advise_corrupt_share(self, *a, **kw):
         """
         Pass-through without a pass check to let clients inform us of possible
diff --git a/src/_zkapauthorizer/foolscap.py b/src/_zkapauthorizer/foolscap.py
index 29ed94e7374c22b4a7534a9cc843a2db9970be79..b8f12425e72f3c3e80df6350f59f16a6c93bb635 100644
--- a/src/_zkapauthorizer/foolscap.py
+++ b/src/_zkapauthorizer/foolscap.py
@@ -141,7 +141,6 @@ def add_arguments(schema, kwargs):
     return modified_schema
 
 
-
 class RIPrivacyPassAuthorizedStorageServer(RemoteInterface):
     """
     An object which can store and retrieve shares, subject to pass-based
@@ -162,8 +161,6 @@ class RIPrivacyPassAuthorizedStorageServer(RemoteInterface):
 
     add_lease = add_passes(RIStorageServer["add_lease"])
 
-    renew_lease = add_passes(RIStorageServer["renew_lease"])
-
     get_buckets = RIStorageServer["get_buckets"]
 
     def share_sizes(
diff --git a/src/_zkapauthorizer/storage_common.py b/src/_zkapauthorizer/storage_common.py
index 487c164aa7f5cce69a2e9a66d5cbbfaa475ecd4e..829d5a17e3facf46a12fa2685e788d012e086622 100644
--- a/src/_zkapauthorizer/storage_common.py
+++ b/src/_zkapauthorizer/storage_common.py
@@ -70,7 +70,6 @@ def _message_maker(label):
 # construction for different Tahoe-LAFS storage operations.
 allocate_buckets_message = _message_maker(u"allocate_buckets")
 add_lease_message = _message_maker(u"add_lease")
-renew_lease_message = _message_maker(u"renew_lease")
 slot_testv_and_readv_and_writev_message = _message_maker(u"slot_testv_and_readv_and_writev")
 
 # The number of bytes we're willing to store for a lease period for each pass
diff --git a/src/_zkapauthorizer/tests/fixtures.py b/src/_zkapauthorizer/tests/fixtures.py
index 1b226500bc327358f4dfa3ee28b981b209ca9d88..392520c90b82778aeb5879a972c92517dee52ba2 100644
--- a/src/_zkapauthorizer/tests/fixtures.py
+++ b/src/_zkapauthorizer/tests/fixtures.py
@@ -37,6 +37,7 @@ from twisted.python.filepath import (
 from twisted.internet.task import (
     Clock,
 )
+from allmydata import __version__ as allmydata_version
 from allmydata.storage.server import (
     StorageServer,
 )
@@ -51,6 +52,7 @@ from ..controller import (
     PaymentController,
 )
 
+@attr.s
 class AnonymousStorageServer(Fixture):
     """
     Supply an instance of allmydata.storage.server.StorageServer which
@@ -61,12 +63,28 @@ class AnonymousStorageServer(Fixture):
 
     :ivar allmydata.storage.server.StorageServer storage_server: The storage
         server.
+
+    :ivar twisted.internet.task.Clock clock: The ``IReactorTime`` provider to
+        supply to ``StorageServer`` for its time-checking needs.
     """
+    clock = attr.ib()
+
     def _setUp(self):
         self.tempdir = FilePath(self.useFixture(TempDir()).join(b"storage"))
+        if allmydata_version >= "1.16.":
+            # This version of Tahoe adds a new StorageServer argument for
+            # controlling time.
+            timeargs = {"get_current_time": self.clock.seconds}
+        else:
+            # Older versions just use time.time() and there's not much we can
+            # do _here_.  Code somewhere else will have to monkey-patch that
+            # to control things.
+            timeargs = {}
+
         self.storage_server = StorageServer(
             self.tempdir.asBytesMode().path,
             b"x" * 20,
+            **timeargs
         )
 
 
diff --git a/src/_zkapauthorizer/tests/strategies.py b/src/_zkapauthorizer/tests/strategies.py
index 70ec582cb96ff560d5c9cdfa612689d3fd540d5a..d20eb91613d294470a76f8b71933615d7d732162 100644
--- a/src/_zkapauthorizer/tests/strategies.py
+++ b/src/_zkapauthorizer/tests/strategies.py
@@ -812,20 +812,31 @@ def posix_safe_datetimes():
     )
 
 
-def clocks(now=posix_safe_datetimes()):
+def posix_timestamps():
+    """
+    Build floats in a range that can represent time without losing microsecond
+    precision.
+    """
+    return posix_safe_datetimes().map(
+        lambda when: (when - _POSIX_EPOCH).total_seconds(),
+    )
+
+
+def clocks(now=posix_timestamps()):
     """
     Build ``twisted.internet.task.Clock`` instances set to a time built by
     ``now``.
+
+    :param now: A strategy that builds POSIX timestamps (ie, ints or floats in
+        the range of time_t).
     """
     def clock_at_time(when):
         c = Clock()
-        c.advance((when - _POSIX_EPOCH).total_seconds())
+        c.advance(when)
         return c
     return now.map(clock_at_time)
 
 
-
-
 @implementer(IFilesystemNode)
 @attr.s(frozen=True)
 class _LeafNode(object):
diff --git a/src/_zkapauthorizer/tests/test_plugin.py b/src/_zkapauthorizer/tests/test_plugin.py
index 0db1a375d2ffe5c1c7143920909f4a346f6791c5..5de8f4121bcbca70f1c1719080fbfdd70dc90093 100644
--- a/src/_zkapauthorizer/tests/test_plugin.py
+++ b/src/_zkapauthorizer/tests/test_plugin.py
@@ -20,8 +20,8 @@ from __future__ import (
     absolute_import,
 )
 
-from io import (
-    BytesIO,
+from StringIO import (
+    StringIO,
 )
 from os import (
     makedirs,
@@ -397,7 +397,17 @@ class ClientPluginTests(TestCase):
             b"tub.port",
             config_text.encode("utf-8"),
         )
-        config_text = BytesIO()
+        # On Tahoe-LAFS <1.16, the config is written as bytes.
+        # On Tahoe-LAFS >=1.16, the config is written as unicode.
+        #
+        # So we'll use `StringIO.StringIO` (not `io.StringIO`) here - which
+        # will allow either type (it will also implicitly decode bytes to
+        # unicode if we mix them, though I don't think that should happen
+        # here).
+        #
+        # After support for Tahoe <1.16 support is dropped we probably want to
+        # switch to an io.StringIO here.
+        config_text = StringIO()
         node_config.config.write(config_text)
         self.addDetail(u"config", text_content(config_text.getvalue()))
         self.addDetail(u"announcement", text_content(unicode(announcement)))
diff --git a/src/_zkapauthorizer/tests/test_storage_protocol.py b/src/_zkapauthorizer/tests/test_storage_protocol.py
index d79b0fc84599902aa5737aaba45efc9377ba07b6..afe963c24d3f5e932fc1871d5122fe3dbe2eb91c 100644
--- a/src/_zkapauthorizer/tests/test_storage_protocol.py
+++ b/src/_zkapauthorizer/tests/test_storage_protocol.py
@@ -63,6 +63,9 @@ from twisted.python.runtime import (
 from twisted.python.filepath import (
     FilePath,
 )
+from twisted.internet.task import (
+    Clock,
+)
 
 from foolscap.referenceable import (
     LocalReferenceable,
@@ -90,7 +93,7 @@ from .strategies import (
     sharenum_sets,
     sizes,
     slot_test_and_write_vectors_for_shares,
-    clocks,
+    posix_timestamps,
     # Not really a strategy...
     bytes_for_share,
 )
@@ -130,6 +133,7 @@ from ..foolscap import (
     ShareStat,
 )
 
+
 class RequiredPassesTests(TestCase):
     """
     Tests for ``required_passes``.
@@ -192,23 +196,38 @@ class ShareTests(TestCase):
     def setUp(self):
         super(ShareTests, self).setUp()
         self.canary = LocalReferenceable(None)
-        self.anonymous_storage_server = self.useFixture(AnonymousStorageServer()).storage_server
         self.signing_key = random_signing_key()
-
         self.pass_factory = pass_factory(get_passes=privacypass_passes(self.signing_key))
 
+        self.clock = Clock()
+        self.anonymous_storage_server = self.useFixture(
+            AnonymousStorageServer(self.clock),
+        ).storage_server
+
         self.server = ZKAPAuthorizerStorageServer(
             self.anonymous_storage_server,
             self.pass_value,
             self.signing_key,
+            clock=self.clock,
         )
         self.local_remote_server = LocalRemote(self.server)
         self.client = ZKAPAuthorizerStorageClient(
             self.pass_value,
             get_rref=lambda: self.local_remote_server,
             get_passes=self.pass_factory.get,
+            clock=self.clock,
         )
 
+    def setup_example(self):
+        """
+        Initialize any necessary state prior to each Hypothesis iteration of a
+        test method.
+        """
+        # Reset the mutable, shared clock to the epoch to simplify related
+        # code in the tests and ensure consistent starting state for each
+        # iteration.
+        self.clock.advance(-self.clock.seconds())
+
     def test_get_version(self):
         """
         Version information about the storage server can be retrieved using
@@ -522,60 +541,23 @@ class ShareTests(TestCase):
         leases = list(self.anonymous_storage_server.get_leases(storage_index))
         self.assertThat(leases, HasLength(2))
 
-    @given(
-        storage_index=storage_indexes(),
-        renew_secret=lease_renew_secrets(),
-        cancel_secret=lease_cancel_secrets(),
-        sharenums=sharenum_sets(),
-        size=sizes(),
-    )
-    def test_renew_lease(self, storage_index, renew_secret, cancel_secret, sharenums, size):
-        """
-        A lease on an immutable share can be updated to expire at a later time.
-        """
+    def _stat_shares_immutable_test(self, storage_index, sharenum, size, when, leases, write_shares):
         # Hypothesis causes our storage server to be used many times.  Clean
         # up between iterations.
         cleanup_storage_server(self.anonymous_storage_server)
 
-        # Take control of time (in this hacky, fragile way) so we can verify
-        # the expiration time gets bumped by the renewal.
-        now = 1000000000.5
-        self.useFixture(MonkeyPatch("time.time", lambda: now))
+        # Lease cancellation is unimplemented in Tahoe so this doesn't matter.
+        cancel_secret = b""
 
-        # Create a share we can toy with.
-        write_toy_shares(
-            self.anonymous_storage_server,
-            storage_index,
-            renew_secret,
-            cancel_secret,
-            sharenums,
-            size,
-            canary=self.canary,
-        )
-
-        now += 100000
-        self.assertThat(
-            self.client.renew_lease(
-                storage_index,
-                renew_secret,
-            ),
-            succeeded(Always()),
-        )
-
-        [lease] = self.anonymous_storage_server.get_leases(storage_index)
-        self.assertThat(
-            lease.get_expiration_time(),
-            Equals(int(now + self.server.LEASE_PERIOD.total_seconds())),
-        )
+        self.clock.advance(when)
 
-    def _stat_shares_immutable_test(self, storage_index, sharenum, size, clock, leases, write_shares):
-        # Hypothesis causes our storage server to be used many times.  Clean
-        # up between iterations.
-        cleanup_storage_server(self.anonymous_storage_server)
-
-        # anonymous_storage_server uses time.time(), unfortunately.  And
-        # useFixture does not interact very well with Hypothesis.
-        patch = MonkeyPatch("time.time", clock.seconds)
+        # anonymous_storage_server uses time.time() before Tahoe-LAFS 1.16,
+        # unfortunately.  For Tahoe-LAFS 1.16, AnonymousStorageServer will
+        # glue self.clock in for us.  For older versions we still need this
+        # monkey-patching.
+        #
+        # And useFixture does not interact very well with Hypothesis.
+        patch = MonkeyPatch("time.time", self.clock.seconds)
         try:
             patch.setUp()
             # Create a share we can toy with.
@@ -592,7 +574,7 @@ class ShareTests(TestCase):
                 self.anonymous_storage_server.remote_add_lease(
                     storage_index,
                     renew_secret,
-                    b"",
+                    cancel_secret,
                 )
         finally:
             patch.cleanUp()
@@ -600,7 +582,7 @@ class ShareTests(TestCase):
         expected = [{
             sharenum: ShareStat(
                 size=size,
-                lease_expiration=int(clock.seconds() + LEASE_INTERVAL),
+                lease_expiration=int(self.clock.seconds() + LEASE_INTERVAL),
             ),
         }]
         self.assertThat(
@@ -614,10 +596,10 @@ class ShareTests(TestCase):
         cancel_secret=lease_cancel_secrets(),
         sharenum=sharenums(),
         size=sizes(),
-        clock=clocks(),
+        when=posix_timestamps(),
         leases=lists(lease_renew_secrets(), unique=True),
     )
-    def test_stat_shares_immutable(self, storage_index, renew_secret, cancel_secret, sharenum, size, clock, leases):
+    def test_stat_shares_immutable(self, storage_index, renew_secret, cancel_secret, sharenum, size, when, leases):
         """
         Size and lease information about immutable shares can be retrieved from a
         storage server.
@@ -626,7 +608,7 @@ class ShareTests(TestCase):
             storage_index,
             sharenum,
             size,
-            clock,
+            when,
             leases,
             lambda storage_server, storage_index, sharenums, size, canary: write_toy_shares(
                 storage_server,
@@ -643,11 +625,11 @@ class ShareTests(TestCase):
         storage_index=storage_indexes(),
         sharenum=sharenums(),
         size=sizes(),
-        clock=clocks(),
+        when=posix_timestamps(),
         leases=lists(lease_renew_secrets(), unique=True, min_size=1),
         version=share_versions(),
     )
-    def test_stat_shares_immutable_wrong_version(self, storage_index, sharenum, size, clock, leases, version):
+    def test_stat_shares_immutable_wrong_version(self, storage_index, sharenum, size, when, leases, version):
         """
         If a share file with an unexpected version is found, ``stat_shares``
         declines to offer a result (by raising ``ValueError``).
@@ -670,7 +652,7 @@ class ShareTests(TestCase):
             version=version,
             size=size,
             leases=leases,
-            now=clock.seconds(),
+            now=when,
         )
 
         self.assertThat(
@@ -687,12 +669,12 @@ class ShareTests(TestCase):
         storage_index=storage_indexes(),
         sharenum=sharenums(),
         size=sizes(),
-        clock=clocks(),
+        when=posix_timestamps(),
         version=share_versions(),
         # Encode our knowledge of the share header format and size right here...
         position=integers(min_value=0, max_value=11),
     )
-    def test_stat_shares_truncated_file(self, storage_index, sharenum, size, clock, version, position):
+    def test_stat_shares_truncated_file(self, storage_index, sharenum, size, when, version, position):
         """
         If a share file is truncated in the middle of the header,
         ``stat_shares`` declines to offer a result (by raising
@@ -716,7 +698,7 @@ class ShareTests(TestCase):
             # We know leases are at the end, where they'll get chopped off, so
             # we don't bother to write any.
             leases=[],
-            now=clock.seconds(),
+            now=when,
         )
         with sharepath.open("wb") as fobj:
             fobj.truncate(position)
@@ -737,10 +719,10 @@ class ShareTests(TestCase):
         storage_index=storage_indexes(),
         sharenum=sharenums(),
         size=sizes(min_value=2 ** 18, max_value=2 ** 40),
-        clock=clocks(),
+        when=posix_timestamps(),
         leases=lists(lease_renew_secrets(), unique=True, min_size=1),
     )
-    def test_stat_shares_immutable_large(self, storage_index, sharenum, size, clock, leases):
+    def test_stat_shares_immutable_large(self, storage_index, sharenum, size, when, leases):
         """
         Size and lease information about very large immutable shares can be
         retrieved from a storage server.
@@ -763,14 +745,14 @@ class ShareTests(TestCase):
                     version=1,
                     size=size,
                     leases=leases,
-                    now=clock.seconds(),
+                    now=when,
                 )
 
         return self._stat_shares_immutable_test(
             storage_index,
             sharenum,
             size,
-            clock,
+            when,
             leases,
             write_shares,
         )
@@ -784,9 +766,9 @@ class ShareTests(TestCase):
             lease_cancel_secrets(),
         ),
         test_and_write_vectors_for_shares=slot_test_and_write_vectors_for_shares(),
-        clock=clocks(),
+        when=posix_timestamps(),
     )
-    def test_stat_shares_mutable(self, storage_index, secrets, test_and_write_vectors_for_shares, clock):
+    def test_stat_shares_mutable(self, storage_index, secrets, test_and_write_vectors_for_shares, when):
         """
         Size and lease information about mutable shares can be retrieved from a
         storage server.
@@ -795,9 +777,9 @@ class ShareTests(TestCase):
         # up between iterations.
         cleanup_storage_server(self.anonymous_storage_server)
 
-        # anonymous_storage_server uses time.time(), unfortunately.  And
-        # useFixture does not interact very well with Hypothesis.
-        patch = MonkeyPatch("time.time", clock.seconds)
+        self.clock.advance(when)
+
+        patch = MonkeyPatch("time.time", self.clock.seconds)
         try:
             patch.setUp()
             # Create a share we can toy with.
@@ -827,7 +809,7 @@ class ShareTests(TestCase):
                     vectors.write_vector,
                     vectors.new_length,
                 ),
-                lease_expiration=int(clock.seconds() + LEASE_INTERVAL),
+                lease_expiration=int(self.clock.seconds() + LEASE_INTERVAL),
             )
             for (sharenum, vectors)
             in test_and_write_vectors_for_shares.items()
@@ -996,7 +978,7 @@ class ShareTests(TestCase):
         storage_index=storage_indexes(),
         sharenum=sharenums(),
         size=sizes(),
-        clock=clocks(),
+        when=posix_timestamps(),
         write_enabler=write_enabler_secrets(),
         renew_secret=lease_renew_secrets(),
         cancel_secret=lease_cancel_secrets(),
@@ -1005,7 +987,7 @@ class ShareTests(TestCase):
     def test_mutable_rewrite_renews_expired_lease(
             self,
             storage_index,
-            clock,
+            when,
             sharenum,
             size,
             write_enabler,
@@ -1021,9 +1003,7 @@ class ShareTests(TestCase):
         # up between iterations.
         cleanup_storage_server(self.anonymous_storage_server)
 
-        # Make the client and server use our clock.
-        self.server._clock = clock
-        self.client._clock = clock
+        self.clock.advance(when)
 
         secrets = (write_enabler, renew_secret, cancel_secret)
 
@@ -1039,9 +1019,7 @@ class ShareTests(TestCase):
                 r_vector=[],
             )
 
-        # anonymous_storage_server uses time.time() to assign leases,
-        # unfortunately.
-        patch = MonkeyPatch("time.time", clock.seconds)
+        patch = MonkeyPatch("time.time", self.clock.seconds)
         try:
             patch.setUp()
 
@@ -1050,7 +1028,7 @@ class ShareTests(TestCase):
 
             # Advance time by more than a lease period so the lease is no
             # longer valid.
-            clock.advance(self.server.LEASE_PERIOD.total_seconds() + 1)
+            self.clock.advance(self.server.LEASE_PERIOD.total_seconds() + 1)
 
             self.assertThat(write(), is_successful_write())
         finally:
@@ -1066,7 +1044,7 @@ class ShareTests(TestCase):
                         test_and_write_vectors_for_shares[num].write_vector,
                         test_and_write_vectors_for_shares[num].new_length,
                     ),
-                    lease_expiration=int(clock.seconds() + self.server.LEASE_PERIOD.total_seconds()),
+                    lease_expiration=int(self.clock.seconds() + self.server.LEASE_PERIOD.total_seconds()),
                 )
                 for num
                 in test_and_write_vectors_for_shares
diff --git a/src/_zkapauthorizer/tests/test_storage_server.py b/src/_zkapauthorizer/tests/test_storage_server.py
index a3d1451ba38bc28576948f9eda7cd39a99af9f68..1adab62a8b9e6e6605424f2a2ee78dc75f2f87bd 100644
--- a/src/_zkapauthorizer/tests/test_storage_server.py
+++ b/src/_zkapauthorizer/tests/test_storage_server.py
@@ -97,7 +97,6 @@ from ..storage_common import (
     required_passes,
     allocate_buckets_message,
     add_lease_message,
-    renew_lease_message,
     slot_testv_and_readv_and_writev_message,
     get_implied_data_length,
     get_required_new_passes_for_mutable_write,
@@ -204,7 +203,9 @@ class PassValidationTests(TestCase):
         # the same time so we can do lease expiration calculations more
         # easily.
         self.clock.advance(time())
-        self.anonymous_storage_server = self.useFixture(AnonymousStorageServer()).storage_server
+        self.anonymous_storage_server = self.useFixture(
+            AnonymousStorageServer(self.clock),
+        ).storage_server
         self.signing_key = random_signing_key()
         self.storage_server = ZKAPAuthorizerStorageServer(
             self.anonymous_storage_server,
@@ -539,40 +540,6 @@ class PassValidationTests(TestCase):
             add_lease_message,
         )
 
-    @given(
-        storage_index=storage_indexes(),
-        secrets=tuples(
-            lease_renew_secrets(),
-            lease_cancel_secrets(),
-        ),
-        sharenums=sharenum_sets(),
-        allocated_size=sizes(),
-    )
-    def test_renew_lease_fails_without_passes(self, storage_index, secrets, sharenums, allocated_size):
-        """
-        If ``remote_renew_lease`` is invoked without supplying enough passes to
-        cover the storage for all shares on the given storage index, the
-        operation fails with ``MorePassesRequired``.
-        """
-        renew_secret, cancel_secret = secrets
-        def renew_lease(storage_server, passes):
-            return storage_server.doRemoteCall(
-                "renew_lease", (
-                    passes,
-                    storage_index,
-                    renew_secret,
-                ),
-                {},
-            )
-        return self._test_lease_operation_fails_without_passes(
-            storage_index,
-            secrets,
-            sharenums,
-            allocated_size,
-            renew_lease,
-            renew_lease_message,
-        )
-
     @given(
         slot=storage_indexes(),
         secrets=tuples(
diff --git a/zkapauthorizer.nix b/zkapauthorizer.nix
index 89639e0d41ec84db5811503dd150f9c33250d0a3..484c364166b2179a50e47e97acc468600949755e 100644
--- a/zkapauthorizer.nix
+++ b/zkapauthorizer.nix
@@ -34,15 +34,17 @@ buildPythonPackage rec {
   ];
 
   propagatedBuildInputs = [
-    attrs
-    zope_interface
     aniso8601
-    # Inherit eliot from tahoe-lafs
-    # eliot
-    twisted
     tahoe-lafs
     challenge-bypass-ristretto
-    treq
+
+    # Inherit some things from tahoe-lafs to avoid conflicting versions
+    #
+    # attrs
+    # zope_interface
+    # twisted
+    # eliot
+    # treq
   ];
 
   checkInputs = [