diff --git a/src/_zkapauthorizer/_plugin.py b/src/_zkapauthorizer/_plugin.py
index 1f96295374e30064d0c51e9ade02bfab3cc135df..95a45a4388485c136e00087d29db949046e84271 100644
--- a/src/_zkapauthorizer/_plugin.py
+++ b/src/_zkapauthorizer/_plugin.py
@@ -140,8 +140,7 @@ class ZKAPAuthorizer(object):
             registry=registry,
         )
         storage_server = ZKAPAuthorizerStorageServer(
-            # unwrap the Foolscap layer, we'll do it ourselves.
-            anonymous_storage_server._server,
+            anonymous_storage_server,
             pass_value=pass_value,
             signing_key=signing_key,
             spender=spender,
diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py
index 8ff606a549a15f07828a8af4d70c2142b864826e..0a4b76db61fcc0d89a66ff52a09faab8a7d978cc 100644
--- a/src/_zkapauthorizer/_storage_server.py
+++ b/src/_zkapauthorizer/_storage_server.py
@@ -232,6 +232,10 @@ class ZKAPAuthorizerStorageServer(Referenceable):
         notification when a bucket writer is closed.  It removes the
         disconnection-based cleanup callback for the given bucket.
         """
+        # This implementation was originally copied from
+        # allmydata.storage.server.FoolscapStorageServer.  Since we don't use
+        # Tahoe's Foolscap storage server layer we need to do this bucket
+        # writer bookkeeping ourselves.
         if bw in self._bucket_writer_disconnect_markers:
             canary, disconnect_marker = self._bucket_writer_disconnect_markers.pop(bw)
             canary.dontNotifyOnDisconnect(disconnect_marker)
diff --git a/src/_zkapauthorizer/model.py b/src/_zkapauthorizer/model.py
index fb67ec74de980344e3d0a45f7c3db52b06b8d637..726be23690610c5681067e6f857f0c2a345bf30b 100644
--- a/src/_zkapauthorizer/model.py
+++ b/src/_zkapauthorizer/model.py
@@ -96,10 +96,9 @@ def open_and_initialize(path, connect=None):
     except OSError as e:
         raise StoreOpenError(e)
 
-    dbfile = path.asBytesMode().path
     try:
         conn = connect(
-            dbfile,
+            path.path,
             isolation_level="IMMEDIATE",
         )
     except OperationalError as e:
diff --git a/src/_zkapauthorizer/spending.py b/src/_zkapauthorizer/spending.py
index e3af5af91919bd9c075343b6f418a67bbb6970c5..f718ac0056d609af45a9f0c5488ca6abb93e3571 100644
--- a/src/_zkapauthorizer/spending.py
+++ b/src/_zkapauthorizer/spending.py
@@ -16,6 +16,8 @@
 A module for logic controlling the manner in which ZKAPs are spent.
 """
 
+from __future__ import annotations
+
 from typing import Callable, List, Tuple
 
 import attr
@@ -126,7 +128,7 @@ class PassGroup(object):
     def unblinded_tokens(self) -> List[UnblindedToken]:
         return list(unblinded_token for (unblinded_token, pass_) in self._tokens)
 
-    def split(self, select_indices: List[int]) -> ("PassGroup", "PassGroup"):
+    def split(self, select_indices: List[int]) -> (PassGroup, PassGroup):
         selected = []
         unselected = []
         for idx, t in enumerate(self._tokens):
@@ -139,7 +141,7 @@ class PassGroup(object):
             attr.evolve(self, tokens=unselected),
         )
 
