diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt
index aa7f7e50f2..af2acc1aac 100644
--- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt
+++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt
@@ -7,7 +7,6 @@ import javafx.collections.FXCollections
 import javafx.collections.ObservableList
 import net.corda.client.jfx.utils.*
 import net.corda.core.identity.AnonymousParty
-import net.corda.core.internal.buildNamed
 import net.corda.core.node.NodeInfo
 import net.corda.core.node.services.NetworkMapCache.MapChange
 import java.security.PublicKey
@@ -32,7 +31,7 @@ class NetworkIdentityModel {
     private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable)
 
     private val identityCache = Caffeine.newBuilder()
-            .buildNamed<PublicKey, ObservableValue<NodeInfo?>>("NetworkIdentityModel_identity", CacheLoader { publicKey: PublicKey ->
+            .build<PublicKey, ObservableValue<NodeInfo?>>(CacheLoader { publicKey: PublicKey ->
                 publicKey.let { rpcProxy.map { it?.cordaRPCOps?.nodeInfoFromParty(AnonymousParty(publicKey)) } }
             })
     val notaries = ChosenList(rpcProxy.map { FXCollections.observableList(it?.cordaRPCOps?.notaryIdentities() ?: emptyList()) }, "notaries")
diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ClientCacheFactory.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ClientCacheFactory.kt
new file mode 100644
index 0000000000..bad74ecd2b
--- /dev/null
+++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ClientCacheFactory.kt
@@ -0,0 +1,19 @@
+package net.corda.client.rpc.internal
+
+import com.github.benmanes.caffeine.cache.Cache
+import com.github.benmanes.caffeine.cache.CacheLoader
+import com.github.benmanes.caffeine.cache.Caffeine
+import com.github.benmanes.caffeine.cache.LoadingCache
+import net.corda.core.internal.NamedCacheFactory
+
+class ClientCacheFactory : NamedCacheFactory {
+    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
+        checkCacheName(name)
+        return caffeine.build<K, V>()
+    }
+
+    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
+        checkCacheName(name)
+        return caffeine.build<K, V>(loader)
+    }
+}
\ No newline at end of file
diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt
index be74d7b316..6ceff2b9d0 100644
--- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt
+++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt
@@ -83,7 +83,8 @@ class RPCClientProxyHandler(
         private val sessionId: Trace.SessionId,
         private val externalTrace: Trace?,
         private val impersonatedActor: Actor?,
-        private val targetLegalIdentity: CordaX500Name?
+        private val targetLegalIdentity: CordaX500Name?,
+        private val cacheFactory: NamedCacheFactory = ClientCacheFactory()
 ) : InvocationHandler {
 
     private enum class State {
@@ -169,8 +170,7 @@ class RPCClientProxyHandler(
             }
             observablesToReap.locked { observables.add(observableId) }
         }
-        return Caffeine.newBuilder().
-                weakValues().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()).buildNamed("RpcClientProxyHandler_rpcObservable")
+        return cacheFactory.buildNamed(Caffeine.newBuilder().weakValues().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()), "RpcClientProxyHandler_rpcObservable")
     }
 
     private var sessionFactory: ClientSessionFactory? = null
@@ -179,7 +179,7 @@ class RPCClientProxyHandler(
     private var rpcProducer: ClientProducer? = null
     private var rpcConsumer: ClientConsumer? = null
 
-    private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry)
+    private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry, cacheFactory = cacheFactory)
     private val deduplicationSequenceNumber = AtomicLong(0)
 
     private val sendingEnabled = AtomicBoolean(true)
diff --git a/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt b/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt
index 2a96de4835..632b0c3060 100644
--- a/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt
+++ b/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt
@@ -6,30 +6,21 @@ import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
 
 /**
- * Restrict the allowed characters of a cache name - this ensures that each cache has a name, and that
- * the name can be used to create a file name or a metric name.
+ * Allow extra functionality to be injected to our caches.
  */