-    def expand(self, by_amount: int) -> "PassGroup":
+    def expand(self, by_amount: int) -> PassGroup:
         return attr.evolve(
             self,
             tokens=self._tokens + self._factory.get(self._message, by_amount)._tokens,
diff --git a/src/_zkapauthorizer/tests/fixtures.py b/src/_zkapauthorizer/tests/fixtures.py
index a01dc6ff430eef143a73c0b0242767514b136dbb..8803180f62410c0f62e7032563ef6af7ae142a3c 100644
--- a/src/_zkapauthorizer/tests/fixtures.py
+++ b/src/_zkapauthorizer/tests/fixtures.py
@@ -36,7 +36,7 @@ class AnonymousStorageServer(Fixture):
 
     :ivar tempdir: The path to the server's storage on the filesystem.
 
-    :ivar backend: The protocol-agnostic storage server backend.
+    :ivar storage_server: The protocol-agnostic storage server backend.
 
     :ivar clock: The ``IReactorTime`` provider to supply to ``StorageServer``
         for its time-checking needs.
@@ -45,11 +45,11 @@ class AnonymousStorageServer(Fixture):
     clock: Clock = attr.ib()
 
     tempdir: FilePath = attr.ib(default=None)
-    backend: StorageServer = attr.ib(default=None)
+    storage_server: StorageServer = attr.ib(default=None)
 
     def _setUp(self):
         self.tempdir = FilePath(self.useFixture(TempDir()).join(u"storage"))
-        self.backend = StorageServer(
+        self.storage_server = StorageServer(
             self.tempdir.path,
             b"x" * 20,
             clock=self.clock,
diff --git a/src/_zkapauthorizer/tests/foolscap.py b/src/_zkapauthorizer/tests/foolscap.py
index 9512f47c234d0c7ade266b2a80fb6056b59c9524..b10b00ed48a1ccdc75d3c6037ebeaf0dd8fc66c1 100644
--- a/src/_zkapauthorizer/tests/foolscap.py
+++ b/src/_zkapauthorizer/tests/foolscap.py
@@ -17,7 +17,6 @@ Testing helpers related to Foolscap.
 """
 
 import attr
-from allmydata.interfaces import RIStorageServer
 from foolscap.api import Any, Copyable, Referenceable, RemoteInterface
 from foolscap.copyable import CopyableSlicer, ICopyable
 from twisted.internet.defer import fail, succeed
@@ -33,19 +32,13 @@ class RIEcho(RemoteInterface):
         return Any()
 
 
-class StubStorageBackend(object):
+class StubStorageServer(object):
     def register_bucket_writer_close_handler(self, handler):
         pass
 
 
-@implementer(RIStorageServer)
-@attr.s
-class StubFoolscapStorageServer(object):
-    _server = attr.ib(default=attr.Factory(StubStorageBackend))
-
-
 def get_anonymous_storage_server():
-    return StubFoolscapStorageServer()
+    return StubStorageServer()
 
 
 class BrokenCopyable(Copyable):
diff --git a/src/_zkapauthorizer/tests/storage_common.py b/src/_zkapauthorizer/tests/storage_common.py
index 6538b3bc4afee1cab06b5f9b57c601eb79dbefd8..39d85d25c6132ab0b8a14cddc267787b1e160619 100644
--- a/src/_zkapauthorizer/tests/storage_common.py
+++ b/src/_zkapauthorizer/tests/storage_common.py
@@ -36,13 +36,17 @@ from .strategies import bytes_for_share  # Not really a strategy...
 LEASE_INTERVAL = 60 * 60 * 24 * 31
 
 
-def cleanup_storage_server(storage_server):
+def reset_storage_server(storage_server):
     """
-    Delete all of the shares held by the given storage server.
+    Restore a storage server to a default state.  This includes
+    deleting all of the shares it holds.
 
     :param allmydata.storage.server.StorageServer storage_server: The storage
         server with some on-disk shares to delete.
     """
+    # A storage server is read-write by default.
+    storage_server.readonly_storage = False
+
     starts = [
         FilePath(storage_server.sharedir),
         FilePath(storage_server.corruption_advisory_dir),
diff --git a/src/_zkapauthorizer/tests/test_storage_protocol.py b/src/_zkapauthorizer/tests/test_storage_protocol.py
index 2ee75aaae77a34dadf1c239c2397ceddcd852fc7..10e30c0fa51da66f27f975a44bc16dd6689cd65f 100644
--- a/src/_zkapauthorizer/tests/test_storage_protocol.py
+++ b/src/_zkapauthorizer/tests/test_storage_protocol.py
@@ -61,10 +61,10 @@ from .foolscap import LocalRemote
 from .matchers import matches_spent_passes, matches_version_dictionary
 from .storage_common import (
     LEASE_INTERVAL,
-    cleanup_storage_server,
     get_passes,
     pass_factory,
     privacypass_passes,
+    reset_storage_server,
     whitebox_write_sparse_share,
     write_toy_shares,
 )
@@ -154,13 +154,13 @@ class ShareTests(TestCase):
         )
 
         self.clock = Clock()
-        self.storage = self.useFixture(
+        self.anonymous_storage_server = self.useFixture(
             AnonymousStorageServer(self.clock),
-        )
+        ).storage_server
 
         self.spending_recorder, spender = RecordingSpender.make()
         self.server = ZKAPAuthorizerStorageServer(
-            self.storage.backend,
+            self.anonymous_storage_server,
             self.pass_value,
             self.signing_key,
             spender,
@@ -191,7 +191,7 @@ class ShareTests(TestCase):
         self.spending_recorder.reset()
 
         # And clean out any shares that might confuse things.
-        cleanup_storage_server(self.storage.backend)
+        reset_storage_server(self.anonymous_storage_server)
 
     def test_get_version(self):
         """
@@ -410,7 +410,7 @@ class ShareTests(TestCase):
         # Create some shares to alter the behavior of the next
         # allocate_buckets.
         write_toy_shares(
-            self.storage.backend,
+            self.anonymous_storage_server,
             storage_index,
             renew_secret,
             cancel_secret,
@@ -479,7 +479,7 @@ class ShareTests(TestCase):
         )
 
         self.assertThat(
-            dict(get_lease_grant_times(self.storage.backend, storage_index)),
+            dict(get_lease_grant_times(self.anonymous_storage_server, storage_index)),
             Equals(expected_leases),
         )
 
@@ -503,7 +503,7 @@ class ShareTests(TestCase):
 
         # Create a share we can toy with.
         write_toy_shares(
-            self.storage.backend,
+            self.anonymous_storage_server,
             storage_index,
             add_lease_secret,
             cancel_secret,
@@ -526,7 +526,7 @@ class ShareTests(TestCase):
             matches_spent_passes(self.public_key_hash, self.pass_factory.spent),
         )
 
-        leases = list(self.storage.backend.get_leases(storage_index))
+        leases = list(self.anonymous_storage_server.get_leases(storage_index))
         self.assertThat(leases, HasLength(2))
 
     def _stat_shares_immutable_test(
@@ -539,7 +539,7 @@ class ShareTests(TestCase):
 
         # Create a share we can toy with.
         write_shares(
-            self.storage,
+            self.anonymous_storage_server,
             storage_index,
             {sharenum},
             size,
@@ -548,7 +548,7 @@ class ShareTests(TestCase):
         # Perhaps put some more leases on it.  Leases might impact our
         # ability to determine share data size.
         for renew_secret in leases:
-            self.storage.backend.add_lease(
+            self.anonymous_storage_server.add_lease(
                 storage_index,
                 renew_secret,
                 cancel_secret,
@@ -589,8 +589,8 @@ class ShareTests(TestCase):
             size,
             when,
             leases,
-            lambda storage, storage_index, sharenums, size, canary: write_toy_shares(
-                storage.backend,
+            lambda storage_server, storage_index, sharenums, size, canary: write_toy_shares(
+                storage_server,
                 storage_index,
                 renew_secret,
                 cancel_secret,
@@ -616,7 +616,7 @@ class ShareTests(TestCase):
         """
         assume(version not in (1, 2))
 
-        sharedir = FilePath(self.storage.backend.sharedir).preauthChild(
+        sharedir = FilePath(self.anonymous_storage_server.sharedir).preauthChild(
             # storage_index_to_dir likes to return multiple segments
             # joined by pathsep
             storage_index_to_dir(storage_index),
@@ -658,7 +658,7 @@ class ShareTests(TestCase):
         ``stat_shares`` declines to offer a result (by raising
         ``ValueError``).
         """
-        sharedir = FilePath(self.storage.backend.sharedir).preauthChild(
+        sharedir = FilePath(self.anonymous_storage_server.sharedir).preauthChild(
             # storage_index_to_dir likes to return multiple segments
             # joined by pathsep
             storage_index_to_dir(storage_index),
@@ -710,8 +710,8 @@ class ShareTests(TestCase):
         write real multi-gigabyte files to exercise the behavior.
         """
 
-        def write_shares(storage, storage_index, sharenums, size, canary):
-            sharedir = FilePath(storage.backend.sharedir).preauthChild(
+        def write_shares(storage_server, storage_index, sharenums, size, canary):
+            sharedir = FilePath(storage_server.sharedir).preauthChild(
                 # storage_index_to_dir likes to return multiple segments
                 # joined by pathsep
                 storage_index_to_dir(storage_index),
@@ -816,7 +816,7 @@ class ShareTests(TestCase):
         """
         # Create a share we can toy with.
         write_toy_shares(
-            self.storage.backend,
+            self.anonymous_storage_server,
             storage_index,
             renew_secret,
             cancel_secret,
@@ -834,7 +834,7 @@ class ShareTests(TestCase):
             succeeded(Always()),
         )
         self.assertThat(
-            FilePath(self.storage.backend.corruption_advisory_dir).children(),
+            FilePath(self.anonymous_storage_server.corruption_advisory_dir).children(),
             HasLength(1),
         )
 
@@ -924,7 +924,7 @@ class ShareTests(TestCase):
         self.assertThat(
             dict(
                 get_lease_grant_times(
-                    self.storage.backend,
+                    self.anonymous_storage_server,
                     storage_index,
                 )
             ),
@@ -952,7 +952,9 @@ class ShareTests(TestCase):
         def leases():
             return list(
                 lease.to_mutable_data()
-                for lease in self.storage.backend.get_slot_leases(storage_index)
+                for lease in self.anonymous_storage_server.get_slot_leases(
+                    storage_index
+                )
             )
 
         def write():
diff --git a/src/_zkapauthorizer/tests/test_storage_server.py b/src/_zkapauthorizer/tests/test_storage_server.py
index defab2b6842a34ffc513cc9a444a61a6ea0dd890..a0237bb7b82cf5c6069d7ae6f243bb37479f22d1 100644
--- a/src/_zkapauthorizer/tests/test_storage_server.py
+++ b/src/_zkapauthorizer/tests/test_storage_server.py
@@ -45,7 +45,7 @@ from ..storage_common import (
 from .common import skipIf
 from .fixtures import AnonymousStorageServer
 from .matchers import matches_spent_passes, raises
-from .storage_common import cleanup_storage_server, get_passes, write_toy_shares
+from .storage_common import get_passes, reset_storage_server, write_toy_shares
 from .strategies import (
     lease_cancel_secrets,
     lease_renew_secrets,
@@ -194,15 +194,15 @@ class PassValidationTests(TestCase):
         # the same time so we can do lease expiration calculations more
         # easily.
         self.clock.advance(time())
-        self.storage = self.useFixture(
+        self.anonymous_storage_server = self.useFixture(
             AnonymousStorageServer(self.clock),
-        )
+        ).storage_server
         self.signing_key = random_signing_key()
         self.public_key_hash = PublicKey.from_signing_key(
             self.signing_key
         ).encode_base64()
         self.storage_server = ZKAPAuthorizerStorageServer(
-            self.storage.backend,
+            self.anonymous_storage_server,
             self.pass_value,
             self.signing_key,
             spender,
@@ -222,10 +222,7 @@ class PassValidationTests(TestCase):
         # Hypothesis and testtools fixtures don't play nicely together in a
         # way that allows us to just move everything from `setUp` into this
         # method.
-        cleanup_storage_server(self.storage.backend)
-        # One of the tests makes the server read-only partway through.  Make
-        # sure that doesn't leak into other examples.
-        self.storage.backend.readonly_storage = False
+        reset_storage_server(self.anonymous_storage_server)
 
         self.spending_recorder.reset()
 
@@ -532,7 +529,7 @@ class PassValidationTests(TestCase):
         )
         # Create some shares at a slot which will require lease renewal.
         write_toy_shares(
-            self.storage.backend,
+            self.anonymous_storage_server,
             storage_index,
             renew_secret,
             cancel_secret,
@@ -805,7 +802,7 @@ class PassValidationTests(TestCase):
         # the subsequent `allocate_buckets` operation - but of which the
         # client is unaware.
         write_toy_shares(
-            self.storage.backend,
+            self.anonymous_storage_server,
             storage_index,
             renew_secret,
             cancel_secret,
@@ -875,7 +872,7 @@ class PassValidationTests(TestCase):
     ):
         # Create some shares at a slot which will require lease renewal.
         write_toy_shares(
-            self.storage.backend,
+            self.anonymous_storage_server,
             storage_index,
             renew_secret,
             cancel_secret,
@@ -938,7 +935,7 @@ class PassValidationTests(TestCase):
 
         # Put some shares up there to target with the add_lease operation.
         write_toy_shares(
-            self.storage.backend,
+            self.anonymous_storage_server,
             storage_index,
             renew_secret,
             cancel_secret,
@@ -957,7 +954,7 @@ class PassValidationTests(TestCase):
 
         # Turn off space-allocating operations entirely.  Since there will be
         # no space for a new lease, the operation will fail.
-        self.storage.backend.readonly_storage = True
+        self.anonymous_storage_server.readonly_storage = True
 
         try:
             self.storage_server.doRemoteCall(