-internal fun checkCacheName(name: String) {
-    require(!name.isBlank())
-    require(allowedChars.matches(name))
+interface NamedCacheFactory {
+    /**
+     * Restrict the allowed characters of a cache name - this ensures that each cache has a name, and that
+     * the name can be used to create a file name or a metric name.
+     */
+    fun checkCacheName(name: String) {
+        require(!name.isBlank())
+        require(allowedChars.matches(name))
+    }
+
+    fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V>
+
+    fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V>
 }
 
 private val allowedChars = Regex("^[0-9A-Za-z_.]*\$")
-
-/* buildNamed is the central helper method to build caffeine caches in Corda.
- * This allows to easily add tweaks to all caches built in Corda, and also forces
- * cache users to give their cache a (meaningful) name that can be used e.g. for
- * capturing cache traces etc.
- *
- * Currently it is not used in this version of CORDA, but there are plans to do so.
- */
-
-fun <K, V> Caffeine<in K, in V>.buildNamed(name: String): Cache<K, V> {
-    checkCacheName(name)
-    return this.build<K, V>()
-}
-
-fun <K, V> Caffeine<in K, in V>.buildNamed(name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
-    checkCacheName(name)
-    return this.build<K, V>(loader)
-}
diff --git a/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt b/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt
index 3358696bce..4d9f9297ab 100644
--- a/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt
+++ b/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt
@@ -1,9 +1,21 @@
 package net.corda.core.internal
 
+import com.github.benmanes.caffeine.cache.Cache
+import com.github.benmanes.caffeine.cache.CacheLoader
+import com.github.benmanes.caffeine.cache.Caffeine
+import com.github.benmanes.caffeine.cache.LoadingCache
 import org.junit.Test
 import kotlin.test.assertEquals
 
-class NamedCacheTest {
+class NamedCacheTest : NamedCacheFactory {
+    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
+        throw IllegalStateException("Should not be called")
+    }
+
+    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
+        throw IllegalStateException("Should not be called")
+    }
+
     fun checkNameHelper(name: String, throws: Boolean) {
         var exceptionThrown = false
         try {
diff --git a/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt b/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt
index 43238f2d9e..d40a2949bc 100644
--- a/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt
+++ b/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt
@@ -123,7 +123,8 @@ class FlowWorkerServiceHub(override val configuration: NodeConfiguration, overri
             configuration.database,
             identityService::wellKnownPartyFromX500Name,
             identityService::wellKnownPartyFromAnonymous,
-            schemaService
+            schemaService,
+            cacheFactory
     )
 
     init {
@@ -142,7 +143,7 @@ class FlowWorkerServiceHub(override val configuration: NodeConfiguration, overri
     private val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, validatedTransactions)
     @Suppress("LeakingThis")
     override val vaultService = NodeVaultService(clock, keyManagementService, servicesForResolution, database, schemaService, cacheFactory).tokenize()
-    override val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database)
+    override val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database, cacheFactory)
     val flowLogicRefFactory = FlowLogicRefFactoryImpl(cordappLoader.appClassLoader)
     override val monitoringService = MonitoringService(metricRegistry).tokenize()
 
@@ -163,7 +164,7 @@ class FlowWorkerServiceHub(override val configuration: NodeConfiguration, overri
     private val transactionVerifierWorkerCount = 4
     @Suppress("LeakingThis")
     override val transactionVerifierService = InMemoryTransactionVerifierService(transactionVerifierWorkerCount).tokenize()
-    override val contractUpgradeService = ContractUpgradeServiceImpl().tokenize()
+    override val contractUpgradeService = ContractUpgradeServiceImpl(cacheFactory).tokenize()
     override val auditService = DummyAuditService().tokenize()
 
     @Suppress("LeakingThis")
diff --git a/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftUniquenessProvider.kt b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftUniquenessProvider.kt
index c7670d0c18..8146178559 100644
--- a/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftUniquenessProvider.kt
+++ b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftUniquenessProvider.kt
@@ -18,6 +18,7 @@ import net.corda.core.contracts.TimeWindow
 import net.corda.core.crypto.SecureHash
 import net.corda.core.flows.NotarisationRequestSignature
 import net.corda.core.identity.Party
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.notary.NotaryInternalException
 import net.corda.core.internal.notary.UniquenessProvider
 import net.corda.core.schemas.PersistentStateRef
@@ -27,7 +28,6 @@ import net.corda.core.utilities.contextLogger
 import net.corda.core.utilities.debug
 import net.corda.node.services.config.RaftConfig
 import net.corda.node.utilities.AppendOnlyPersistentMap
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.config.MutualSslConfiguration
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
diff --git a/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftTransactionCommitLogTests.kt b/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftTransactionCommitLogTests.kt
index cfd7df9cdc..eb3b614474 100644
--- a/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftTransactionCommitLogTests.kt
+++ b/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftTransactionCommitLogTests.kt
@@ -15,15 +15,15 @@ import net.corda.core.internal.concurrent.asCordaFuture
 import net.corda.core.internal.concurrent.transpose
 import net.corda.core.utilities.NetworkHostAndPort
 import net.corda.core.utilities.getOrThrow
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.schema.NodeSchemaService
-import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.core.ALICE_NAME
 import net.corda.testing.core.SerializationEnvironmentRule
 import net.corda.testing.driver.PortAllocation
 import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.internal.makeInternalTestDataSourceProperties
 import org.hamcrest.Matchers.instanceOf
 import org.junit.After
diff --git a/experimental/rpc-worker/src/integration-test/kotlin/net/corda/rpcWorker/RpcFlowWorkerDriver.kt b/experimental/rpc-worker/src/integration-test/kotlin/net/corda/rpcWorker/RpcFlowWorkerDriver.kt
index 5d07d4e73c..be3ea0938d 100644
--- a/experimental/rpc-worker/src/integration-test/kotlin/net/corda/rpcWorker/RpcFlowWorkerDriver.kt
+++ b/experimental/rpc-worker/src/integration-test/kotlin/net/corda/rpcWorker/RpcFlowWorkerDriver.kt
@@ -32,6 +32,8 @@ import net.corda.node.services.config.*
 import net.corda.node.services.messaging.ArtemisMessagingServer
 import net.corda.node.services.network.NodeInfoWatcher
 import net.corda.node.services.rpc.ArtemisRpcBroker
+import net.corda.node.utilities.EnterpriseNamedCacheFactory
+import net.corda.node.utilities.profiling.getTracingConfig
 import net.corda.nodeapi.internal.NodeInfoAndSigned
 import net.corda.nodeapi.internal.config.User
 import net.corda.nodeapi.internal.config.toConfig
@@ -221,7 +223,7 @@ data class RpcFlowWorkerDriverDSL(private val driverDSL: DriverDSLImpl) : Intern
 
     private fun createRpcWorkerBroker(config: NodeConfiguration): ArtemisBroker {
         val rpcOptions = config.rpcOptions
-        val securityManager = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(config.rpcUsers))
+        val securityManager = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(config.rpcUsers), EnterpriseNamedCacheFactory(config.enterpriseConfiguration.getTracingConfig()))
         val broker = if (rpcOptions.useSsl) {
             ArtemisRpcBroker.withSsl(config.p2pSslOptions, rpcOptions.address, rpcOptions.adminAddress, rpcOptions.sslConfig!!, securityManager,
                     Node.MAX_RPC_MESSAGE_SIZE, false, config.baseDirectory / "artemis", false)
diff --git a/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorker.kt b/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorker.kt
index 503b3e97f6..0ddf23fb71 100644
--- a/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorker.kt
+++ b/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorker.kt
@@ -15,6 +15,8 @@ import net.corda.node.services.messaging.InternalRPCMessagingClient
 import net.corda.node.services.messaging.RPCOpsRouting
 import net.corda.node.services.messaging.RPCServerConfiguration
 import net.corda.node.services.rpc.ArtemisRpcBroker
+import net.corda.node.utilities.EnterpriseNamedCacheFactory
+import net.corda.node.utilities.profiling.getTracingConfig
 import net.corda.nodeapi.internal.config.User
 import net.corda.nodeapi.internal.crypto.X509Utilities
 import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl
@@ -100,7 +102,7 @@ class Main : Runnable {
 
     private fun createRpcWorkerBroker(config: NodeConfiguration, maxMessageSize: Int): ArtemisBroker {
         val rpcOptions = config.rpcOptions
-        val securityManager = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(config.rpcUsers))
+        val securityManager = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(config.rpcUsers), EnterpriseNamedCacheFactory(config.enterpriseConfiguration.getTracingConfig()))
         val broker = if (rpcOptions.useSsl) {
             ArtemisRpcBroker.withSsl(config.p2pSslOptions, rpcOptions.address, rpcOptions.adminAddress, rpcOptions.sslConfig!!, securityManager, maxMessageSize, false, config.baseDirectory / "artemis", false)
         } else {
@@ -127,7 +129,7 @@ class RpcWorker(private val serverControl: ActiveMQServerControl, private val rp
         val rpcServerConfiguration = RPCServerConfiguration.DEFAULT.copy(
                 rpcThreadPoolSize = rpcWorkerConfig.enterpriseConfiguration.tuning.rpcThreadPoolSize
         )
-        val securityManager = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(rpcWorkerConfig.rpcUsers))
+        val securityManager = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(rpcWorkerConfig.rpcUsers), rpcWorkerServiceHubs[0].cacheFactory)
         val nodeName =
                 if(rpcWorkerServiceHubs.size == 1) {
                     rpcWorkerServiceHubs.single().configuration.myLegalName
@@ -140,7 +142,7 @@ class RpcWorker(private val serverControl: ActiveMQServerControl, private val rp
 
         val rpcOpsMap = rpcWorkerServiceHubs.map { Pair(it.myInfo.legalIdentities.single().name, it.rpcOps) }.toMap()
 
-        internalRpcMessagingClient.init(RPCOpsRouting(rpcOpsMap), securityManager)
+        internalRpcMessagingClient.init(RPCOpsRouting(rpcOpsMap), securityManager, rpcWorkerServiceHubs[0].cacheFactory)
         internalRpcMessagingClient.start(serverControl)
 
         runOnStop += { internalRpcMessagingClient.stop() }
diff --git a/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorkerServiceHub.kt b/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorkerServiceHub.kt
index f72fdc896d..0c1a5dbe19 100644
--- a/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorkerServiceHub.kt
+++ b/experimental/rpc-worker/src/main/kotlin/net/corda/rpcWorker/RpcWorkerServiceHub.kt
@@ -14,7 +14,9 @@ import net.corda.core.node.services.ContractUpgradeService
 import net.corda.core.node.services.TransactionVerifierService
 import net.corda.core.serialization.SerializeAsToken
 import net.corda.core.serialization.SingletonSerializeAsToken
-import net.corda.core.serialization.internal.*
+import net.corda.core.serialization.internal.SerializationEnvironment
+import net.corda.core.serialization.internal.effectiveSerializationEnv
+import net.corda.core.serialization.internal.nodeSerializationEnv
 import net.corda.core.utilities.contextLogger
 import net.corda.node.CordaClock
 import net.corda.node.SimpleClock
@@ -81,7 +83,8 @@ class RpcWorkerServiceHub(override val configuration: NodeConfiguration, overrid
             configuration.database,
             identityService::wellKnownPartyFromX500Name,
             identityService::wellKnownPartyFromAnonymous,
-            schemaService
+            schemaService,
+            cacheFactory
     )
 
     init {
@@ -102,7 +105,7 @@ class RpcWorkerServiceHub(override val configuration: NodeConfiguration, overrid
     private val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, validatedTransactions)
     @Suppress("LeakingThis")
     override val vaultService = NodeVaultService(clock, keyManagementService, servicesForResolution, database, schemaService, cacheFactory)
-    override val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database)
+    override val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database, cacheFactory)
     override val monitoringService = MonitoringService(metricRegistry)
     override val networkMapUpdater = NetworkMapUpdater(
             networkMapCache,
diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt
index 71d99e0fec..8b913c6ea2 100644
--- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt
+++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt
@@ -2,7 +2,7 @@ package net.corda.nodeapi.internal
 
 import com.github.benmanes.caffeine.cache.CacheLoader
 import com.github.benmanes.caffeine.cache.Caffeine
-import net.corda.core.internal.buildNamed
+import net.corda.core.internal.NamedCacheFactory
 import java.time.Duration
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.atomic.AtomicLong
@@ -10,11 +10,10 @@ import java.util.concurrent.atomic.AtomicLong
 /**
  * A class allowing the deduplication of a strictly incrementing sequence number.
  */
-class DeduplicationChecker(cacheExpiry: Duration, name: String = "DeduplicationChecker") {
+class DeduplicationChecker(cacheExpiry: Duration, name: String = "DeduplicationChecker", cacheFactory: NamedCacheFactory) {
     // dedupe identity -> watermark cache
-    private val watermarkCache = Caffeine.newBuilder()
-            .expireAfterAccess(cacheExpiry.toNanos(), TimeUnit.NANOSECONDS)
-            .buildNamed("${name}_watermark", WatermarkCacheLoader)
+    private val watermarkCache = cacheFactory.buildNamed(Caffeine.newBuilder()
+            .expireAfterAccess(cacheExpiry.toNanos(), TimeUnit.NANOSECONDS), "${name}_watermark", WatermarkCacheLoader)
 
     private object WatermarkCacheLoader : CacheLoader<Any, AtomicLong> {
         override fun load(key: Any) = AtomicLong(-1)
diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt
index 71a509a54c..d22d8307ab 100644
--- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt
+++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt
@@ -1,6 +1,7 @@
 package net.corda.nodeapi.internal.persistence
 
 import co.paralleluniverse.strands.Strand
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.schemas.MappedSchema
 import net.corda.core.utilities.contextLogger
 import rx.Observable
@@ -54,6 +55,7 @@ val contextDatabaseOrNull: CordaPersistence? get() = _contextDatabase.get()
 class CordaPersistence(
         databaseConfig: DatabaseConfig,
         schemas: Set<MappedSchema>,
+        cacheFactory: NamedCacheFactory,
         attributeConverters: Collection<AttributeConverter<*, *>> = emptySet()
 ) : Closeable {
     companion object {
@@ -63,7 +65,7 @@ class CordaPersistence(
     private val defaultIsolationLevel = databaseConfig.transactionIsolationLevel
     val hibernateConfig: HibernateConfiguration by lazy {
         transaction {
-            HibernateConfiguration(schemas, databaseConfig, attributeConverters, jdbcUrl)
+            HibernateConfiguration(schemas, databaseConfig, attributeConverters, jdbcUrl, cacheFactory)
         }
     }
 
diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt
index 9fce23202c..679be4df8d 100644
--- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt
+++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt
@@ -1,7 +1,7 @@
 package net.corda.nodeapi.internal.persistence
 
 import com.github.benmanes.caffeine.cache.Caffeine
-import net.corda.core.internal.buildNamed
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.castIfPossible
 import net.corda.core.schemas.MappedSchema
 import net.corda.core.utilities.contextLogger
@@ -31,6 +31,7 @@ class HibernateConfiguration(
         private val databaseConfig: DatabaseConfig,
         private val attributeConverters: Collection<AttributeConverter<*, *>>,
         private val jdbcUrl: String,
+        cacheFactory: NamedCacheFactory,
         val cordappClassLoader: ClassLoader? = null
 ) {
     companion object {
@@ -63,7 +64,7 @@ class HibernateConfiguration(
         }
     }
 
-    private val sessionFactories = Caffeine.newBuilder().maximumSize(databaseConfig.mappedSchemaCacheSize).buildNamed<Set<MappedSchema>, SessionFactory>("HibernateConfiguration_sessionFactories")
+    private val sessionFactories = cacheFactory.buildNamed<Set<MappedSchema>, SessionFactory>(Caffeine.newBuilder(), "HibernateConfiguration_sessionFactories")
 
     val sessionFactoryForRegisteredSchemas = schemas.let {
         logger.info("Init HibernateConfiguration for schemas: $it")
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt
index 2a63d16066..9e2b93f8b2 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt
+++ b/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt
@@ -8,11 +8,7 @@ import net.corda.core.crypto.generateKeyPair
 import net.corda.core.internal.div
 import net.corda.core.utilities.NetworkHostAndPort
 import net.corda.core.utilities.seconds
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.config.*
-import net.corda.node.services.config.FlowTimeoutConfiguration
-import net.corda.node.services.config.NodeConfiguration
-import net.corda.node.services.config.configureWithDevSSLCertificate
 import net.corda.node.services.network.PersistentNetworkMapCache
 import net.corda.node.services.transactions.PersistentUniquenessProvider
 import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
@@ -23,14 +19,14 @@ import net.corda.testing.core.MAX_MESSAGE_SIZE
 import net.corda.testing.core.SerializationEnvironmentRule
 import net.corda.testing.driver.PortAllocation
 import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.internal.rigorousMock
 import net.corda.testing.internal.stubs.CertificateStoreStubs
 import net.corda.testing.node.internal.MOCK_VERSION_INFO
 import net.corda.testing.node.internal.makeInternalTestDataSourceProperties
 import org.apache.activemq.artemis.api.core.Message.HDR_VALIDATED_USER
 import org.apache.activemq.artemis.api.core.SimpleString
-import net.corda.testing.internal.TestingNamedCacheFactory
-import org.apache.activemq.artemis.api.core.ActiveMQConnectionTimedOutException
 import org.assertj.core.api.Assertions.assertThat
 import org.assertj.core.api.Assertions.assertThatThrownBy
 import org.junit.After
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt
index 7a061840aa..9a99c3ccfa 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt
+++ b/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt
@@ -2,18 +2,14 @@ package net.corda.node.services.network
 
 import net.corda.core.node.NodeInfo
 import net.corda.core.utilities.NetworkHostAndPort
-import net.corda.node.internal.configureDatabase
 import net.corda.node.internal.schemas.NodeInfoSchemaV1
 import net.corda.node.services.identity.InMemoryIdentityService
 import net.corda.nodeapi.internal.DEV_ROOT_CA
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.core.*
-import net.corda.testing.internal.IntegrationTest
-import net.corda.testing.internal.IntegrationTestSchemas
-import net.corda.testing.internal.toDatabaseSchemaName
+import net.corda.testing.internal.*
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
-import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.testing.node.internal.makeTestDatabaseProperties
 import org.assertj.core.api.Assertions.assertThat
 import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
@@ -36,7 +32,7 @@ class PersistentNetworkMapCacheTest : IntegrationTest() {
     private var portCounter = 1000
 
     //Enterprise only - objects created in the setup method, below initialized with dummy values to avoid need for nullable type declaration
-    private var database = CordaPersistence(DatabaseConfig(), emptySet())
+    private var database = CordaPersistence(DatabaseConfig(), emptySet(), TestingNamedCacheFactory())
     private var charlieNetMapCache = PersistentNetworkMapCache(TestingNamedCacheFactory(), database, InMemoryIdentityService(trustRoot = DEV_ROOT_CA.certificate))
 
     @Before()
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt
index cd000f9845..ada8572c09 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt
+++ b/node/src/integration-test/kotlin/net/corda/node/services/rpc/ArtemisRpcTests.kt
@@ -23,6 +23,8 @@ import net.corda.nodeapi.internal.config.MutualSslConfiguration
 import net.corda.nodeapi.internal.config.User
 import net.corda.testing.core.SerializationEnvironmentRule
 import net.corda.testing.driver.PortAllocation
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.fromUserList
 import net.corda.testing.internal.p2pSslOptions
 import org.apache.activemq.artemis.api.core.ActiveMQConnectionTimedOutException
 import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl
@@ -128,7 +130,7 @@ class ArtemisRpcTests {
 
     private fun <OPS : RPCOps> InternalRPCMessagingClient<OPS>.start(ops: OPS, securityManager: RPCSecurityManager, brokerControl: ActiveMQServerControl) {
         apply {
-            init(ops, securityManager)
+            init(ops, securityManager, TestingNamedCacheFactory())
             start(brokerControl)
         }
     }
diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
index 420d7fd2a1..43f0ad18f9 100644
--- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
@@ -18,6 +18,7 @@ import net.corda.core.identity.CordaX500Name
 import net.corda.core.identity.Party
 import net.corda.core.identity.PartyAndCertificate
 import net.corda.core.internal.FlowStateMachine
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.VisibleForTesting
 import net.corda.core.internal.concurrent.map
 import net.corda.core.internal.concurrent.openFuture
@@ -118,7 +119,7 @@ import net.corda.core.crypto.generateKeyPair as cryptoGenerateKeyPair
 // TODO Log warning if this node is a notary but not one of the ones specified in the network parameters, both for core and custom
 abstract class AbstractNode<S>(val configuration: NodeConfiguration,
                                val platformClock: CordaClock,
-                               cacheFactoryPrototype: NamedCacheFactory,
+                               cacheFactoryPrototype: BindableNamedCacheFactory,
                                protected val versionInfo: VersionInfo,
                                protected val serverThread: AffinityExecutor.ServiceAffinityExecutor,
                                protected val busyNodeLatch: ReusableLatch = ReusableLatch()) : SingletonSerializeAsToken() {
@@ -152,8 +153,8 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
             configuration.database,
             identityService::wellKnownPartyFromX500Name,
             identityService::wellKnownPartyFromAnonymous,
-            schemaService
-    )
+            schemaService,
+            cacheFactory)
     init {
         // TODO Break cyclic dependency
         identityService.database = database
@@ -171,7 +172,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
     val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, transactionStorage)
     @Suppress("LeakingThis")
     val vaultService = makeVaultService(keyManagementService, servicesForResolution, database).tokenize()
-    val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database)
+    val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database, cacheFactory)
     val flowLogicRefFactory = FlowLogicRefFactoryImpl(cordappLoader.appClassLoader)
     val networkMapUpdater = NetworkMapUpdater(
             networkMapCache,
@@ -187,7 +188,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
     ).closeOnStop()
     @Suppress("LeakingThis")
     val transactionVerifierService = InMemoryTransactionVerifierService(transactionVerifierWorkerCount).tokenize()
-    val contractUpgradeService = ContractUpgradeServiceImpl().tokenize()
+    val contractUpgradeService = ContractUpgradeServiceImpl(cacheFactory).tokenize()
     val auditService = DummyAuditService().tokenize()
     @Suppress("LeakingThis")
     protected val network: MessagingService = makeMessagingService().tokenize()
@@ -1036,30 +1037,18 @@ class FlowStarterImpl(private val smm: StateMachineManager, private val flowLogi
 
 class ConfigurationException(message: String) : CordaException(message)
 
-// TODO This is no longer used by AbstractNode and can be moved elsewhere
-fun configureDatabase(hikariProperties: Properties,
-                      databaseConfig: DatabaseConfig,
-                      wellKnownPartyFromX500Name: (CordaX500Name) -> Party?,
-                      wellKnownPartyFromAnonymous: (AbstractParty) -> Party?,
-                      schemaService: SchemaService = NodeSchemaService()): CordaPersistence {
-    val isH2Database = isH2Database(hikariProperties.getProperty("dataSource.url", ""))
-    val schemas = if (isH2Database) NodeSchemaService().internalSchemas() else schemaService.schemaOptions.keys
-    return createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService)
-            .apply { startHikariPool(hikariProperties, databaseConfig, schemas) }
-
-}
-
 fun createCordaPersistence(databaseConfig: DatabaseConfig,
                            wellKnownPartyFromX500Name: (CordaX500Name) -> Party?,
                            wellKnownPartyFromAnonymous: (AbstractParty) -> Party?,
-                           schemaService: SchemaService): CordaPersistence {
+                           schemaService: SchemaService,
+                           cacheFactory: NamedCacheFactory): CordaPersistence {
     // Register the AbstractPartyDescriptor so Hibernate doesn't warn when encountering AbstractParty. Unfortunately
     // Hibernate warns about not being able to find a descriptor if we don't provide one, but won't use it by default
     // so we end up providing both descriptor and converter. We should re-examine this in later versions to see if
     // either Hibernate can be convinced to stop warning, use the descriptor by default, or something else.
     JavaTypeDescriptorRegistry.INSTANCE.addDescriptor(AbstractPartyDescriptor(wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous))
     val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous))
-    return CordaPersistence(databaseConfig, schemaService.schemaOptions.keys, attributeConverters)
+    return CordaPersistence(databaseConfig, schemaService.schemaOptions.keys, cacheFactory, attributeConverters)
 }
 
 fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set<MappedSchema>, metricRegistry: MetricRegistry? = null) {
diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt
index 1723aec99e..f2b7553d8d 100644
--- a/node/src/main/kotlin/net/corda/node/internal/Node.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt
@@ -44,6 +44,7 @@ import net.corda.node.services.config.*
 import net.corda.node.services.messaging.*
 import net.corda.node.services.rpc.ArtemisRpcBroker
 import net.corda.node.utilities.*
+import net.corda.node.utilities.profiling.getTracingConfig
 import net.corda.nodeapi.internal.ArtemisMessagingClient
 import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.INTERNAL_SHELL_USER
 import net.corda.nodeapi.internal.ShutdownHook
@@ -86,7 +87,7 @@ class NodeWithInfo(val node: Node, val info: NodeInfo) {
 open class Node(configuration: NodeConfiguration,
                 versionInfo: VersionInfo,
                 private val initialiseSerialization: Boolean = true,
-                cacheFactoryPrototype: NamedCacheFactory = DefaultNamedCacheFactory()
+                cacheFactoryPrototype: BindableNamedCacheFactory = EnterpriseNamedCacheFactory(configuration.enterpriseConfiguration.getTracingConfig())
 ) : AbstractNode<NodeInfo>(
         configuration,
         createClock(configuration),
@@ -224,7 +225,7 @@ open class Node(configuration: NodeConfiguration,
         val securityManagerConfig = configuration.security?.authService
                 ?: SecurityConfiguration.AuthService.fromUsers(configuration.rpcUsers)
 
-        val securityManager = with(RPCSecurityManagerImpl(securityManagerConfig)) {
+        val securityManager = with(RPCSecurityManagerImpl(securityManagerConfig, cacheFactory)) {
             if (configuration.shouldStartLocalShell()) RPCSecurityManagerWithAdditionalUser(this, User(INTERNAL_SHELL_USER, INTERNAL_SHELL_USER, setOf(Permissions.all()))) else this
         }
 
@@ -285,7 +286,7 @@ open class Node(configuration: NodeConfiguration,
         // Start up the MQ clients.
         internalRpcMessagingClient?.run {
             closeOnStop()
-            init(rpcOps, securityManager)
+            init(rpcOps, securityManager, cacheFactory)
         }
         network.closeOnStop()
         network.start(
diff --git a/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt b/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt
index bd7fcb9f72..5186e234b7 100644
--- a/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt
@@ -4,14 +4,13 @@ package net.corda.node.internal.security
 import com.github.benmanes.caffeine.cache.Cache
 import com.github.benmanes.caffeine.cache.Caffeine
 import com.google.common.primitives.Ints
-import net.corda.core.context.AuthServiceId
-import net.corda.core.internal.buildNamed
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.uncheckedCast
 import net.corda.core.utilities.loggerFor
 import net.corda.node.internal.DataSourceFactory
+import net.corda.node.services.config.AuthDataSourceType
 import net.corda.node.services.config.PasswordEncryption
 import net.corda.node.services.config.SecurityConfiguration
-import net.corda.node.services.config.AuthDataSourceType
 import net.corda.nodeapi.internal.config.User
 import org.apache.shiro.authc.*
 import org.apache.shiro.authc.credential.PasswordMatcher
@@ -28,22 +27,22 @@ import org.apache.shiro.realm.jdbc.JdbcRealm
 import org.apache.shiro.subject.PrincipalCollection
 import org.apache.shiro.subject.SimplePrincipalCollection
 import java.io.Closeable
-import javax.security.auth.login.FailedLoginException
 import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.TimeUnit
+import javax.security.auth.login.FailedLoginException
+
 private typealias AuthServiceConfig = SecurityConfiguration.AuthService
 
 /**
  * Default implementation of [RPCSecurityManager] adapting
  * [org.apache.shiro.mgt.SecurityManager]
  */
-class RPCSecurityManagerImpl(config: AuthServiceConfig) : RPCSecurityManager {
+class RPCSecurityManagerImpl(config: AuthServiceConfig, cacheFactory: NamedCacheFactory) : RPCSecurityManager {
 
     override val id = config.id
     private val manager: DefaultSecurityManager
 
     init {
-        manager = buildImpl(config)
+        manager = buildImpl(config, cacheFactory)
     }
 
     @Throws(FailedLoginException::class)
@@ -75,14 +74,8 @@ class RPCSecurityManagerImpl(config: AuthServiceConfig) : RPCSecurityManager {
 
         private val logger = loggerFor<RPCSecurityManagerImpl>()
 
-        /**
-         * Instantiate RPCSecurityManager initialised with users data from a list of [User]
-         */
-        fun fromUserList(id: AuthServiceId, users: List<User>) =
-                RPCSecurityManagerImpl(AuthServiceConfig.fromUsers(users).copy(id = id))
-
         // Build internal Shiro securityManager instance
-        private fun buildImpl(config: AuthServiceConfig): DefaultSecurityManager {
+        private fun buildImpl(config: AuthServiceConfig, cacheFactory: NamedCacheFactory): DefaultSecurityManager {
             val realm = when (config.dataSource.type) {
                 AuthDataSourceType.DB -> {
                     logger.info("Constructing DB-backed security data source: ${config.dataSource.connection}")
@@ -98,7 +91,8 @@ class RPCSecurityManagerImpl(config: AuthServiceConfig) : RPCSecurityManager {
                 it.cacheManager = config.options?.cache?.let {
                     CaffeineCacheManager(
                             timeToLiveSeconds = it.expireAfterSecs,
-                            maxSize = it.maxEntries)
+                            maxSize = it.maxEntries,
+                            cacheFactory = cacheFactory)
                 }
             }
         }
@@ -294,7 +288,8 @@ private fun <K : Any, V> Cache<K, V>.toShiroCache() = object : ShiroCache<K, V>
  * cache implementation in [com.github.benmanes.caffeine.cache.Cache]
  */
 private class CaffeineCacheManager(val maxSize: Long,
-                                   val timeToLiveSeconds: Long) : CacheManager {
+                                   val timeToLiveSeconds: Long,
+                                   val cacheFactory: NamedCacheFactory) : CacheManager {
 
     private val instances = ConcurrentHashMap<String, ShiroCache<*, *>>()
 
@@ -306,11 +301,7 @@ private class CaffeineCacheManager(val maxSize: Long,
 
     private fun <K : Any, V> buildCache(name: String): ShiroCache<K, V> {
         logger.info("Constructing cache '$name' with maximumSize=$maxSize, TTL=${timeToLiveSeconds}s")
-        return Caffeine.newBuilder()
-                .expireAfterWrite(timeToLiveSeconds, TimeUnit.SECONDS)
-                .maximumSize(maxSize)
-                .buildNamed<K, V>("RPCSecurityManagerShiroCache_$name")
-                .toShiroCache()
+        return cacheFactory.buildNamed<K, V>(Caffeine.newBuilder(), "RPCSecurityManagerShiroCache_$name").toShiroCache()
     }
 
     companion object {
diff --git a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt
index 8d5583544f..7ccd6db8b9 100644
--- a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt
+++ b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt
@@ -6,6 +6,7 @@ import net.corda.core.crypto.SecureHash
 import net.corda.core.flows.FlowLogic
 import net.corda.core.flows.StateMachineRunId
 import net.corda.core.internal.FlowStateMachine
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.concurrent.OpenFuture
 import net.corda.core.messaging.DataFeed
 import net.corda.core.messaging.StateMachineTransactionMapping
@@ -25,7 +26,6 @@ import net.corda.node.services.network.NetworkMapUpdater
 import net.corda.node.services.persistence.AttachmentStorageInternal
 import net.corda.node.services.statemachine.ExternalEvent
 import net.corda.node.services.statemachine.FlowStateMachineImpl
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import java.security.PublicKey
 
diff --git a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt
index 46f29b1ffd..43de48c6b7 100644
--- a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt
@@ -2,6 +2,7 @@ package net.corda.node.services.identity
 
 import net.corda.core.crypto.SecureHash
 import net.corda.core.identity.*
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.hash
 import net.corda.core.node.services.UnknownAnonymousPartyException
 import net.corda.core.serialization.SingletonSerializeAsToken
@@ -10,7 +11,6 @@ import net.corda.core.utilities.contextLogger
 import net.corda.core.utilities.debug
 import net.corda.node.services.api.IdentityServiceInternal
 import net.corda.node.utilities.AppendOnlyPersistentMap
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.crypto.X509CertificateFactory
 import net.corda.nodeapi.internal.crypto.x509Certificates
 import net.corda.nodeapi.internal.persistence.CordaPersistence
diff --git a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt
index 835a751c73..574ca82aca 100644
--- a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt
@@ -2,11 +2,11 @@ package net.corda.node.services.keys
 
 import net.corda.core.crypto.*
 import net.corda.core.identity.PartyAndCertificate
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.serialization.SingletonSerializeAsToken
 import net.corda.core.utilities.MAX_HASH_HEX_SIZE
 import net.corda.node.services.identity.PersistentIdentityService
 import net.corda.node.utilities.AppendOnlyPersistentMap
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
 import org.apache.commons.lang.ArrayUtils.EMPTY_BYTE_ARRAY
diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt
index d6a5ecabed..544744d557 100644
--- a/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt
+++ b/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt
@@ -1,6 +1,7 @@
 package net.corda.node.services.messaging
 
 import net.corda.core.identity.CordaX500Name
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.messaging.RPCOps
 import net.corda.core.serialization.SingletonSerializeAsToken
 import net.corda.core.serialization.internal.nodeSerializationEnv
@@ -20,11 +21,11 @@ class InternalRPCMessagingClient<OPS : RPCOps>(val sslConfig: MutualSslConfigura
     private var locator: ServerLocator? = null
     private var rpcServer: RPCServer<OPS>? = null
 
-    fun init(rpcOps: OPS, securityManager: RPCSecurityManager) {
-        init(RPCOpsRouting.singleton(nodeName, rpcOps), securityManager)
+    fun init(rpcOps: OPS, securityManager: RPCSecurityManager, cacheFactory: NamedCacheFactory) {
+        init(RPCOpsRouting.singleton(nodeName, rpcOps), securityManager, cacheFactory)
     }
 
-    fun init(rpcOpsRouting: RPCOpsRouting<OPS>, securityManager: RPCSecurityManager) = synchronized(this) {
+    fun init(rpcOpsRouting: RPCOpsRouting<OPS>, securityManager: RPCSecurityManager, cacheFactory: NamedCacheFactory) = synchronized(this) {
 
         val tcpTransport = ArtemisTcpTransport.rpcInternalClientTcpTransport(serverAddress, sslConfig)
         locator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport).apply {
@@ -36,7 +37,7 @@ class InternalRPCMessagingClient<OPS : RPCOps>(val sslConfig: MutualSslConfigura
             isUseGlobalPools = nodeSerializationEnv != null
         }
 
-        rpcServer = RPCServer(rpcOpsRouting, NODE_RPC_USER, NODE_RPC_USER, locator!!, securityManager, nodeName, rpcServerConfiguration)
+        rpcServer = RPCServer(rpcOpsRouting, NODE_RPC_USER, NODE_RPC_USER, locator!!, securityManager, nodeName, rpcServerConfiguration, cacheFactory)
     }
 
     fun start(serverControl: ActiveMQServerControl) = synchronized(this) {
diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt
index 35e6b45cd4..85cdccbf83 100644
--- a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt
+++ b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt
@@ -3,9 +3,9 @@ package net.corda.node.services.messaging
 import com.github.benmanes.caffeine.cache.Caffeine
 import net.corda.core.crypto.SecureHash
 import net.corda.core.identity.CordaX500Name
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.node.services.statemachine.DeduplicationId
 import net.corda.node.utilities.AppendOnlyPersistentMap
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
 import java.time.Instant
diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt
index b75e376e18..8ec46dbaf9 100644
--- a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt
+++ b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt
@@ -6,6 +6,7 @@ import com.codahale.metrics.MetricRegistry
 import net.corda.core.crypto.toStringShort
 import net.corda.core.identity.CordaX500Name
 import net.corda.core.identity.Party
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.ThreadBox
 import net.corda.core.messaging.CordaRPCOps
 import net.corda.core.messaging.MessageRecipients
@@ -29,7 +30,6 @@ import net.corda.node.services.statemachine.DeduplicationId
 import net.corda.node.services.statemachine.ExternalEvent
 import net.corda.node.services.statemachine.SenderDeduplicationId
 import net.corda.node.utilities.AffinityExecutor
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.ArtemisMessagingComponent
 import net.corda.nodeapi.internal.ArtemisMessagingComponent.*
 import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.BRIDGE_CONTROL
diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt
index a908717d1e..5f06b38572 100644
--- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt
+++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt
@@ -13,7 +13,7 @@ import net.corda.core.context.Trace
 import net.corda.core.context.Trace.InvocationId
 import net.corda.core.identity.CordaX500Name
 import net.corda.core.internal.LifeCycle
-import net.corda.core.internal.buildNamed
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.messaging.RPCOps
 import net.corda.core.serialization.SerializationContext
 import net.corda.core.serialization.SerializationDefaults
@@ -33,13 +33,8 @@ import net.corda.nodeapi.internal.persistence.contextDatabase
 import net.corda.nodeapi.internal.persistence.contextDatabaseOrNull
 import org.apache.activemq.artemis.api.core.Message
 import org.apache.activemq.artemis.api.core.SimpleString
+import org.apache.activemq.artemis.api.core.client.*
 import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE
-import org.apache.activemq.artemis.api.core.client.ClientConsumer
-import org.apache.activemq.artemis.api.core.client.ClientMessage
-import org.apache.activemq.artemis.api.core.client.ClientProducer
-import org.apache.activemq.artemis.api.core.client.ClientSession
-import org.apache.activemq.artemis.api.core.client.ClientSessionFactory
-import org.apache.activemq.artemis.api.core.client.ServerLocator
 import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl
 import org.apache.activemq.artemis.api.core.management.CoreNotificationType
 import org.apache.activemq.artemis.api.core.management.ManagementHelper
@@ -86,7 +81,8 @@ class RPCServer<OPS : RPCOps>(
         private val serverLocator: ServerLocator,
         private val securityManager: RPCSecurityManager,
         private val nodeLegalName: CordaX500Name,
-        private val rpcConfiguration: RPCServerConfiguration
+        private val rpcConfiguration: RPCServerConfiguration,
+        private val cacheFactory: NamedCacheFactory
 ) {
     private companion object {
         private val log = contextLogger()
@@ -153,7 +149,7 @@ class RPCServer<OPS : RPCOps>(
     private val responseMessageBuffer = ConcurrentHashMap<SimpleString, BufferOrNone>()
     private val sendJobQueue = LinkedBlockingQueue<RpcSendJob>()
 
-    private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry)
+    private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry, cacheFactory = cacheFactory)
     private var deduplicationIdentity: String? = null
 
     constructor(
@@ -163,8 +159,9 @@ class RPCServer<OPS : RPCOps>(
             serverLocator: ServerLocator,
             securityManager: RPCSecurityManager,
             nodeLegalName: CordaX500Name,
-            rpcConfiguration: RPCServerConfiguration
-    ) : this(RPCOpsRouting.singleton(nodeLegalName, ops), rpcServerUsername, rpcServerPassword, serverLocator, securityManager, nodeLegalName, rpcConfiguration)
+            rpcConfiguration: RPCServerConfiguration,
+            cacheFactory: NamedCacheFactory
+    ) : this(RPCOpsRouting.singleton(nodeLegalName, ops), rpcServerUsername, rpcServerPassword, serverLocator, securityManager, nodeLegalName, rpcConfiguration, cacheFactory)
 
     init {
         // It is assumed that all the identities have the same type of RPCOps associated with them.
@@ -184,7 +181,7 @@ class RPCServer<OPS : RPCOps>(
             log.debug { "Unsubscribing from Observable with id $key because of $cause" }
             value!!.subscription.unsubscribe()
         }
-        return Caffeine.newBuilder().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()).buildNamed("RPCServer_observableSubscription")
+        return cacheFactory.buildNamed(Caffeine.newBuilder().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()), "RPCServer_observableSubscription")
     }
 
     fun start(activeMqServerControl: ActiveMQServerControl) {
diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt
index 385afa93ee..cac58ab17d 100644
--- a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt
+++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt
@@ -6,6 +6,7 @@ import net.corda.core.identity.AbstractParty
 import net.corda.core.identity.CordaX500Name
 import net.corda.core.identity.Party
 import net.corda.core.identity.PartyAndCertificate
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.bufferUntilSubscribed
 import net.corda.core.internal.concurrent.OpenFuture
 import net.corda.core.internal.concurrent.openFuture
@@ -23,7 +24,6 @@ import net.corda.core.utilities.contextLogger
 import net.corda.core.utilities.debug
 import net.corda.node.internal.schemas.NodeInfoSchemaV1
 import net.corda.node.services.api.NetworkMapCacheInternal
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.node.utilities.NonInvalidatingCache
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.bufferUntilDatabaseCommit
diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt
index 79794e804f..308af5b356 100644
--- a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt
+++ b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt
@@ -4,6 +4,7 @@ import net.corda.core.concurrent.CordaFuture
 import net.corda.core.crypto.SecureHash
 import net.corda.core.crypto.TransactionSignature
 import net.corda.core.internal.ConcurrentBox
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.VisibleForTesting
 import net.corda.core.internal.bufferUntilSubscribed
 import net.corda.core.internal.concurrent.doneFuture
@@ -15,7 +16,6 @@ import net.corda.core.transactions.SignedTransaction
 import net.corda.node.services.api.WritableTransactionStorage
 import net.corda.node.services.statemachine.FlowStateMachineImpl
 import net.corda.node.utilities.AppendOnlyPersistentMapBase
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.node.utilities.WeightBasedAppendOnlyPersistentMap
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt
index ca96ef1ad5..31f937f62b 100644
--- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt
@@ -19,7 +19,6 @@ import net.corda.core.node.services.vault.AttachmentSort
 import net.corda.core.serialization.*
 import net.corda.core.utilities.contextLogger
 import net.corda.node.services.vault.HibernateAttachmentQueryCriteriaParser
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.node.utilities.NonInvalidatingCache
 import net.corda.node.utilities.NonInvalidatingWeightBasedCache
 import net.corda.nodeapi.exceptions.DuplicateAttachmentException
diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt
index 2c48dfd6f9..386415f7c9 100644
--- a/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt
+++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt
@@ -1,5 +1,6 @@
 package net.corda.node.services.persistence
 
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.utilities.contextLogger
 import net.corda.core.utilities.debug
 import net.corda.node.services.api.NodePropertiesStore
@@ -17,12 +18,12 @@ import javax.persistence.Table
 /**
  * Simple node properties key value store in DB.
  */
-class NodePropertiesPersistentStore(readPhysicalNodeId: () -> String, database: CordaPersistence) : NodePropertiesStore {
+class NodePropertiesPersistentStore(readPhysicalNodeId: () -> String, database: CordaPersistence, cacheFactory: NamedCacheFactory) : NodePropertiesStore {
     private companion object {
         val logger = contextLogger()
     }
 
-    override val flowsDrainingMode = FlowsDrainingModeOperationsImpl(readPhysicalNodeId, database, logger)
+    override val flowsDrainingMode = FlowsDrainingModeOperationsImpl(readPhysicalNodeId, database, logger, cacheFactory)
 
     fun start() {
         flowsDrainingMode.map.preload()
@@ -40,7 +41,7 @@ class NodePropertiesPersistentStore(readPhysicalNodeId: () -> String, database:
     )
 }
 
-class FlowsDrainingModeOperationsImpl(readPhysicalNodeId: () -> String, private val persistence: CordaPersistence, logger: Logger) : FlowsDrainingModeOperations {
+class FlowsDrainingModeOperationsImpl(readPhysicalNodeId: () -> String, private val persistence: CordaPersistence, logger: Logger, cacheFactory: NamedCacheFactory) : FlowsDrainingModeOperations {
     private val nodeSpecificFlowsExecutionModeKey = "${readPhysicalNodeId()}_flowsExecutionMode"
 
     init {
@@ -52,7 +53,8 @@ class FlowsDrainingModeOperationsImpl(readPhysicalNodeId: () -> String, private
             { key -> key },
             { entity -> entity.key to entity.value!! },
             NodePropertiesPersistentStore::DBNodeProperty,
-            NodePropertiesPersistentStore.DBNodeProperty::class.java
+            NodePropertiesPersistentStore.DBNodeProperty::class.java,
+            cacheFactory
     )
 
     override val values = PublishSubject.create<Pair<Boolean, Boolean>>()!!
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt
index b6c8ebf437..122e10d3c3 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt
+++ b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt
@@ -9,6 +9,7 @@ import net.corda.core.flows.NotarisationRequestSignature
 import net.corda.core.flows.NotaryError
 import net.corda.core.flows.StateConsumptionDetails
 import net.corda.core.identity.Party
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.internal.concurrent.OpenFuture
 import net.corda.core.internal.concurrent.openFuture
 import net.corda.core.internal.notary.AsyncUniquenessProvider
@@ -22,7 +23,6 @@ import net.corda.core.serialization.serialize
 import net.corda.core.utilities.contextLogger
 import net.corda.core.utilities.debug
 import net.corda.node.utilities.AppendOnlyPersistentMap
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
 import net.corda.nodeapi.internal.persistence.currentDBSession
diff --git a/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt
index e6924dd3c7..9aa5739a61 100644
--- a/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt
+++ b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt
@@ -2,6 +2,7 @@ package net.corda.node.services.upgrade
 
 import net.corda.core.contracts.StateRef
 import net.corda.core.contracts.UpgradedContract
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.node.services.ContractUpgradeService
 import net.corda.core.serialization.SingletonSerializeAsToken
 import net.corda.node.utilities.PersistentMap
@@ -11,7 +12,7 @@ import javax.persistence.Entity
 import javax.persistence.Id
 import javax.persistence.Table
 
-class ContractUpgradeServiceImpl : ContractUpgradeService, SingletonSerializeAsToken() {
+class ContractUpgradeServiceImpl(cacheFactory: NamedCacheFactory) : ContractUpgradeService, SingletonSerializeAsToken() {
 
     @Entity
     @Table(name = "${NODE_DATABASE_PREFIX}contract_upgrades")
@@ -26,7 +27,7 @@ class ContractUpgradeServiceImpl : ContractUpgradeService, SingletonSerializeAsT
     )
 
     private companion object {
-        fun createContractUpgradesMap(): PersistentMap<String, String, DBContractUpgrade, String> {
+        fun createContractUpgradesMap(cacheFactory: NamedCacheFactory): PersistentMap<String, String, DBContractUpgrade, String> {
             return PersistentMap(
                     "ContractUpgradeService_upgrades",
                     toPersistentEntityKey = { it },
@@ -37,12 +38,13 @@ class ContractUpgradeServiceImpl : ContractUpgradeService, SingletonSerializeAsT
                             upgradedContractClassName = value
                         }
                     },
-                    persistentEntityClass = DBContractUpgrade::class.java
+                    persistentEntityClass = DBContractUpgrade::class.java,
+                    cacheFactory = cacheFactory
             )
         }
     }
 
-    private val authorisedUpgrade = createContractUpgradesMap()
+    private val authorisedUpgrade = createContractUpgradesMap(cacheFactory)
 
     fun start() {
         authorisedUpgrade.preload()
diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt
index ff5cc3de40..6f15c3466c 100644
--- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt
@@ -13,21 +13,17 @@ import net.corda.core.node.StatesToRecord
 import net.corda.core.node.services.KeyManagementService
 import net.corda.core.node.services.StatesNotAvailableException
 import net.corda.core.node.services.Vault
+import net.corda.core.node.services.Vault.ConstraintInfo.Companion.constraintInfo
 import net.corda.core.node.services.VaultQueryException
 import net.corda.core.node.services.vault.*
-import net.corda.core.node.services.Vault.ConstraintInfo.Companion.constraintInfo
 import net.corda.core.schemas.PersistentStateRef
-import net.corda.core.serialization.SerializationDefaults.STORAGE_CONTEXT
 import net.corda.core.serialization.SingletonSerializeAsToken
-import net.corda.core.serialization.deserialize
-import net.corda.core.serialization.serialize
 import net.corda.core.transactions.*
 import net.corda.core.utilities.*
 import net.corda.node.services.api.SchemaService
 import net.corda.node.services.api.VaultServiceInternal
 import net.corda.node.services.schema.PersistentStateService
 import net.corda.node.services.statemachine.FlowStateMachineImpl
-import net.corda.node.utilities.NamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.bufferUntilDatabaseCommit
 import net.corda.nodeapi.internal.persistence.currentDBSession
diff --git a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt
index 81f080e425..532a71f497 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt
@@ -2,6 +2,7 @@ package net.corda.node.utilities
 
 import com.github.benmanes.caffeine.cache.LoadingCache
 import com.github.benmanes.caffeine.cache.Weigher
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.utilities.contextLogger
 import net.corda.nodeapi.internal.persistence.DatabaseTransaction
 import net.corda.nodeapi.internal.persistence.contextTransaction
@@ -12,7 +13,6 @@ import java.util.concurrent.ConcurrentHashMap
 import java.util.concurrent.atomic.AtomicBoolean
 import java.util.concurrent.atomic.AtomicReference
 
-
 /**
  * Implements a caching layer on top of an *append-only* table accessed via Hibernate mapping. Note that if the same key is [set] twice,
  * typically this will result in a duplicate insert if this is racing with another transaction.  The flow framework will then retry.
diff --git a/node/src/main/kotlin/net/corda/node/utilities/CaffeineStatsCounter.kt b/node/src/main/kotlin/net/corda/node/utilities/CaffeineStatsCounter.kt
index a0e33d84ff..3b97407047 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/CaffeineStatsCounter.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/CaffeineStatsCounter.kt
@@ -10,16 +10,15 @@ import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
 import com.github.benmanes.caffeine.cache.stats.CacheStats
 import com.github.benmanes.caffeine.cache.stats.StatsCounter
-import net.corda.core.internal.buildNamed
 import java.util.concurrent.TimeUnit
 import java.util.function.Supplier
 
 /**
- * Helper to export statistics to JMX and finally build the cache.
+ * Helpers to export statistics to JMX and finally build the cache.
  */
-fun <K, V> Caffeine<in K, in V>.buildNamed(registry: MetricRegistry, metricsPrefix: String): Cache<K, V> = this.addMetrics(registry, metricsPrefix).buildNamed<K, V>(metricsPrefix).addExtraMetrics(registry, metricsPrefix)
+fun <K, V> Caffeine<in K, in V>.buildNamed(registry: MetricRegistry, metricsPrefix: String): Cache<K, V> = this.addMetrics(registry, metricsPrefix).build<K, V>().addExtraMetrics(registry, metricsPrefix)
 
-fun <K, V> Caffeine<in K, in V>.buildNamed(registry: MetricRegistry, metricsPrefix: String, loader: CacheLoader<K, V>): LoadingCache<K, V> = this.recordStats(CaffeineStatsCounter.supplier(registry, "Caches/$metricsPrefix")).buildNamed<K, V>(metricsPrefix, loader).addExtraMetrics(registry, metricsPrefix)
+fun <K, V> Caffeine<in K, in V>.buildNamed(registry: MetricRegistry, metricsPrefix: String, loader: CacheLoader<K, V>): LoadingCache<K, V> = this.addMetrics(registry, metricsPrefix).build<K, V>(loader).addExtraMetrics(registry, metricsPrefix)
 
 private fun <K, V> Caffeine<in K, in V>.addMetrics(registry: MetricRegistry, metricsPrefix: String): Caffeine<in K, in V> = this.recordStats(CaffeineStatsCounter.supplier(registry, "Caches/$metricsPrefix"))
 private fun <K, V, C : Cache<K, V>> C.addExtraMetrics(registry: MetricRegistry, metricsPrefix: String): C = this.apply {
diff --git a/node/src/main/kotlin/net/corda/node/utilities/EnterpriseNamedCacheFactory.kt b/node/src/main/kotlin/net/corda/node/utilities/EnterpriseNamedCacheFactory.kt
index d0295bbe2a..a62d75f903 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/EnterpriseNamedCacheFactory.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/EnterpriseNamedCacheFactory.kt
@@ -7,18 +7,17 @@ import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
 import net.corda.core.internal.profiling.CacheTracing
 import net.corda.core.internal.profiling.CacheTracing.Companion.wrap
-import net.corda.core.serialization.SingletonSerializeAsToken
 import net.corda.node.services.config.KB
 import net.corda.node.services.config.MB
 import net.corda.node.services.config.NodeConfiguration
 import java.util.concurrent.TimeUnit
 
 
-class EnterpriseNamedCacheFactory private constructor(private val tracingConfig: CacheTracing.CacheTracingConfig, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : NamedCacheFactory, SingletonSerializeAsToken() {
+class EnterpriseNamedCacheFactory private constructor(private val tracingConfig: CacheTracing.CacheTracingConfig, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : DefaultNamedCacheFactory(metricRegistry, nodeConfiguration) {
     constructor(tracingConfig: CacheTracing.CacheTracingConfig) : this(tracingConfig, null, null)
 
-    override fun bindWithMetrics(metricRegistry: MetricRegistry): NamedCacheFactory = EnterpriseNamedCacheFactory(tracingConfig, metricRegistry, this.nodeConfiguration)
-    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): NamedCacheFactory = EnterpriseNamedCacheFactory(tracingConfig, this.metricRegistry, nodeConfiguration)
+    override fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = EnterpriseNamedCacheFactory(tracingConfig, metricRegistry, this.nodeConfiguration)
+    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = EnterpriseNamedCacheFactory(tracingConfig, this.metricRegistry, nodeConfiguration)
 
     // Scale most caches off the transaction cache size.
     private fun defaultBound(nodeConfiguration: NodeConfiguration): Long = nodeConfiguration.transactionCacheSizeBytes / 8.KB
@@ -29,23 +28,25 @@ class EnterpriseNamedCacheFactory private constructor(private val tracingConfig:
     // This results in a minium of 1024 entries as per OS, but then grows linearly with attachment cache size.
     private fun defaultAttachmentPresenceCacheBound(nodeConfiguration: NodeConfiguration): Long = defaultAttachmentCacheBound(nodeConfiguration) / 10.KB
 
-    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
-        checkNotNull(metricRegistry)
-        checkNotNull(nodeConfiguration)
-        return wrap(caffeine.maximumSize(defaultBound(nodeConfiguration!!)).buildNamed<K, V>(metricRegistry!!, name), tracingConfig, name)
+    override val defaultCacheSize = if (nodeConfiguration == null) super.defaultCacheSize else defaultAttachmentCacheBound(nodeConfiguration)
+
+    override fun <K, V> configuredForNamed(caffeine: Caffeine<K, V>, name: String): Caffeine<K, V> {
+        return with(nodeConfiguration!!) {
+            when {
+                name == "NodeVaultService_producedStates" -> caffeine.maximumSize(defaultCacheSize)
+                name == "NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(defaultAttachmentCacheBound(this))
+                name == "NodeAttachmentService_attachmentPresence" -> caffeine.maximumSize(defaultAttachmentPresenceCacheBound(this))
+                name == "P2PMessageDeduplicator_senderUUIDSeqNoHWM" -> caffeine.expireAfterAccess(7, TimeUnit.DAYS)
+                else -> super.configuredForNamed(caffeine, name)
+            }
+        }
+    }
+
+    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
+        return wrap(configuredForNamed(caffeine, name).buildNamed<K, V>(metricRegistry!!, name), tracingConfig, name)
     }
 
-    // TODO: allow a config file override for any named cache.
     override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
-        checkNotNull(metricRegistry)
-        checkNotNull(nodeConfiguration)
-        val configuredCaffeine = when (name) {
-            "DBTransactionStorage_transactions" -> caffeine.maximumWeight(nodeConfiguration!!.transactionCacheSizeBytes)
-            "NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(defaultAttachmentCacheBound(nodeConfiguration!!))
-            "NodeAttachmentService_attachmentPresence" -> caffeine.maximumSize(defaultAttachmentPresenceCacheBound(nodeConfiguration!!))
-            "P2PMessageDeduplicator_senderUUIDSeqNoHWM" -> caffeine.expireAfterAccess(7, TimeUnit.DAYS)
-            else -> caffeine.maximumSize(defaultBound(nodeConfiguration!!))
-        }
-        return wrap(configuredCaffeine.buildNamed<K, V>(metricRegistry!!, name, loader), tracingConfig, name)
+        return wrap(configuredForNamed(caffeine, name).buildNamed<K, V>(metricRegistry!!, name, loader), tracingConfig, name)
     }
 }
\ No newline at end of file
diff --git a/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt
index d11c9667c2..5c2b9a1241 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/NodeNamedCache.kt
@@ -5,50 +5,77 @@ import com.github.benmanes.caffeine.cache.Cache
 import com.github.benmanes.caffeine.cache.CacheLoader
 import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
-import net.corda.core.internal.buildNamed
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.serialization.SerializeAsToken
 import net.corda.core.serialization.SingletonSerializeAsToken
 import net.corda.node.services.config.NodeConfiguration
+import java.util.concurrent.TimeUnit
 
 /**
- * Allow passing metrics and config to caching implementations.
+ * Allow passing metrics and config to caching implementations.  This is needs to be distinct from [NamedCacheFactory]
+ * to avoid deterministic serialization from seeing metrics and config on method signatures.
  */
-interface NamedCacheFactory : SerializeAsToken {
+interface BindableNamedCacheFactory : NamedCacheFactory, SerializeAsToken {
     /**
      * Build a new cache factory of the same type that incorporates metrics.
      */
-    fun bindWithMetrics(metricRegistry: MetricRegistry): NamedCacheFactory
+    fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory
 
     /**
      * Build a new cache factory of the same type that incorporates the associated configuration.
      */
-    fun bindWithConfig(nodeConfiguration: NodeConfiguration): NamedCacheFactory
-
-    fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V>
-    fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V>
+    fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory
 }
 
-class DefaultNamedCacheFactory private constructor(private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : NamedCacheFactory, SingletonSerializeAsToken() {
+open class DefaultNamedCacheFactory protected constructor(private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : BindableNamedCacheFactory, SingletonSerializeAsToken() {
     constructor() : this(null, null)
 
-    override fun bindWithMetrics(metricRegistry: MetricRegistry): NamedCacheFactory = DefaultNamedCacheFactory(metricRegistry, this.nodeConfiguration)
-    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): NamedCacheFactory = DefaultNamedCacheFactory(this.metricRegistry, nodeConfiguration)
+    override fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = DefaultNamedCacheFactory(metricRegistry, this.nodeConfiguration)
+    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = DefaultNamedCacheFactory(this.metricRegistry, nodeConfiguration)
 
-    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
+    open protected fun <K, V> configuredForNamed(caffeine: Caffeine<K, V>, name: String): Caffeine<K, V> {
+        return with(nodeConfiguration!!) {
+            when {
+                name.startsWith("RPCSecurityManagerShiroCache_") -> with(security?.authService?.options?.cache!!) { caffeine.maximumSize(maxEntries).expireAfterWrite(expireAfterSecs, TimeUnit.SECONDS) }
+                name == "RPCServer_observableSubscription" -> caffeine
+                name == "RpcClientProxyHandler_rpcObservable" -> caffeine
+                name == "SerializationScheme_attachmentClassloader" -> caffeine
+                name == "HibernateConfiguration_sessionFactories" -> caffeine.maximumSize(database.mappedSchemaCacheSize)
+                name == "DBTransactionStorage_transactions" -> caffeine.maximumWeight(transactionCacheSizeBytes)
+                name == "NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(attachmentContentCacheSizeBytes)
+                name == "NodeAttachmentService_attachmentPresence" -> caffeine.maximumSize(attachmentCacheBound)
+                name == "PersistentIdentityService_partyByKey" -> caffeine.maximumSize(defaultCacheSize)
+                name == "PersistentIdentityService_partyByName" -> caffeine.maximumSize(defaultCacheSize)
+                name == "PersistentNetworkMap_nodesByKey" -> caffeine.maximumSize(defaultCacheSize)
+                name == "PersistentNetworkMap_idByLegalName" -> caffeine.maximumSize(defaultCacheSize)
+                name == "PersistentKeyManagementService_keys" -> caffeine.maximumSize(defaultCacheSize)
+                name == "FlowDrainingMode_nodeProperties" -> caffeine.maximumSize(defaultCacheSize)
+                name == "ContractUpgradeService_upgrades" -> caffeine.maximumSize(defaultCacheSize)
+                name == "PersistentUniquenessProvider_transactions" -> caffeine.maximumSize(defaultCacheSize)
+                name == "P2PMessageDeduplicator_processedMessages" -> caffeine.maximumSize(defaultCacheSize)
+                name == "DeduplicationChecker_watermark" -> caffeine
+                name == "BFTNonValidatingNotaryService_transactions" -> caffeine.maximumSize(defaultCacheSize)
+                name == "RaftUniquenessProvider_transactions" -> caffeine.maximumSize(defaultCacheSize)
+                else -> throw IllegalArgumentException("Unexpected cache name $name. Did you add a new cache?")
+            }
+        }
+    }
+
+    protected fun checkState(name: String) {
+        checkCacheName(name)
         checkNotNull(metricRegistry)
         checkNotNull(nodeConfiguration)
-        return caffeine.maximumSize(1024).buildNamed<K, V>(name)
+    }
+
+    override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
+        checkState(name)
+        return configuredForNamed(caffeine, name).build<K, V>()
     }
 
     override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
-        checkNotNull(metricRegistry)
-        checkNotNull(nodeConfiguration)
-        val configuredCaffeine = when (name) {
-            "DBTransactionStorage_transactions" -> caffeine.maximumWeight(nodeConfiguration!!.transactionCacheSizeBytes)
-            "NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(nodeConfiguration!!.attachmentContentCacheSizeBytes)
-            "NodeAttachmentService_attachmentPresence" -> caffeine.maximumSize(nodeConfiguration!!.attachmentCacheBound)
-            else -> caffeine.maximumSize(1024)
-        }
-        return configuredCaffeine.buildNamed<K, V>(name, loader)
+        checkState(name)
+        return configuredForNamed(caffeine, name).build<K, V>(loader)
     }
+
+    open protected val defaultCacheSize = 1024L
 }
\ No newline at end of file
diff --git a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt
index 2cf4904282..25688233c2 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt
@@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.CacheLoader
 import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
 import com.github.benmanes.caffeine.cache.Weigher
+import net.corda.core.internal.NamedCacheFactory
 
 class NonInvalidatingCache<K, V> private constructor(
         val cache: LoadingCache<K, V>
diff --git a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt
index f16ec74f8f..634189a7b7 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt
@@ -5,21 +5,21 @@ import com.github.benmanes.caffeine.cache.CacheLoader
 import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
 import com.github.benmanes.caffeine.cache.RemovalListener
-import net.corda.core.internal.buildNamed
+import net.corda.core.internal.NamedCacheFactory
 
 class NonInvalidatingUnboundCache<K, V> private constructor(
         val cache: LoadingCache<K, V>
 ) : LoadingCache<K, V> by cache {
 
-    constructor(name: String, loadFunction: (K) -> V, removalListener: RemovalListener<K, V> = RemovalListener { _, _, _ -> },
+    constructor(name: String, cacheFactory: NamedCacheFactory, loadFunction: (K) -> V, removalListener: RemovalListener<K, V> = RemovalListener { _, _, _ -> },
                 keysToPreload: () -> Iterable<K> = { emptyList() }) :
-            this(buildCache(name, loadFunction, removalListener, keysToPreload))
+            this(buildCache(name, cacheFactory, loadFunction, removalListener, keysToPreload))
 
     private companion object {
-        private fun <K, V> buildCache(name: String, loadFunction: (K) -> V, removalListener: RemovalListener<K, V>,
+        private fun <K, V> buildCache(name: String, cacheFactory: NamedCacheFactory, loadFunction: (K) -> V, removalListener: RemovalListener<K, V>,
                                       keysToPreload: () -> Iterable<K>): LoadingCache<K, V> {
             val builder = Caffeine.newBuilder().removalListener(removalListener).executor(SameThreadExecutor.getExecutor())
-            return builder.buildNamed(name, NonInvalidatingCacheLoader(loadFunction)).apply {
+            return cacheFactory.buildNamed(builder, name, NonInvalidatingCacheLoader(loadFunction)).apply {
                 getAll(keysToPreload())
             }
         }
diff --git a/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt b/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt
index 2f04ea7bbe..a006ee9883 100644
--- a/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt
+++ b/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt
@@ -2,6 +2,7 @@ package net.corda.node.utilities
 
 import com.github.benmanes.caffeine.cache.RemovalCause
 import com.github.benmanes.caffeine.cache.RemovalListener
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.utilities.contextLogger
 import net.corda.nodeapi.internal.persistence.currentDBSession
 import java.util.*
@@ -14,7 +15,8 @@ class PersistentMap<K : Any, V, E, out EK>(
         val toPersistentEntityKey: (K) -> EK,
         val fromPersistentEntity: (E) -> Pair<K, V>,
         val toPersistentEntity: (key: K, value: V) -> E,
-        val persistentEntityClass: Class<E>
+        val persistentEntityClass: Class<E>,
+        cacheFactory: NamedCacheFactory
 ) : MutableMap<K, V>, AbstractMap<K, V>() {
 
     private companion object {
@@ -24,7 +26,8 @@ class PersistentMap<K : Any, V, E, out EK>(
     private val cache = NonInvalidatingUnboundCache(
             name,
             loadFunction = { key -> Optional.ofNullable(loadValue(key)) },
-            removalListener = ExplicitRemoval(toPersistentEntityKey, persistentEntityClass)
+            removalListener = ExplicitRemoval(toPersistentEntityKey, persistentEntityClass),
+            cacheFactory = cacheFactory
     )
 
     /** Preload to allow [all] to take data only from the cache (cache is unbound) */
diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt
index 8c8c794378..8d25b1ac66 100644
--- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt
+++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt
@@ -38,10 +38,11 @@ import net.corda.testing.core.ALICE_NAME
 import net.corda.testing.core.expect
 import net.corda.testing.core.expectEvents
 import net.corda.testing.core.sequence
-import net.corda.testing.node.internal.cordappsForPackages
+import net.corda.testing.internal.fromUserList
 import net.corda.testing.node.internal.InternalMockNetwork
 import net.corda.testing.node.internal.InternalMockNodeParameters
 import net.corda.testing.node.internal.TestStartedNode
+import net.corda.testing.node.internal.cordappsForPackages
 import net.corda.testing.node.testActor
 import org.apache.commons.io.IOUtils
 import org.assertj.core.api.Assertions.*
diff --git a/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt b/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt
index 7e92e706b6..d4e6a24186 100644
--- a/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt
+++ b/node/src/test/kotlin/net/corda/node/internal/AbstractNodeTests.kt
@@ -7,7 +7,7 @@ import net.corda.core.utilities.contextLogger
 import net.corda.core.utilities.getOrThrow
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.common.internal.relaxedThoroughness
-import net.corda.testing.internal.rigorousMock
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.internal.ProcessUtilities.startJavaProcess
 import org.junit.Rule
 import org.junit.Test
diff --git a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt b/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt
index d7605c8e1a..766e1d6548 100644
--- a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt
+++ b/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt
@@ -18,6 +18,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.core.ALICE_NAME
 import net.corda.testing.core.SerializationEnvironmentRule
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.internal.createNodeInfoAndSigned
 import net.corda.testing.internal.rigorousMock
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
diff --git a/node/src/test/kotlin/net/corda/node/services/RPCSecurityManagerTest.kt b/node/src/test/kotlin/net/corda/node/services/RPCSecurityManagerTest.kt
index f64d72ea87..64ed341993 100644
--- a/node/src/test/kotlin/net/corda/node/services/RPCSecurityManagerTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/RPCSecurityManagerTest.kt
@@ -9,6 +9,8 @@ import net.corda.node.internal.security.tryAuthenticate
 import net.corda.node.services.Permissions.Companion.invokeRpc
 import net.corda.node.services.config.SecurityConfiguration
 import net.corda.nodeapi.internal.config.User
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.fromUserList
 import org.assertj.core.api.Assertions.assertThatThrownBy
 import org.junit.Test
 import javax.security.auth.login.FailedLoginException
@@ -134,7 +136,7 @@ class RPCSecurityManagerTest {
 
     private fun checkUserActions(permissions: Set<String>, permitted: Set<ArrayList<String>>) {
         val user = User(username = "user", password = "password", permissions = permissions)
-        val userRealms = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(listOf(user)))
+        val userRealms = RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(listOf(user)), TestingNamedCacheFactory())
         val disabled = allActions.filter { !permitted.contains(listOf(it)) }
         for (subject in listOf(
                 userRealms.authenticate("user", Password("password")),
diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt
index 7cd1955776..b0279be977 100644
--- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt
@@ -10,13 +10,13 @@ import net.corda.core.internal.FlowStateMachine
 import net.corda.core.internal.concurrent.openFuture
 import net.corda.core.node.ServicesForResolution
 import net.corda.core.utilities.days
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.api.FlowStarter
 import net.corda.node.services.api.NodePropertiesStore
 import net.corda.node.services.messaging.DeduplicationHandler
 import net.corda.node.services.statemachine.ExternalEvent
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.internal.doLookup
 import net.corda.testing.internal.rigorousMock
 import net.corda.testing.internal.spectator
diff --git a/node/src/test/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepositoryTest.kt b/node/src/test/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepositoryTest.kt
index f25588ea74..d478dc473d 100644
--- a/node/src/test/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepositoryTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepositoryTest.kt
@@ -4,9 +4,8 @@ import net.corda.core.contracts.ScheduledStateRef
 import net.corda.core.contracts.StateRef
 import net.corda.core.crypto.SecureHash
 import net.corda.core.utilities.days
-import net.corda.node.internal.configureDatabase
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
-import net.corda.testing.internal.rigorousMock
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices
 import org.junit.Test
 import java.time.Instant
diff --git a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt
index 37cffad6b9..719e1fd380 100644
--- a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt
@@ -7,8 +7,6 @@ import net.corda.core.identity.CordaX500Name
 import net.corda.core.identity.Party
 import net.corda.core.identity.PartyAndCertificate
 import net.corda.core.node.services.UnknownAnonymousPartyException
-import net.corda.node.internal.configureDatabase
-import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.nodeapi.internal.crypto.CertificateType
 import net.corda.nodeapi.internal.crypto.X509Utilities
 import net.corda.nodeapi.internal.crypto.x509Certificates
@@ -17,6 +15,8 @@ import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.core.*
 import net.corda.testing.internal.DEV_INTERMEDIATE_CA
 import net.corda.testing.internal.DEV_ROOT_CA
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import net.corda.testing.node.makeTestIdentityService
 import org.junit.After
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt
index b52d8f39a8..0dea08f1b6 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt
@@ -2,11 +2,11 @@ package net.corda.node.services.persistence
 
 import net.corda.core.schemas.MappedSchema
 import net.corda.core.utilities.loggerFor
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.schema.NodeSchemaService
 import net.corda.node.utilities.AppendOnlyPersistentMap
-import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.junit.After
 import org.junit.Assert.*
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt
index c36629af2a..f599d52eeb 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt
@@ -3,16 +3,15 @@ package net.corda.node.services.persistence
 import net.corda.core.context.InvocationContext
 import net.corda.core.flows.FlowLogic
 import net.corda.core.flows.StateMachineRunId
-import net.corda.core.serialization.internal.CheckpointSerializationDefaults
 import net.corda.core.serialization.SerializedBytes
+import net.corda.core.serialization.internal.CheckpointSerializationDefaults
 import net.corda.core.serialization.internal.checkpointSerialize
 import net.corda.node.internal.CheckpointIncompatibleException
 import net.corda.node.internal.CheckpointVerifier
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.api.CheckpointStorage
 import net.corda.node.services.statemachine.Checkpoint
-import net.corda.node.services.statemachine.SubFlowVersion
 import net.corda.node.services.statemachine.FlowStart
+import net.corda.node.services.statemachine.SubFlowVersion
 import net.corda.node.services.transactions.PersistentUniquenessProvider
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
@@ -20,6 +19,7 @@ import net.corda.testing.core.ALICE_NAME
 import net.corda.testing.core.SerializationEnvironmentRule
 import net.corda.testing.core.TestIdentity
 import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.assertj.core.api.Assertions
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
index 1b9d96c792..66ac3198c3 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
@@ -7,13 +7,13 @@ import net.corda.core.crypto.SignatureMetadata
 import net.corda.core.crypto.TransactionSignature
 import net.corda.core.toFuture
 import net.corda.core.transactions.SignedTransaction
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.transactions.PersistentUniquenessProvider
-import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.core.*
 import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.internal.createWireTransaction
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.assertj.core.api.Assertions.assertThat
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt
index f99d027559..5de8c8461e 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt
@@ -29,7 +29,6 @@ import net.corda.finance.schemas.test.SampleCashSchemaV1
 import net.corda.finance.schemas.test.SampleCashSchemaV2
 import net.corda.finance.schemas.test.SampleCashSchemaV3
 import net.corda.finance.utils.sumCash
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.api.IdentityServiceInternal
 import net.corda.node.services.api.WritableTransactionStorage
 import net.corda.node.services.schema.ContractStateAndRef
@@ -42,6 +41,7 @@ import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.nodeapi.internal.persistence.HibernateConfiguration
 import net.corda.testing.core.*
 import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.internal.rigorousMock
 import net.corda.testing.internal.vault.DummyDealStateSchemaV1
 import net.corda.testing.internal.vault.DummyLinearStateSchemaV1
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt
index 6583677215..a34053f8ae 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt
@@ -13,12 +13,12 @@ import net.corda.core.node.services.vault.AttachmentSort
 import net.corda.core.node.services.vault.Builder
 import net.corda.core.node.services.vault.Sort
 import net.corda.core.utilities.getOrThrow
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.transactions.PersistentUniquenessProvider
-import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import net.corda.testing.node.internal.InternalMockNetwork
 import net.corda.testing.node.internal.startFlow
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/RunOnceServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/RunOnceServiceTest.kt
index 614f0f5ea4..1cc10972e2 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/RunOnceServiceTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/RunOnceServiceTest.kt
@@ -4,8 +4,8 @@ import com.nhaarman.mockito_kotlin.any
 import com.nhaarman.mockito_kotlin.mock
 import com.nhaarman.mockito_kotlin.verify
 import com.nhaarman.mockito_kotlin.whenever
-import net.corda.node.internal.configureDatabase
 import net.corda.nodeapi.internal.persistence.CordaPersistence
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import net.corda.testing.node.internal.makeTestDatabaseProperties
 import org.junit.After
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt
index f775621d18..6dea181d19 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt
@@ -12,6 +12,7 @@ import net.corda.node.services.schema.NodeSchemaService
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.nodeapi.internal.persistence.SchemaMigration
+import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.testing.node.MockServices
 import org.apache.commons.io.FileUtils
 import org.assertj.core.api.Assertions.assertThat
@@ -19,18 +20,18 @@ import org.junit.Test
 import java.lang.reflect.Method
 import java.math.BigInteger
 import java.net.URL
-import javax.persistence.*
 import java.net.URLClassLoader
 import java.nio.file.Files
 import java.nio.file.Path
 import java.util.*
+import javax.persistence.*
 
 class SchemaMigrationTest {
 
     private fun configureDatabase(hikariProperties: Properties,
                           databaseConfig: DatabaseConfig,
                           schemaService: NodeSchemaService = NodeSchemaService()): CordaPersistence =
-            createCordaPersistence(databaseConfig, { null }, { null }, schemaService)
+            createCordaPersistence(databaseConfig, { null }, { null }, schemaService, TestingNamedCacheFactory())
                 .apply { startHikariPool(hikariProperties, databaseConfig, schemaService.schemaOptions.keys) }
 
     @Test
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/TransactionCallbackTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/TransactionCallbackTest.kt
index 7231c3afed..e6c4e8fdf2 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/TransactionCallbackTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/TransactionCallbackTest.kt
@@ -1,7 +1,7 @@
 package net.corda.node.services.persistence
 
-import net.corda.node.internal.configureDatabase
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.junit.After
 import org.junit.Test
diff --git a/node/src/test/kotlin/net/corda/node/services/schema/PersistentStateServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/schema/PersistentStateServiceTests.kt
index d2198115d6..37e8a21255 100644
--- a/node/src/test/kotlin/net/corda/node/services/schema/PersistentStateServiceTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/schema/PersistentStateServiceTests.kt
@@ -7,24 +7,20 @@ import net.corda.core.contracts.TransactionState
 import net.corda.core.crypto.SecureHash
 import net.corda.core.identity.AbstractParty
 import net.corda.core.identity.CordaX500Name
-import net.corda.core.node.services.Vault
 import net.corda.core.schemas.MappedSchema
 import net.corda.core.schemas.PersistentState
 import net.corda.core.schemas.QueryableState
 import net.corda.node.services.api.SchemaService
-import net.corda.node.internal.configureDatabase
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.nodeapi.internal.persistence.currentDBSession
-import net.corda.testing.internal.LogHelper
-import net.corda.testing.core.TestIdentity
 import net.corda.testing.contracts.DummyContract
-import net.corda.testing.internal.rigorousMock
+import net.corda.testing.core.TestIdentity
+import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.junit.After
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Test
-import rx.subjects.PublishSubject
 import kotlin.test.assertEquals
 
 class PersistentStateServiceTests {
diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt b/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt
index 7b79ff93b4..b8e63f4b13 100644
--- a/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt
@@ -8,15 +8,15 @@ import net.corda.core.flows.NotarisationRequestSignature
 import net.corda.core.flows.NotaryError
 import net.corda.core.identity.CordaX500Name
 import net.corda.core.internal.notary.NotaryInternalException
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.schema.NodeSchemaService
-import net.corda.testing.internal.TestingNamedCacheFactory
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.core.SerializationEnvironmentRule
 import net.corda.testing.core.TestIdentity
 import net.corda.testing.core.generateStateRef
 import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.junit.After
 import org.junit.Before
diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
index 50920365bf..cd98fe5476 100644
--- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
@@ -7,9 +7,9 @@ import net.corda.core.identity.CordaX500Name
 import net.corda.core.identity.Party
 import net.corda.core.internal.packageName
 import net.corda.core.node.services.*
+import net.corda.core.node.services.Vault.ConstraintInfo.Type.*
 import net.corda.core.node.services.vault.*
 import net.corda.core.node.services.vault.QueryCriteria.*
-import net.corda.core.node.services.Vault.ConstraintInfo.Type.*
 import net.corda.core.transactions.LedgerTransaction
 import net.corda.core.transactions.TransactionBuilder
 import net.corda.core.utilities.*
@@ -24,13 +24,13 @@ import net.corda.finance.schemas.CashSchemaV1.PersistentCashState
 import net.corda.finance.schemas.CommercialPaperSchemaV1
 import net.corda.finance.schemas.test.SampleCashSchemaV2
 import net.corda.finance.schemas.test.SampleCashSchemaV3
-import net.corda.node.internal.configureDatabase
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.nodeapi.internal.persistence.DatabaseTransaction
 import net.corda.testing.core.*
 import net.corda.testing.internal.TEST_TX_TIME
 import net.corda.testing.internal.chooseIdentity
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.internal.rigorousMock
 import net.corda.testing.internal.vault.*
 import net.corda.testing.node.MockServices
diff --git a/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt b/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt
index e7a1645d68..3c4974d779 100644
--- a/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt
+++ b/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt
@@ -3,8 +3,8 @@ package net.corda.node.utilities
 import com.google.common.util.concurrent.SettableFuture
 import net.corda.core.internal.bufferUntilSubscribed
 import net.corda.core.internal.tee
-import net.corda.node.internal.configureDatabase
 import net.corda.nodeapi.internal.persistence.*
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.assertj.core.api.Assertions.assertThat
 import org.junit.After
diff --git a/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt b/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt
index baaf99a34f..69212e7369 100644
--- a/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt
+++ b/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt
@@ -1,9 +1,10 @@
 package net.corda.node.utilities
 
 import net.corda.core.crypto.SecureHash
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.upgrade.ContractUpgradeServiceImpl
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices
 import org.junit.Test
 import kotlin.test.assertEquals
@@ -25,7 +26,8 @@ class PersistentMapTests {
                         upgradedContractClassName = value
                     }
                 },
-                persistentEntityClass = ContractUpgradeServiceImpl.DBContractUpgrade::class.java
+                persistentEntityClass = ContractUpgradeServiceImpl.DBContractUpgrade::class.java,
+                cacheFactory = TestingNamedCacheFactory()
         ).apply { preload() }
     }
 
diff --git a/notary/jpa/src/test/kotlin/net/corda/notary/jpa/JPAUniquenessProviderTests.kt b/notary/jpa/src/test/kotlin/net/corda/notary/jpa/JPAUniquenessProviderTests.kt
index 068a2c416d..4fa10a59b1 100644
--- a/notary/jpa/src/test/kotlin/net/corda/notary/jpa/JPAUniquenessProviderTests.kt
+++ b/notary/jpa/src/test/kotlin/net/corda/notary/jpa/JPAUniquenessProviderTests.kt
@@ -8,7 +8,6 @@ import net.corda.core.flows.NotarisationRequestSignature
 import net.corda.core.flows.NotaryError
 import net.corda.core.identity.CordaX500Name
 import net.corda.core.internal.notary.NotaryInternalException
-import net.corda.node.internal.configureDatabase
 import net.corda.node.services.config.NotaryConfig
 import net.corda.node.services.schema.NodeSchemaService
 import net.corda.notary.jpa.JPAUniquenessProvider.Companion.decodeStateRef
@@ -19,6 +18,7 @@ import net.corda.testing.core.SerializationEnvironmentRule
 import net.corda.testing.core.TestIdentity
 import net.corda.testing.core.generateStateRef
 import net.corda.testing.internal.LogHelper
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
 import org.junit.After
 import org.junit.Before
diff --git a/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt b/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt
index 1ffdbcce5a..421eb0b093 100644
--- a/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt
+++ b/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt
@@ -10,13 +10,14 @@ import net.corda.finance.DOLLARS
 import net.corda.finance.contracts.Fix
 import net.corda.finance.contracts.asset.CASH
 import net.corda.finance.contracts.asset.Cash
-import net.corda.node.internal.configureDatabase
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.testing.core.*
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.internal.rigorousMock
-import net.corda.testing.node.*
+import net.corda.testing.node.MockServices
 import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
+import net.corda.testing.node.createMockCordaService
 import org.junit.After
 import org.junit.Assert.*
 import org.junit.Before
diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt
index e94e2b95b4..9c78e01926 100644
--- a/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt
+++ b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt
@@ -6,7 +6,6 @@ import net.corda.core.DeleteForDJVM
 import net.corda.core.KeepForDJVM
 import net.corda.core.contracts.Attachment
 import net.corda.core.crypto.SecureHash
-import net.corda.core.internal.buildNamed
 import net.corda.core.internal.copyBytes
 import net.corda.core.serialization.*
 import net.corda.core.utilities.ByteSequence
@@ -77,7 +76,7 @@ data class SerializationContextImpl @JvmOverloads constructor(override val prefe
  */
 @DeleteForDJVM
 internal class AttachmentsClassLoaderBuilder(private val properties: Map<Any, Any>, private val deserializationClassLoader: ClassLoader) {
-    private val cache: Cache<List<SecureHash>, AttachmentsClassLoader> = Caffeine.newBuilder().weakValues().maximumSize(1024).buildNamed("SerializationScheme_attachmentClassloader")
+    private val cache: Cache<List<SecureHash>, AttachmentsClassLoader> = Caffeine.newBuilder().weakValues().maximumSize(1024).build()
 
     fun build(attachmentHashes: List<SecureHash>): AttachmentsClassLoader? {
         val serializationContext = properties[serializationContextKey] as? SerializeAsTokenContext ?: return null // Some tests don't set one.
diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt
index b06814bccb..6464dcf274 100644
--- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt
+++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt
@@ -21,7 +21,6 @@ import net.corda.core.utilities.NetworkHostAndPort
 import net.corda.node.VersionInfo
 import net.corda.node.cordapp.CordappLoader
 import net.corda.node.internal.ServicesForResolutionImpl
-import net.corda.node.internal.configureDatabase
 import net.corda.node.internal.cordapp.JarScanningCordappLoader
 import net.corda.node.services.api.*
 import net.corda.node.services.identity.InMemoryIdentityService
@@ -33,6 +32,7 @@ import net.corda.testing.common.internal.testNetworkParameters
 import net.corda.testing.core.TestIdentity
 import net.corda.testing.internal.DEV_ROOT_CA
 import net.corda.testing.internal.MockCordappProvider
+import net.corda.testing.internal.configureDatabase
 import net.corda.testing.node.internal.*
 import net.corda.testing.services.MockAttachmentStorage
 import java.security.KeyPair
diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/EnterpriseMockNamedCachedFactory.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/EnterpriseMockNamedCachedFactory.kt
index c6d989af37..9468624e7e 100644
--- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/EnterpriseMockNamedCachedFactory.kt
+++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/EnterpriseMockNamedCachedFactory.kt
@@ -5,22 +5,21 @@ import com.github.benmanes.caffeine.cache.Cache
 import com.github.benmanes.caffeine.cache.CacheLoader
 import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
-import net.corda.core.internal.buildNamed
 import net.corda.core.serialization.SingletonSerializeAsToken
 import net.corda.node.services.config.MB
 import net.corda.node.services.config.NodeConfiguration
-import net.corda.node.utilities.NamedCacheFactory
+import net.corda.node.utilities.BindableNamedCacheFactory
 import java.util.concurrent.TimeUnit
 
-class EnterpriseMockNamedCachedFactory(private val sizeOverride: Long, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : NamedCacheFactory, SingletonSerializeAsToken() {
+class EnterpriseMockNamedCachedFactory(private val sizeOverride: Long, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : BindableNamedCacheFactory, SingletonSerializeAsToken() {
     constructor(sizeOverride: Long = 1024) : this(sizeOverride, null, null)
 
-    override fun bindWithMetrics(metricRegistry: MetricRegistry): NamedCacheFactory = EnterpriseMockNamedCachedFactory(sizeOverride, metricRegistry, this.nodeConfiguration)
-    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): NamedCacheFactory = EnterpriseMockNamedCachedFactory(sizeOverride, this.metricRegistry, nodeConfiguration)
+    override fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = EnterpriseMockNamedCachedFactory(sizeOverride, metricRegistry, this.nodeConfiguration)
+    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = EnterpriseMockNamedCachedFactory(sizeOverride, this.metricRegistry, nodeConfiguration)
 
     override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
         // Does not check metricRegistry or nodeConfiguration, because for tests we don't care.
-        return caffeine.maximumSize(sizeOverride).buildNamed<K, V>(name)
+        return caffeine.maximumSize(sizeOverride).build<K, V>()
     }
 
     override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
@@ -31,6 +30,6 @@ class EnterpriseMockNamedCachedFactory(private val sizeOverride: Long, private v
             "P2PMessageDeduplicator_senderUUIDSeqNoHWM" -> caffeine.expireAfterAccess(1, TimeUnit.HOURS)
             else -> caffeine.maximumSize(sizeOverride)
         }
-        return configuredCaffeine.buildNamed<K, V>(name, loader)
+        return configuredCaffeine.build<K, V>(loader)
     }
 }
diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt
index 34b6027eba..8efbc54931 100644
--- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt
+++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt
@@ -42,13 +42,13 @@ import net.corda.node.services.messaging.MessagingService
 import net.corda.node.services.persistence.NodeAttachmentService
 import net.corda.node.services.statemachine.StateMachineManager
 import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
-import net.corda.node.utilities.DefaultNamedCacheFactory
+import net.corda.node.utilities.EnterpriseNamedCacheFactory
+import net.corda.node.utilities.profiling.getTracingConfig
 import net.corda.nodeapi.internal.DevIdentityGenerator
 import net.corda.nodeapi.internal.config.User
 import net.corda.nodeapi.internal.network.NetworkParametersCopier
 import net.corda.nodeapi.internal.persistence.CordaPersistence
 import net.corda.nodeapi.internal.persistence.DatabaseConfig
-import net.corda.testing.node.TestCordapp
 import net.corda.testing.common.internal.testNetworkParameters
 import net.corda.testing.internal.rigorousMock
 import net.corda.testing.internal.setGlobalSerialization
@@ -269,7 +269,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
     open class MockNode(args: MockNodeArgs) : AbstractNode<TestStartedNode>(
             args.config,
             TestClock(Clock.systemUTC()),
-            DefaultNamedCacheFactory(),
+            EnterpriseNamedCacheFactory(args.config.enterpriseConfiguration.getTracingConfig()),
             args.version,
             args.network.getServerThread(args.id),
             args.network.busyLatch
diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt
index 19c0398dd9..98ab766aaa 100644
--- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt
+++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt
@@ -24,12 +24,14 @@ import net.corda.node.services.messaging.RPCServerConfiguration
 import net.corda.nodeapi.RPCApi
 import net.corda.nodeapi.internal.ArtemisTcpTransport
 import net.corda.serialization.internal.AMQP_RPC_CLIENT_CONTEXT
-import net.corda.testing.node.TestCordapp
 import net.corda.testing.common.internal.testNetworkParameters
 import net.corda.testing.core.MAX_MESSAGE_SIZE
 import net.corda.testing.driver.JmxPolicy
 import net.corda.testing.driver.PortAllocation
+import net.corda.testing.internal.TestingNamedCacheFactory
+import net.corda.testing.internal.fromUserList
 import net.corda.testing.node.NotarySpec
+import net.corda.testing.node.TestCordapp
 import net.corda.testing.node.User
 import net.corda.testing.node.internal.DriverDSLImpl.Companion.cordappsInCurrentAndAdditionalPackages
 import org.apache.activemq.artemis.api.core.SimpleString
@@ -485,7 +487,8 @@ data class RPCDriverDSL(
                 locator,
                 rpcSecurityManager,
                 nodeLegalName,
-                configuration
+                configuration,
+                TestingNamedCacheFactory()
         )
         driverDSL.shutdownManager.registerShutdown {
             rpcServer.close(queueDrainTimeout)
diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt
index 4ddca172af..e3e7b0ae6d 100644
--- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt
+++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt
@@ -1,26 +1,42 @@
 package net.corda.testing.internal
 
+import net.corda.core.context.AuthServiceId
 import net.corda.core.contracts.*
 import net.corda.core.crypto.Crypto
 import net.corda.core.crypto.Crypto.generateKeyPair
 import net.corda.core.crypto.SecureHash
+import net.corda.core.identity.AbstractParty
 import net.corda.core.identity.CordaX500Name
 import net.corda.core.identity.Party
 import net.corda.core.identity.PartyAndCertificate
+import net.corda.core.internal.NamedCacheFactory
 import net.corda.core.node.NodeInfo
 import net.corda.core.transactions.WireTransaction
 import net.corda.core.utilities.loggerFor
+import net.corda.node.internal.createCordaPersistence
+import net.corda.node.internal.security.RPCSecurityManagerImpl
+import net.corda.node.internal.startHikariPool
+import net.corda.node.services.api.SchemaService
+import net.corda.node.services.config.SecurityConfiguration
+import net.corda.node.services.schema.NodeSchemaService
 import net.corda.nodeapi.BrokerRpcSslOptions
 import net.corda.nodeapi.internal.config.MutualSslConfiguration
-import net.corda.nodeapi.internal.registerDevP2pCertificates
+import net.corda.nodeapi.internal.config.User
 import net.corda.nodeapi.internal.createDevNodeCa
-import net.corda.nodeapi.internal.crypto.*
+import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
+import net.corda.nodeapi.internal.crypto.CertificateType
+import net.corda.nodeapi.internal.crypto.X509Utilities
 import net.corda.nodeapi.internal.loadDevCaTrustStore
+import net.corda.nodeapi.internal.persistence.CordaPersistence
+import net.corda.nodeapi.internal.persistence.DatabaseConfig
+import net.corda.nodeapi.internal.persistence.isH2Database
+import net.corda.nodeapi.internal.registerDevP2pCertificates
 import net.corda.serialization.internal.amqp.AMQP_ENABLED
 import net.corda.testing.internal.stubs.CertificateStoreStubs
 import java.nio.file.Files
 import java.nio.file.Path
 import java.security.KeyPair
+import java.util.*
 import javax.security.auth.x500.X500Principal
 
 @Suppress("unused")
@@ -136,3 +152,25 @@ fun createWireTransaction(inputs: List<StateRef>,
     val componentGroups = WireTransaction.createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow)
     return WireTransaction(componentGroups, privacySalt)
 }
+
+/**
+ * Instantiate RPCSecurityManager initialised with users data from a list of [User]
+ */
+fun RPCSecurityManagerImpl.Companion.fromUserList(id: AuthServiceId, users: List<User>) =
+        RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(users).copy(id = id), TestingNamedCacheFactory())
+
+/**
+ * Convenience method for configuring a database for some tests.
+ */
+fun configureDatabase(hikariProperties: Properties,
+                      databaseConfig: DatabaseConfig,
+                      wellKnownPartyFromX500Name: (CordaX500Name) -> Party?,
+                      wellKnownPartyFromAnonymous: (AbstractParty) -> Party?,
+                      schemaService: SchemaService = NodeSchemaService(),
+                      cacheFactory: NamedCacheFactory = TestingNamedCacheFactory()): CordaPersistence {
+    val isH2Database = isH2Database(hikariProperties.getProperty("dataSource.url", ""))
+    val schemas = if (isH2Database) NodeSchemaService().internalSchemas() else schemaService.schemaOptions.keys
+    val persistence = createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService, cacheFactory)
+    persistence.startHikariPool(hikariProperties, databaseConfig, schemas)
+    return persistence
+}
\ No newline at end of file
diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt
index 7908d5dd27..6802fd042e 100644
--- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt
+++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt
@@ -5,21 +5,20 @@ import com.github.benmanes.caffeine.cache.Cache
 import com.github.benmanes.caffeine.cache.CacheLoader
 import com.github.benmanes.caffeine.cache.Caffeine
 import com.github.benmanes.caffeine.cache.LoadingCache
-import net.corda.core.internal.buildNamed
 import net.corda.core.serialization.SingletonSerializeAsToken
 import net.corda.node.services.config.MB
 import net.corda.node.services.config.NodeConfiguration
-import net.corda.node.utilities.NamedCacheFactory
+import net.corda.node.utilities.BindableNamedCacheFactory
 
-class TestingNamedCacheFactory private constructor(private val sizeOverride: Long, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : NamedCacheFactory, SingletonSerializeAsToken() {
+class TestingNamedCacheFactory private constructor(private val sizeOverride: Long, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : BindableNamedCacheFactory, SingletonSerializeAsToken() {
     constructor(sizeOverride: Long = 1024) : this(sizeOverride, null, null)
 
-    override fun bindWithMetrics(metricRegistry: MetricRegistry): NamedCacheFactory = TestingNamedCacheFactory(sizeOverride, metricRegistry, this.nodeConfiguration)
-    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): NamedCacheFactory = TestingNamedCacheFactory(sizeOverride, this.metricRegistry, nodeConfiguration)
+    override fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = TestingNamedCacheFactory(sizeOverride, metricRegistry, this.nodeConfiguration)
+    override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = TestingNamedCacheFactory(sizeOverride, this.metricRegistry, nodeConfiguration)
 
     override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
         // Does not check metricRegistry or nodeConfiguration, because for tests we don't care.
-        return caffeine.maximumSize(sizeOverride).buildNamed<K, V>(name)
+        return caffeine.maximumSize(sizeOverride).build<K, V>()
     }
 
     override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
@@ -29,6 +28,6 @@ class TestingNamedCacheFactory private constructor(private val sizeOverride: Lon
             "NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(1.MB)
             else -> caffeine.maximumSize(sizeOverride)
         }
-        return configuredCaffeine.buildNamed<K, V>(name, loader)
+        return configuredCaffeine.build<K, V>(loader)
     }
 }
\ No newline at end of file
diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt
index db17fc7749..97a8549688 100644
--- a/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt
+++ b/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt
@@ -14,7 +14,6 @@ import javafx.scene.image.WritableImage
 import javafx.scene.paint.Color
 import javafx.scene.text.TextAlignment
 import net.corda.core.crypto.SecureHash
-import net.corda.core.internal.buildNamed
 
 /**
  *  (The MIT License)
@@ -76,7 +75,7 @@ object IdenticonRenderer {
 
     private const val renderingSize = 30.0
 
-    private val cache = Caffeine.newBuilder().buildNamed("IdentIconRenderer_image", CacheLoader<SecureHash, Image> { key ->
+    private val cache = Caffeine.newBuilder().build(CacheLoader<SecureHash, Image> { key ->
         key.let { render(key.hashCode(), renderingSize) }
     })