mirror of
https://github.com/corda/corda.git
synced 2025-02-04 02:01:13 +00:00
CORDA-676 Eager cordapp schemas (#1839)
* Retire customSchemas. * Key cordapp-to-hash map by url as native equality too strict.
This commit is contained in:
parent
d3d87c2497
commit
38cf4a489e
@ -32,7 +32,7 @@ import static net.corda.testing.TestConstants.getALICE;
|
||||
|
||||
public class CordaRPCJavaClientTest extends NodeBasedTest {
|
||||
public CordaRPCJavaClientTest() {
|
||||
super(Collections.singletonList("net.corda.finance.contracts"));
|
||||
super(Arrays.asList("net.corda.finance.contracts", CashSchemaV1.class.getPackage().getName()));
|
||||
}
|
||||
|
||||
private List<String> perms = Arrays.asList(startFlowPermission(CashPaymentFlow.class), startFlowPermission(CashIssueFlow.class));
|
||||
@ -53,7 +53,6 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
|
||||
public void setUp() throws ExecutionException, InterruptedException {
|
||||
CordaFuture<StartedNode<Node>> nodeFuture = startNotaryNode(getALICE().getName(), singletonList(rpcUser), true);
|
||||
node = nodeFuture.get();
|
||||
node.getInternals().registerCustomSchemas(Collections.singleton(CashSchemaV1.INSTANCE));
|
||||
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package net.corda.client.rpc
|
||||
|
||||
import net.corda.core.crypto.random63BitValue
|
||||
import net.corda.core.flows.FlowInitiator
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.messaging.FlowProgressHandle
|
||||
import net.corda.core.messaging.StateMachineUpdate
|
||||
import net.corda.core.messaging.startFlow
|
||||
@ -32,7 +33,7 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts")) {
|
||||
class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", CashSchemaV1::class.packageName)) {
|
||||
private val rpcUser = User("user1", "test", permissions = setOf(
|
||||
startFlowPermission<CashIssueFlow>(),
|
||||
startFlowPermission<CashPaymentFlow>()
|
||||
@ -48,7 +49,6 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts"))
|
||||
@Before
|
||||
fun setUp() {
|
||||
node = startNotaryNode(ALICE.name, rpcUsers = listOf(rpcUser)).getOrThrow()
|
||||
node.internals.registerCustomSchemas(setOf(CashSchemaV1))
|
||||
client = CordaRPCClient(node.internals.configuration.rpcAddress!!)
|
||||
}
|
||||
|
||||
|
@ -300,3 +300,6 @@ fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serial
|
||||
* @suppress
|
||||
*/
|
||||
fun TransactionBuilder.toLedgerTransaction(services: ServiceHub, serializationContext: SerializationContext) = toLedgerTransactionWithContext(services, serializationContext)
|
||||
|
||||
/** Convenience method to get the package name of a class literal. */
|
||||
val KClass<*>.packageName get() = java.`package`.name
|
||||
|
@ -61,6 +61,7 @@ class InternalUtilsTest {
|
||||
assertArrayEquals(intArrayOf(1, 2, 3, 4), (1 until 5).stream().toArray())
|
||||
assertArrayEquals(intArrayOf(1, 3), (1..4 step 2).stream().toArray())
|
||||
assertArrayEquals(intArrayOf(1, 3), (1..3 step 2).stream().toArray())
|
||||
@Suppress("EmptyRange") // It's supposed to be empty.
|
||||
assertArrayEquals(intArrayOf(), (1..0).stream().toArray())
|
||||
assertArrayEquals(intArrayOf(1, 0), (1 downTo 0).stream().toArray())
|
||||
assertArrayEquals(intArrayOf(3, 1), (3 downTo 0 step 2).stream().toArray())
|
||||
|
@ -2,6 +2,7 @@ package net.corda.docs
|
||||
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.*
|
||||
@ -26,15 +27,12 @@ class CustomVaultQueryTest {
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset"))
|
||||
mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName))
|
||||
mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
|
||||
nodeA = mockNet.createPartyNode()
|
||||
nodeB = mockNet.createPartyNode()
|
||||
|
||||
nodeA.internals.registerInitiatedFlow(TopupIssuerFlow.TopupIssuer::class.java)
|
||||
nodeA.internals.installCordaService(CustomVaultQuery.Service::class.java)
|
||||
nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1))
|
||||
nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1))
|
||||
notary = nodeA.services.getDefaultNotary()
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.docs
|
||||
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
@ -24,12 +25,10 @@ class FxTransactionBuildTutorialTest {
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset"))
|
||||
mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName))
|
||||
mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
|
||||
nodeA = mockNet.createPartyNode()
|
||||
nodeB = mockNet.createPartyNode()
|
||||
nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1))
|
||||
nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1))
|
||||
nodeB.internals.registerInitiatedFlow(ForeignExchangeRemoteFlow::class.java)
|
||||
notary = nodeA.services.getDefaultNotary()
|
||||
}
|
||||
|
@ -55,8 +55,7 @@ class AttachmentsClassLoaderTests : TestDependencyInjectionBase() {
|
||||
|
||||
class DummyServiceHub : MockServices() {
|
||||
override val cordappProvider: CordappProviderImpl
|
||||
= CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH))).start(attachments)
|
||||
|
||||
= CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH)), attachments)
|
||||
private val cordapp get() = cordappProvider.cordapps.first()
|
||||
val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!!
|
||||
val appContext get() = cordappProvider.getAppContext(cordapp)
|
||||
|
@ -37,7 +37,7 @@ import kotlin.test.assertFailsWith
|
||||
|
||||
class AttachmentLoadingTests : TestDependencyInjectionBase() {
|
||||
private class Services : MockServices() {
|
||||
private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR))).start(attachments)
|
||||
private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), attachments)
|
||||
private val cordapp get() = provider.cordapps.first()
|
||||
val attachmentId get() = provider.getCordappAttachmentId(cordapp)!!
|
||||
val appContext get() = provider.getAppContext(cordapp)
|
||||
|
@ -7,7 +7,6 @@ import net.corda.confidential.SwapIdentitiesFlow
|
||||
import net.corda.confidential.SwapIdentitiesHandler
|
||||
import net.corda.core.CordaException
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.cordapp.CordappProvider
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
@ -26,7 +25,6 @@ import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.StateLoader
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
@ -37,6 +35,7 @@ import net.corda.node.VersionInfo
|
||||
import net.corda.node.internal.classloading.requireAnnotation
|
||||
import net.corda.node.internal.cordapp.CordappLoader
|
||||
import net.corda.node.internal.cordapp.CordappProviderImpl
|
||||
import net.corda.node.internal.cordapp.CordappProviderInternal
|
||||
import net.corda.node.services.ContractUpgradeHandler
|
||||
import net.corda.node.services.FinalityHandler
|
||||
import net.corda.node.services.NotaryChangeHandler
|
||||
@ -148,7 +147,6 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
protected lateinit var network: MessagingService
|
||||
protected val runOnStop = ArrayList<() -> Any?>()
|
||||
protected lateinit var database: CordaPersistence
|
||||
lateinit var cordappProvider: CordappProviderImpl
|
||||
protected val _nodeReadyFuture = openFuture<Unit>()
|
||||
/** Completes once the node has successfully registered with the network map service
|
||||
* or has loaded network map data from local database */
|
||||
@ -161,7 +159,7 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
}
|
||||
|
||||
open val serializationWhitelists: List<SerializationWhitelist> by lazy {
|
||||
cordappProvider.cordapps.flatMap { it.serializationWhitelists }
|
||||
cordappLoader.cordapps.flatMap { it.serializationWhitelists }
|
||||
}
|
||||
|
||||
/** Set to non-null once [start] has been successfully called. */
|
||||
@ -185,11 +183,12 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
validateKeystore()
|
||||
}
|
||||
|
||||
private fun makeSchemaService() = NodeSchemaService(cordappLoader)
|
||||
open fun generateNodeInfo() {
|
||||
check(started == null) { "Node has already been started" }
|
||||
initCertificate()
|
||||
log.info("Generating nodeInfo ...")
|
||||
val schemaService = NodeSchemaService()
|
||||
val schemaService = makeSchemaService()
|
||||
initialiseDatabasePersistence(schemaService) {
|
||||
makeServices(schemaService)
|
||||
saveOwnNodeInfo()
|
||||
@ -200,7 +199,7 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
check(started == null) { "Node has already been started" }
|
||||
initCertificate()
|
||||
log.info("Node starting up ...")
|
||||
val schemaService = NodeSchemaService()
|
||||
val schemaService = makeSchemaService()
|
||||
// Do all of this in a database transaction so anything that might need a connection has one.
|
||||
val startedImpl = initialiseDatabasePersistence(schemaService) {
|
||||
val tokenizableServices = makeServices(schemaService)
|
||||
@ -231,8 +230,7 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
|
||||
installCordaServices()
|
||||
registerCordappFlows()
|
||||
_services.rpcFlows += cordappProvider.cordapps.flatMap { it.rpcFlows }
|
||||
registerCustomSchemas(cordappProvider.cordapps.flatMap { it.customSchemas }.toSet())
|
||||
_services.rpcFlows += cordappLoader.cordapps.flatMap { it.rpcFlows }
|
||||
FlowLogicRefFactoryImpl.classloader = cordappLoader.appClassLoader
|
||||
|
||||
runOnStop += network::stop
|
||||
@ -254,7 +252,7 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
private class ServiceInstantiationException(cause: Throwable?) : CordaException("Service Instantiation Error", cause)
|
||||
|
||||
private fun installCordaServices() {
|
||||
val loadedServices = cordappProvider.cordapps.flatMap { it.services }
|
||||
val loadedServices = cordappLoader.cordapps.flatMap { it.services }
|
||||
filterServicesToInstall(loadedServices).forEach {
|
||||
try {
|
||||
installCordaService(it)
|
||||
@ -374,7 +372,7 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
}
|
||||
|
||||
private fun registerCordappFlows() {
|
||||
cordappProvider.cordapps.flatMap { it.initiatedFlows }
|
||||
cordappLoader.cordapps.flatMap { it.initiatedFlows }
|
||||
.forEach {
|
||||
try {
|
||||
registerInitiatedFlowInternal(it, track = false)
|
||||
@ -471,11 +469,11 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
*/
|
||||
private fun makeServices(schemaService: SchemaService): MutableList<Any> {
|
||||
checkpointStorage = DBCheckpointStorage()
|
||||
cordappProvider = CordappProviderImpl(cordappLoader)
|
||||
val transactionStorage = makeTransactionStorage()
|
||||
_services = ServiceHubInternalImpl(schemaService, transactionStorage, StateLoaderImpl(transactionStorage))
|
||||
attachments = NodeAttachmentService(services.monitoringService.metrics)
|
||||
cordappProvider.start(attachments)
|
||||
val metrics = MetricRegistry()
|
||||
attachments = NodeAttachmentService(metrics)
|
||||
val cordappProvider = CordappProviderImpl(cordappLoader, attachments)
|
||||
_services = ServiceHubInternalImpl(schemaService, transactionStorage, StateLoaderImpl(transactionStorage), MonitoringService(metrics), cordappProvider)
|
||||
legalIdentity = obtainIdentity(notaryConfig = null)
|
||||
network = makeMessagingService(legalIdentity)
|
||||
info = makeInfo(legalIdentity)
|
||||
@ -541,7 +539,7 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
protected open fun <T> initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T {
|
||||
val props = configuration.dataSourceProperties
|
||||
if (props.isNotEmpty()) {
|
||||
this.database = configureDatabase(props, configuration.database, schemaService, { _services.identityService })
|
||||
this.database = configureDatabase(props, configuration.database, { _services.identityService }, schemaService)
|
||||
// Now log the vendor string as this will also cause a connection to be tested eagerly.
|
||||
database.transaction {
|
||||
log.info("Connected to ${database.dataSource.connection.metaData.databaseProductName} database.")
|
||||
@ -764,12 +762,13 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
private inner class ServiceHubInternalImpl(
|
||||
override val schemaService: SchemaService,
|
||||
override val validatedTransactions: WritableTransactionStorage,
|
||||
private val stateLoader: StateLoader
|
||||
private val stateLoader: StateLoader,
|
||||
override val monitoringService: MonitoringService,
|
||||
override val cordappProvider: CordappProviderInternal
|
||||
) : SingletonSerializeAsToken(), ServiceHubInternal, StateLoader by stateLoader {
|
||||
override val rpcFlows = ArrayList<Class<out FlowLogic<*>>>()
|
||||
override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage()
|
||||
override val auditService = DummyAuditService()
|
||||
override val monitoringService = MonitoringService(MetricRegistry())
|
||||
override val transactionVerifierService by lazy { makeTransactionVerifierService() }
|
||||
override val networkMapCache by lazy { PersistentNetworkMapCache(this) }
|
||||
override val vaultService by lazy { NodeVaultService(platformClock, keyManagementService, stateLoader, this@AbstractNode.database.hibernateConfig) }
|
||||
@ -794,8 +793,6 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
override val myInfo: NodeInfo get() = info
|
||||
override val database: CordaPersistence get() = this@AbstractNode.database
|
||||
override val configuration: NodeConfiguration get() = this@AbstractNode.configuration
|
||||
override val cordappProvider: CordappProvider = this@AbstractNode.cordappProvider
|
||||
|
||||
override fun <T : SerializeAsToken> cordaService(type: Class<T>): T {
|
||||
require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" }
|
||||
return cordappServices.getInstance(type) ?: throw IllegalArgumentException("Corda service ${type.name} does not exist")
|
||||
@ -817,9 +814,4 @@ abstract class AbstractNode(config: NodeConfiguration,
|
||||
|
||||
override fun jdbcSession(): Connection = database.createSession()
|
||||
}
|
||||
|
||||
fun registerCustomSchemas(schemas: Set<MappedSchema>) {
|
||||
database.hibernateConfig.schemaService.registerCustomSchemas(schemas)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ import kotlin.system.exitProcess
|
||||
*
|
||||
* @param configuration This is typically loaded from a TypeSafe HOCON configuration file.
|
||||
*/
|
||||
open class Node(override val configuration: FullNodeConfiguration,
|
||||
open class Node(configuration: FullNodeConfiguration,
|
||||
versionInfo: VersionInfo,
|
||||
val initialiseSerialization: Boolean = true,
|
||||
cordappLoader: CordappLoader = makeCordappLoader(configuration)
|
||||
@ -99,6 +99,7 @@ open class Node(override val configuration: FullNodeConfiguration,
|
||||
}
|
||||
|
||||
override val log: Logger get() = logger
|
||||
override val configuration get() = super.configuration as FullNodeConfiguration // Necessary to avoid init order NPE.
|
||||
override val networkMapAddress: NetworkMapAddress? get() = configuration.networkMapService?.address?.let(::NetworkMapAddress)
|
||||
override fun makeTransactionVerifierService() = (network as NodeMessagingClient).verifierService
|
||||
|
||||
|
@ -95,7 +95,7 @@ open class NodeStartup(val args: Array<String>) {
|
||||
return
|
||||
}
|
||||
val startedNode = node.start()
|
||||
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.internals.cordappProvider.cordapps.joinToString { it.name })
|
||||
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name })
|
||||
startedNode.internals.nodeReadyFuture.thenMatch({
|
||||
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
|
||||
val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation
|
||||
|
@ -38,10 +38,10 @@ import kotlin.streams.toList
|
||||
*
|
||||
* @property cordappJarPaths The classpath of cordapp JARs
|
||||
*/
|
||||
class CordappLoader private constructor(private val cordappJarPaths: List<URL>) {
|
||||
class CordappLoader private constructor(private val cordappJarPaths: List<RestrictedURL>) {
|
||||
val cordapps: List<Cordapp> by lazy { loadCordapps() + coreCordapp }
|
||||
|
||||
internal val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.toTypedArray(), javaClass.classLoader)
|
||||
internal val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader)
|
||||
|
||||
init {
|
||||
if (cordappJarPaths.isEmpty()) {
|
||||
@ -97,20 +97,22 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
|
||||
* @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun createDevMode(scanJars: List<URL>) = CordappLoader(scanJars)
|
||||
fun createDevMode(scanJars: List<URL>) = CordappLoader(scanJars.map { RestrictedURL(it, null) })
|
||||
|
||||
private fun getCordappsPath(baseDir: Path): Path = baseDir / CORDAPPS_DIR_NAME
|
||||
|
||||
private fun createScanPackage(scanPackage: String): List<URL> {
|
||||
private fun createScanPackage(scanPackage: String): List<RestrictedURL> {
|
||||
val resource = scanPackage.replace('.', '/')
|
||||
return this::class.java.classLoader.getResources(resource)
|
||||
.asSequence()
|
||||
.map { path ->
|
||||
if (path.protocol == "jar") {
|
||||
(path.openConnection() as JarURLConnection).jarFileURL.toURI()
|
||||
// When running tests from gradle this may be a corda module jar, so restrict to scanPackage:
|
||||
RestrictedURL((path.openConnection() as JarURLConnection).jarFileURL, scanPackage)
|
||||
} else {
|
||||
createDevCordappJar(scanPackage, path, resource)
|
||||
}.toURL()
|
||||
// No need to restrict as createDevCordappJar has already done that:
|
||||
RestrictedURL(createDevCordappJar(scanPackage, path, resource).toURL(), null)
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
@ -143,12 +145,12 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
|
||||
return generatedCordapps[path]!!
|
||||
}
|
||||
|
||||
private fun getCordappsInDirectory(cordappsDir: Path): List<URL> {
|
||||
private fun getCordappsInDirectory(cordappsDir: Path): List<RestrictedURL> {
|
||||
return if (!cordappsDir.exists()) {
|
||||
emptyList<URL>()
|
||||
emptyList()
|
||||
} else {
|
||||
cordappsDir.list {
|
||||
it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.map { it.toUri().toURL() }.toList()
|
||||
it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.map { RestrictedURL(it.toUri().toURL(), null) }.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,15 +189,15 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
|
||||
findServices(scanResult),
|
||||
findPlugins(it),
|
||||
findCustomSchemas(scanResult),
|
||||
it)
|
||||
it.url)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findServices(scanResult: ScanResult): List<Class<out SerializeAsToken>> {
|
||||
private fun findServices(scanResult: RestrictedScanResult): List<Class<out SerializeAsToken>> {
|
||||
return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class)
|
||||
}
|
||||
|
||||
private fun findInitiatedFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> {
|
||||
private fun findInitiatedFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
|
||||
return scanResult.getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class)
|
||||
// First group by the initiating flow class in case there are multiple mappings
|
||||
.groupBy { it.requireAnnotation<InitiatedBy>().value.java }
|
||||
@ -214,35 +216,35 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
|
||||
return Modifier.isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || Modifier.isStatic(modifiers))
|
||||
}
|
||||
|
||||
private fun findRPCFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> {
|
||||
private fun findRPCFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
|
||||
return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class).filter { it.isUserInvokable() }
|
||||
}
|
||||
|
||||
private fun findServiceFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> {
|
||||
private fun findServiceFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
|
||||
return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByService::class)
|
||||
}
|
||||
|
||||
private fun findSchedulableFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> {
|
||||
private fun findSchedulableFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
|
||||
return scanResult.getClassesWithAnnotation(FlowLogic::class, SchedulableFlow::class)
|
||||
}
|
||||
|
||||
private fun findContractClassNames(scanResult: ScanResult): List<String> {
|
||||
return (scanResult.getNamesOfClassesImplementing(Contract::class.java) + scanResult.getNamesOfClassesImplementing(UpgradedContract::class.java)).distinct()
|
||||
private fun findContractClassNames(scanResult: RestrictedScanResult): List<String> {
|
||||
return (scanResult.getNamesOfClassesImplementing(Contract::class) + scanResult.getNamesOfClassesImplementing(UpgradedContract::class)).distinct()
|
||||
}
|
||||
|
||||
private fun findPlugins(cordappJarPath: URL): List<SerializationWhitelist> {
|
||||
return ServiceLoader.load(SerializationWhitelist::class.java, URLClassLoader(arrayOf(cordappJarPath), appClassLoader)).toList().filter {
|
||||
cordappJarPath == it.javaClass.protectionDomain.codeSource.location
|
||||
private fun findPlugins(cordappJarPath: RestrictedURL): List<SerializationWhitelist> {
|
||||
return ServiceLoader.load(SerializationWhitelist::class.java, URLClassLoader(arrayOf(cordappJarPath.url), appClassLoader)).toList().filter {
|
||||
it.javaClass.protectionDomain.codeSource.location == cordappJarPath.url && it.javaClass.name.startsWith(cordappJarPath.qualifiedNamePrefix)
|
||||
} + DefaultWhitelist // Always add the DefaultWhitelist to the whitelist for an app.
|
||||
}
|
||||
|
||||
private fun findCustomSchemas(scanResult: ScanResult): Set<MappedSchema> {
|
||||
private fun findCustomSchemas(scanResult: RestrictedScanResult): Set<MappedSchema> {
|
||||
return scanResult.getClassesWithSuperclass(MappedSchema::class).toSet()
|
||||
}
|
||||
|
||||
private fun scanCordapp(cordappJarPath: URL): ScanResult {
|
||||
private fun scanCordapp(cordappJarPath: RestrictedURL): RestrictedScanResult {
|
||||
logger.info("Scanning CorDapp in $cordappJarPath")
|
||||
return FastClasspathScanner().addClassLoader(appClassLoader).overrideClasspath(cordappJarPath).scan()
|
||||
return RestrictedScanResult(FastClasspathScanner().addClassLoader(appClassLoader).overrideClasspath(cordappJarPath.url).scan(), cordappJarPath.qualifiedNamePrefix)
|
||||
}
|
||||
|
||||
private class FlowTypeHierarchyComparator(val initiatingFlow: Class<out FlowLogic<*>>) : Comparator<Class<out FlowLogic<*>>> {
|
||||
@ -269,16 +271,30 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Any> ScanResult.getClassesWithSuperclass(type: KClass<T>): List<T> {
|
||||
return getNamesOfSubclassesOf(type.java)
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
.map { it.kotlin.objectOrNewInstance() }
|
||||
/** @param rootPackageName only this package and subpackages may be extracted from [url], or null to allow all packages. */
|
||||
private class RestrictedURL(val url: URL, rootPackageName: String?) {
|
||||
val qualifiedNamePrefix = rootPackageName?.let { it + '.' } ?: ""
|
||||
}
|
||||
|
||||
private fun <T : Any> ScanResult.getClassesWithAnnotation(type: KClass<T>, annotation: KClass<out Annotation>): List<Class<out T>> {
|
||||
return getNamesOfClassesWithAnnotation(annotation.java)
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String) {
|
||||
fun getNamesOfClassesImplementing(type: KClass<*>): List<String> {
|
||||
return scanResult.getNamesOfClassesImplementing(type.java)
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
}
|
||||
|
||||
fun <T : Any> getClassesWithSuperclass(type: KClass<T>): List<T> {
|
||||
return scanResult.getNamesOfSubclassesOf(type.java)
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
.map { it.kotlin.objectOrNewInstance() }
|
||||
}
|
||||
|
||||
fun <T : Any> getClassesWithAnnotation(type: KClass<T>, annotation: KClass<out Annotation>): List<Class<out T>> {
|
||||
return scanResult.getNamesOfClassesWithAnnotation(annotation.java)
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,14 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.cordapp.CordappContext
|
||||
import net.corda.core.cordapp.CordappProvider
|
||||
import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import java.net.URLClassLoader
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Cordapp provider and store. For querying CorDapps for their attachment and vice versa.
|
||||
*/
|
||||
open class CordappProviderImpl(private val cordappLoader: CordappLoader) : SingletonSerializeAsToken(), CordappProvider {
|
||||
open class CordappProviderImpl(private val cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage) : SingletonSerializeAsToken(), CordappProviderInternal {
|
||||
override fun getAppContext(): CordappContext {
|
||||
// TODO: Use better supported APIs in Java 9
|
||||
Exception().stackTrace.forEach { stackFrame ->
|
||||
@ -34,28 +33,19 @@ open class CordappProviderImpl(private val cordappLoader: CordappLoader) : Singl
|
||||
/**
|
||||
* Current known CorDapps loaded on this node
|
||||
*/
|
||||
val cordapps get() = cordappLoader.cordapps
|
||||
private lateinit var cordappAttachments: HashBiMap<SecureHash, Cordapp>
|
||||
|
||||
/**
|
||||
* Should only be called once from the initialisation routine of the node or tests
|
||||
*/
|
||||
fun start(attachmentStorage: AttachmentStorage): CordappProviderImpl {
|
||||
cordappAttachments = HashBiMap.create(loadContractsIntoAttachmentStore(attachmentStorage))
|
||||
return this
|
||||
}
|
||||
|
||||
override val cordapps get() = cordappLoader.cordapps
|
||||
private val cordappAttachments = HashBiMap.create(loadContractsIntoAttachmentStore(attachmentStorage))
|
||||
/**
|
||||
* Gets the attachment ID of this CorDapp. Only CorDapps with contracts have an attachment ID
|
||||
*
|
||||
* @param cordapp The cordapp to get the attachment ID
|
||||
* @return An attachment ID if it exists, otherwise nothing
|
||||
*/
|
||||
fun getCordappAttachmentId(cordapp: Cordapp): SecureHash? = cordappAttachments.inverse().get(cordapp)
|
||||
fun getCordappAttachmentId(cordapp: Cordapp): SecureHash? = cordappAttachments.inverse().get(cordapp.jarPath)
|
||||
|
||||
private fun loadContractsIntoAttachmentStore(attachmentStorage: AttachmentStorage): Map<SecureHash, Cordapp> {
|
||||
val cordappsWithAttachments = cordapps.filter { !it.contractClassNames.isEmpty() }
|
||||
val attachmentIds = cordappsWithAttachments.map { it.jarPath.openStream().use { attachmentStorage.importAttachment(it) } }
|
||||
private fun loadContractsIntoAttachmentStore(attachmentStorage: AttachmentStorage): Map<SecureHash, URL> {
|
||||
val cordappsWithAttachments = cordapps.filter { !it.contractClassNames.isEmpty() }.map { it.jarPath }
|
||||
val attachmentIds = cordappsWithAttachments.map { it.openStream().use { attachmentStorage.importAttachment(it) } }
|
||||
return attachmentIds.zip(cordappsWithAttachments).toMap()
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
package net.corda.node.internal.cordapp
|
||||
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.cordapp.CordappProvider
|
||||
|
||||
interface CordappProviderInternal : CordappProvider {
|
||||
val cordapps: List<Cordapp>
|
||||
}
|
@ -30,11 +30,5 @@ interface SchemaService {
|
||||
* or via custom logic in this service.
|
||||
*/
|
||||
fun generateMappedObject(state: ContractState, schema: MappedSchema): PersistentState
|
||||
|
||||
/**
|
||||
* Registration mechanism to add custom contract schemas that extend the [MappedSchema] class.
|
||||
*/
|
||||
fun registerCustomSchemas(customSchemas: Set<MappedSchema>)
|
||||
|
||||
}
|
||||
//DOCEND SchemaService
|
||||
|
@ -21,6 +21,7 @@ import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.internal.InitiatedFlowFactory
|
||||
import net.corda.node.internal.cordapp.CordappProviderInternal
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.messaging.MessagingService
|
||||
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
|
||||
@ -89,7 +90,7 @@ interface ServiceHubInternal : ServiceHub {
|
||||
val networkService: MessagingService
|
||||
val database: CordaPersistence
|
||||
val configuration: NodeConfiguration
|
||||
|
||||
override val cordappProvider: CordappProviderInternal
|
||||
override fun recordTransactions(notifyVault: Boolean, txs: Iterable<SignedTransaction>) {
|
||||
require(txs.any()) { "No transactions passed in for recording" }
|
||||
val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) }
|
||||
|
@ -33,25 +33,13 @@ class HibernateConfiguration(val schemaService: SchemaService, private val datab
|
||||
private val sessionFactories = ConcurrentHashMap<Set<MappedSchema>, SessionFactory>()
|
||||
|
||||
private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?: "")
|
||||
|
||||
init {
|
||||
logger.info("Init HibernateConfiguration for schemas: ${schemaService.schemaOptions.keys}")
|
||||
sessionFactoryForRegisteredSchemas()
|
||||
val sessionFactoryForRegisteredSchemas = schemaService.schemaOptions.keys.let {
|
||||
logger.info("Init HibernateConfiguration for schemas: $it")
|
||||
sessionFactoryForSchemas(it)
|
||||
}
|
||||
|
||||
fun sessionFactoryForRegisteredSchemas(): SessionFactory {
|
||||
return sessionFactoryForSchemas(*schemaService.schemaOptions.keys.toTypedArray())
|
||||
}
|
||||
|
||||
fun sessionFactoryForSchema(schema: MappedSchema): SessionFactory {
|
||||
return sessionFactoryForSchemas(schema)
|
||||
}
|
||||
|
||||
//vararg to set conversions left to preserve method signature for now
|
||||
fun sessionFactoryForSchemas(vararg schemas: MappedSchema): SessionFactory {
|
||||
val schemaSet: Set<MappedSchema> = schemas.toSet()
|
||||
return sessionFactories.computeIfAbsent(schemaSet, { makeSessionFactoryForSchemas(schemaSet) })
|
||||
}
|
||||
/** @param key must be immutable, not just read-only. */
|
||||
fun sessionFactoryForSchemas(key: Set<MappedSchema>) = sessionFactories.computeIfAbsent(key, { makeSessionFactoryForSchemas(key) })
|
||||
|
||||
private fun makeSessionFactoryForSchemas(schemas: Set<MappedSchema>): SessionFactory {
|
||||
logger.info("Creating session factory for schemas: $schemas")
|
||||
|
@ -38,7 +38,7 @@ class HibernateObserver(vaultUpdates: Observable<Vault.Update<ContractState>>, v
|
||||
}
|
||||
|
||||
fun persistStateWithSchema(state: ContractState, stateRef: StateRef, schema: MappedSchema) {
|
||||
val sessionFactory = config.sessionFactoryForSchema(schema)
|
||||
val sessionFactory = config.sessionFactoryForSchemas(setOf(schema))
|
||||
val session = sessionFactory.withOptions().
|
||||
connection(DatabaseTransactionManager.current().connection).
|
||||
flushMode(FlushMode.MANUAL).
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.schemas.NodeInfoSchemaV1
|
||||
import net.corda.core.schemas.PersistentState
|
||||
import net.corda.core.schemas.QueryableState
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.node.internal.cordapp.CordappLoader
|
||||
import net.corda.node.services.api.SchemaService
|
||||
import net.corda.node.services.events.NodeSchedulerService
|
||||
import net.corda.node.services.identity.PersistentIdentityService
|
||||
@ -27,13 +28,13 @@ import net.corda.node.services.vault.VaultSchemaV1
|
||||
|
||||
/**
|
||||
* Most basic implementation of [SchemaService].
|
||||
*
|
||||
* @param cordappLoader if not null, custom schemas will be extracted from its cordapps.
|
||||
* TODO: support loading schema options from node configuration.
|
||||
* TODO: support configuring what schemas are to be selected for persistence.
|
||||
* TODO: support plugins for schema version upgrading or custom mapping not supported by original [QueryableState].
|
||||
* TODO: create whitelisted tables when a CorDapp is first installed
|
||||
*/
|
||||
class NodeSchemaService(customSchemas: Set<MappedSchema> = emptySet()) : SchemaService, SingletonSerializeAsToken() {
|
||||
class NodeSchemaService(cordappLoader: CordappLoader?) : SchemaService, SingletonSerializeAsToken() {
|
||||
|
||||
// Entities for compulsory services
|
||||
object NodeServices
|
||||
@ -67,9 +68,12 @@ class NodeSchemaService(customSchemas: Set<MappedSchema> = emptySet()) : SchemaS
|
||||
Pair(NodeInfoSchemaV1, SchemaService.SchemaOptions()),
|
||||
Pair(NodeServicesV1, SchemaService.SchemaOptions()))
|
||||
|
||||
override var schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = requiredSchemas.plus(customSchemas.map { mappedSchema ->
|
||||
Pair(mappedSchema, SchemaService.SchemaOptions())
|
||||
})
|
||||
override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = if (cordappLoader == null) {
|
||||
requiredSchemas
|
||||
} else {
|
||||
val customSchemas = cordappLoader.cordapps.flatMap { it.customSchemas }.toSet()
|
||||
requiredSchemas.plus(customSchemas.map { mappedSchema -> Pair(mappedSchema, SchemaService.SchemaOptions()) })
|
||||
}
|
||||
|
||||
// Currently returns all schemas supported by the state, with no filtering or enrichment.
|
||||
override fun selectSchemas(state: ContractState): Iterable<MappedSchema> {
|
||||
@ -92,10 +96,4 @@ class NodeSchemaService(customSchemas: Set<MappedSchema> = emptySet()) : SchemaS
|
||||
return VaultSchemaV1.VaultFungibleStates(state.owner, state.amount.quantity, state.amount.token.issuer.party, state.amount.token.issuer.reference, state.participants)
|
||||
return (state as QueryableState).generateMappedObject(schema)
|
||||
}
|
||||
|
||||
override fun registerCustomSchemas(_customSchemas: Set<MappedSchema>) {
|
||||
schemaOptions = schemaOptions.plus(_customSchemas.map { mappedSchema ->
|
||||
Pair(mappedSchema, SchemaService.SchemaOptions())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ private fun CriteriaBuilder.executeUpdate(session: Session, configure: Root<*>.(
|
||||
* TODO: keep an audit trail with time stamps of previously unconsumed states "as of" a particular point in time.
|
||||
* TODO: have transaction storage do some caching.
|
||||
*/
|
||||
class NodeVaultService(private val clock: Clock, private val keyManagementService: KeyManagementService, private val stateLoader: StateLoader, private val hibernateConfig: HibernateConfiguration) : SingletonSerializeAsToken(), VaultServiceInternal {
|
||||
class NodeVaultService(private val clock: Clock, private val keyManagementService: KeyManagementService, private val stateLoader: StateLoader, hibernateConfig: HibernateConfiguration) : SingletonSerializeAsToken(), VaultServiceInternal {
|
||||
|
||||
private companion object {
|
||||
val log = loggerFor<NodeVaultService>()
|
||||
@ -377,9 +377,8 @@ class NodeVaultService(private val clock: Clock, private val keyManagementServic
|
||||
return keysToCheck.any { it in myKeys }
|
||||
}
|
||||
|
||||
private var sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas()
|
||||
private var criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
|
||||
private val sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas
|
||||
private val criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
/**
|
||||
* Maintain a list of contract state interfaces to concrete types stored in the vault
|
||||
* for usage in generic queries of type queryBy<LinearState> or queryBy<FungibleState<*>>
|
||||
@ -406,11 +405,6 @@ class NodeVaultService(private val clock: Clock, private val keyManagementServic
|
||||
@Throws(VaultQueryException::class)
|
||||
override fun <T : ContractState> _queryBy(criteria: QueryCriteria, paging: PageSpecification, sorting: Sort, contractStateType: Class<out T>): Vault.Page<T> {
|
||||
log.info("Vault Query for contract type: $contractStateType, criteria: $criteria, pagination: $paging, sorting: $sorting")
|
||||
|
||||
// refresh to include any schemas registered after initial VQ service initialisation
|
||||
sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas()
|
||||
criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
|
||||
// calculate total results where a page specification has been defined
|
||||
var totalStates = -1L
|
||||
if (!paging.isDefault) {
|
||||
|
@ -6,8 +6,6 @@ import net.corda.core.node.services.IdentityService
|
||||
import net.corda.node.services.api.SchemaService
|
||||
import net.corda.node.services.persistence.HibernateConfiguration
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import org.hibernate.SessionFactory
|
||||
|
||||
import rx.Observable
|
||||
import rx.Subscriber
|
||||
import rx.subjects.UnicastSubject
|
||||
@ -32,12 +30,7 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi
|
||||
HibernateConfiguration(schemaService, databaseProperties, createIdentityService)
|
||||
}
|
||||
}
|
||||
|
||||
val entityManagerFactory: SessionFactory by lazy {
|
||||
transaction {
|
||||
hibernateConfig.sessionFactoryForRegisteredSchemas()
|
||||
}
|
||||
}
|
||||
val entityManagerFactory get() = hibernateConfig.sessionFactoryForRegisteredSchemas
|
||||
|
||||
companion object {
|
||||
fun connect(dataSource: HikariDataSource, schemaService: SchemaService, createIdentityService: () -> IdentityService, databaseProperties: Properties): CordaPersistence {
|
||||
@ -103,7 +96,7 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi
|
||||
}
|
||||
}
|
||||
|
||||
fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, schemaService: SchemaService = NodeSchemaService(), createIdentityService: () -> IdentityService): CordaPersistence {
|
||||
fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, createIdentityService: () -> IdentityService, schemaService: SchemaService = NodeSchemaService(null)): CordaPersistence {
|
||||
val config = HikariConfig(dataSourceProperties)
|
||||
val dataSource = HikariDataSource(config)
|
||||
val persistence = CordaPersistence.connect(dataSource, schemaService, createIdentityService, databaseProperties ?: Properties())
|
||||
|
@ -8,7 +8,6 @@ import net.corda.core.messaging.*;
|
||||
import net.corda.core.node.services.*;
|
||||
import net.corda.core.node.services.vault.*;
|
||||
import net.corda.core.node.services.vault.QueryCriteria.*;
|
||||
import net.corda.core.schemas.*;
|
||||
import net.corda.core.utilities.*;
|
||||
import net.corda.finance.contracts.*;
|
||||
import net.corda.finance.contracts.asset.*;
|
||||
@ -43,14 +42,13 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
List<String> cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset");
|
||||
List<String> cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1.class.getPackage().getName());
|
||||
ArrayList<KeyPair> keys = new ArrayList<>();
|
||||
keys.add(getMEGA_CORP_KEY());
|
||||
keys.add(getDUMMY_NOTARY_KEY());
|
||||
Set<MappedSchema> requiredSchemas = Collections.singleton(CashSchemaV1.INSTANCE);
|
||||
IdentityService identitySvc = makeTestIdentityService();
|
||||
@SuppressWarnings("unchecked")
|
||||
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(requiredSchemas, keys, () -> identitySvc, cordappPackages);
|
||||
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(keys, () -> identitySvc, cordappPackages);
|
||||
issuerServices = new MockServices(cordappPackages, getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY());
|
||||
database = databaseAndServices.getFirst();
|
||||
services = databaseAndServices.getSecond();
|
||||
|
@ -26,7 +26,7 @@ import kotlin.test.assertEquals
|
||||
class InteractiveShellTest {
|
||||
@Before
|
||||
fun setup() {
|
||||
InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService)
|
||||
InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.node.internal.cordapp
|
||||
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.testing.node.MockAttachmentStorage
|
||||
import org.junit.Assert
|
||||
@ -22,9 +23,7 @@ class CordappProviderImplTests {
|
||||
@Test
|
||||
fun `isolated jar is loaded into the attachment store`() {
|
||||
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
||||
val provider = CordappProviderImpl(loader)
|
||||
|
||||
provider.start(attachmentStore)
|
||||
val provider = CordappProviderImpl(loader, attachmentStore)
|
||||
val maybeAttachmentId = provider.getCordappAttachmentId(provider.cordapps.first())
|
||||
|
||||
Assert.assertNotNull(maybeAttachmentId)
|
||||
@ -34,17 +33,14 @@ class CordappProviderImplTests {
|
||||
@Test
|
||||
fun `empty jar is not loaded into the attachment store`() {
|
||||
val loader = CordappLoader.createDevMode(listOf(emptyJAR))
|
||||
val provider = CordappProviderImpl(loader)
|
||||
|
||||
provider.start(attachmentStore)
|
||||
|
||||
val provider = CordappProviderImpl(loader, attachmentStore)
|
||||
Assert.assertNull(provider.getCordappAttachmentId(provider.cordapps.first()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test that we find a cordapp class that is loaded into the store`() {
|
||||
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
||||
val provider = CordappProviderImpl(loader)
|
||||
val provider = CordappProviderImpl(loader, mock())
|
||||
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
||||
|
||||
val expected = provider.cordapps.first()
|
||||
@ -57,10 +53,8 @@ class CordappProviderImplTests {
|
||||
@Test
|
||||
fun `test that we find an attachment for a cordapp contrat class`() {
|
||||
val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
|
||||
val provider = CordappProviderImpl(loader)
|
||||
val provider = CordappProviderImpl(loader, attachmentStore)
|
||||
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
||||
|
||||
provider.start(attachmentStore)
|
||||
val expected = provider.getAppContext(provider.cordapps.first()).attachmentId
|
||||
val actual = provider.getContractAttachmentID(className)
|
||||
|
||||
|
@ -78,7 +78,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
calls = 0
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
val databaseProperties = makeTestDatabaseProperties()
|
||||
database = configureDatabase(dataSourceProps, databaseProperties, createIdentityService = ::makeTestIdentityService)
|
||||
database = configureDatabase(dataSourceProps, databaseProperties, ::makeTestIdentityService)
|
||||
val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val kms = MockKeyManagementService(identityService, ALICE_KEY)
|
||||
|
||||
@ -97,7 +97,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
network = mockMessagingService), TestReference {
|
||||
override val vaultService: VaultServiceInternal = NodeVaultService(testClock, kms, stateLoader, database.hibernateConfig)
|
||||
override val testReference = this@NodeSchedulerServiceTest
|
||||
override val cordappProvider = CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.testing.contracts"))).start(attachments)
|
||||
override val cordappProvider = CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.testing.contracts")), attachments)
|
||||
}
|
||||
smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1)
|
||||
scheduler = NodeSchedulerService(services, schedulerGatedExecutor, serverThread = smmExecutor)
|
||||
|
@ -71,7 +71,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() {
|
||||
baseDirectory = baseDirectory,
|
||||
myLegalName = ALICE.name)
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
networkMapRegistrationFuture = doneFuture(Unit)
|
||||
networkMapCache = PersistentNetworkMapCache(serviceHub = object : MockServiceHubInternal(database, config) {})
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class DBCheckpointStorageTests : TestDependencyInjectionBase() {
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
newCheckpointStorage()
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class DBTransactionStorageTests : TestDependencyInjectionBase() {
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), NodeSchemaService(), ::makeTestIdentityService)
|
||||
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
database.transaction {
|
||||
|
||||
services = object : MockServices(BOB_KEY) {
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.utilities.toBase58String
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.VaultService
|
||||
import net.corda.core.schemas.CommonSchemaV1
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.schemas.PersistentStateRef
|
||||
import net.corda.core.serialization.SerializationDefaults
|
||||
import net.corda.core.serialization.deserialize
|
||||
@ -25,7 +26,6 @@ import net.corda.finance.schemas.SampleCashSchemaV2
|
||||
import net.corda.finance.schemas.SampleCashSchemaV3
|
||||
import net.corda.finance.utils.sumCash
|
||||
import net.corda.node.services.schema.HibernateObserver
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.node.services.vault.VaultSchemaV1
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
@ -77,7 +77,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
|
||||
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY)
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
val defaultDatabaseProperties = makeTestDatabaseProperties()
|
||||
database = configureDatabase(dataSourceProps, defaultDatabaseProperties, NodeSchemaService(), ::makeTestIdentityService)
|
||||
database = configureDatabase(dataSourceProps, defaultDatabaseProperties, ::makeTestIdentityService)
|
||||
database.transaction {
|
||||
hibernateConfig = database.hibernateConfig
|
||||
services = object : MockServices(cordappPackages, BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) {
|
||||
@ -95,13 +95,13 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
|
||||
hibernatePersister = services.hibernatePersister
|
||||
}
|
||||
setUpDb()
|
||||
|
||||
val customSchemas = setOf(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3)
|
||||
sessionFactory = hibernateConfig.sessionFactoryForSchemas(*customSchemas.toTypedArray())
|
||||
sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3)
|
||||
entityManager = sessionFactory.createEntityManager()
|
||||
criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
}
|
||||
|
||||
private fun sessionFactoryForSchemas(vararg schemas: MappedSchema) = hibernateConfig.sessionFactoryForSchemas(schemas.toSet())
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
database.close()
|
||||
@ -536,8 +536,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
|
||||
services.fillWithSomeTestDeals(listOf("123", "456", "789"))
|
||||
services.fillWithSomeTestLinearStates(2)
|
||||
}
|
||||
|
||||
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
|
||||
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
|
||||
val criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
val entityManager = sessionFactory.createEntityManager()
|
||||
|
||||
@ -568,8 +567,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
|
||||
services.fillWithSomeTestDeals(listOf("123", "456", "789"))
|
||||
services.fillWithSomeTestLinearStates(2)
|
||||
}
|
||||
|
||||
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
|
||||
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
|
||||
val criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
val entityManager = sessionFactory.createEntityManager()
|
||||
|
||||
@ -635,8 +633,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
|
||||
hibernatePersister.persistStateWithSchema(dummyFungibleState, it.ref, SampleCashSchemaV3)
|
||||
}
|
||||
}
|
||||
|
||||
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, CommonSchemaV1, SampleCashSchemaV3)
|
||||
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, CommonSchemaV1, SampleCashSchemaV3)
|
||||
val criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
val entityManager = sessionFactory.createEntityManager()
|
||||
|
||||
@ -764,8 +761,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
|
||||
services.fillWithSomeTestLinearStates(2, externalId = "222")
|
||||
services.fillWithSomeTestLinearStates(3, externalId = "333")
|
||||
}
|
||||
|
||||
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
|
||||
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
|
||||
val criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
val entityManager = sessionFactory.createEntityManager()
|
||||
|
||||
@ -817,8 +813,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
|
||||
services.fillWithSomeTestLinearStates(2, externalId = "222")
|
||||
services.fillWithSomeTestLinearStates(3, externalId = "333")
|
||||
}
|
||||
|
||||
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
|
||||
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
|
||||
val criteriaBuilder = sessionFactory.criteriaBuilder
|
||||
val entityManager = sessionFactory.createEntityManager()
|
||||
|
||||
|
@ -40,7 +40,7 @@ class NodeAttachmentStorageTest {
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
|
||||
val dataSourceProperties = makeTestDataSourceProperties()
|
||||
database = configureDatabase(dataSourceProperties, makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService)
|
||||
database = configureDatabase(dataSourceProperties, makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
fs = Jimfs.newFileSystem(Configuration.unix())
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,6 @@ class HibernateObserverTests {
|
||||
val testSchema = TestSchema
|
||||
val rawUpdatesPublisher = PublishSubject.create<Vault.Update<ContractState>>()
|
||||
val schemaService = object : SchemaService {
|
||||
override fun registerCustomSchemas(customSchemas: Set<MappedSchema>) {}
|
||||
|
||||
override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = emptyMap()
|
||||
|
||||
override fun selectSchemas(state: ContractState): Iterable<MappedSchema> = setOf(testSchema)
|
||||
@ -70,7 +68,7 @@ class HibernateObserverTests {
|
||||
return parent
|
||||
}
|
||||
}
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), schemaService, createIdentityService = ::makeTestIdentityService)
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService, schemaService)
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig)
|
||||
database.transaction {
|
||||
|
@ -3,11 +3,13 @@ package net.corda.node.services.schema
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.schemas.PersistentState
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.services.api.ServiceHubInternal
|
||||
import net.corda.testing.driver.NodeHandle
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.schemas.DummyLinearStateSchemaV1
|
||||
@ -15,6 +17,7 @@ import org.hibernate.annotations.Cascade
|
||||
import org.hibernate.annotations.CascadeType
|
||||
import org.junit.Test
|
||||
import javax.persistence.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class NodeSchemaServiceTest {
|
||||
@ -23,11 +26,9 @@ class NodeSchemaServiceTest {
|
||||
*/
|
||||
@Test
|
||||
fun `registering custom schemas for testing with MockNode`() {
|
||||
val mockNet = MockNetwork()
|
||||
val mockNet = MockNetwork(cordappPackages = listOf(DummyLinearStateSchemaV1::class.packageName))
|
||||
val mockNode = mockNet.createNode()
|
||||
mockNet.runNetwork()
|
||||
|
||||
mockNode.internals.registerCustomSchemas(setOf(DummyLinearStateSchemaV1))
|
||||
val schemaService = mockNode.services.schemaService
|
||||
assertTrue(schemaService.schemaOptions.containsKey(DummyLinearStateSchemaV1))
|
||||
|
||||
@ -50,6 +51,16 @@ class NodeSchemaServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom schemas are loaded eagerly`() {
|
||||
val expected = setOf("PARENTS", "CHILDREN")
|
||||
assertEquals<Set<*>>(expected, driver {
|
||||
(startNode(startInSameProcess = true).getOrThrow() as NodeHandle.InProcess).node.database.transaction {
|
||||
session.createNativeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES").list()
|
||||
}
|
||||
}.toMutableSet().apply { retainAll(expected) })
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class MappedSchemasFlow : FlowLogic<List<String>>() {
|
||||
@Suspendable
|
||||
|
@ -86,7 +86,7 @@ class DistributedImmutableMapTests : TestDependencyInjectionBase() {
|
||||
private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture<Member> {
|
||||
val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build()
|
||||
val address = Address(myAddress.host, myAddress.port)
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties("serverNameTablePrefix", "PORT_${myAddress.port}_"), createIdentityService = ::makeTestIdentityService)
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties("serverNameTablePrefix", "PORT_${myAddress.port}_"), ::makeTestIdentityService)
|
||||
databases.add(database)
|
||||
val stateMachineFactory = { DistributedImmutableMap(database, RaftUniquenessProvider.Companion::createMap) }
|
||||
|
||||
|
@ -23,7 +23,7 @@ class PersistentUniquenessProviderTests : TestDependencyInjectionBase() {
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
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.QueryCriteria
|
||||
import net.corda.core.node.services.vault.QueryCriteria.*
|
||||
@ -46,7 +47,7 @@ import kotlin.test.assertTrue
|
||||
|
||||
class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
companion object {
|
||||
private val cordappPackages = listOf("net.corda.finance.contracts.asset")
|
||||
private val cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName)
|
||||
}
|
||||
|
||||
lateinit var services: MockServices
|
||||
@ -58,7 +59,6 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(NodeVaultService::class)
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(BOC_KEY, DUMMY_CASH_ISSUER_KEY),
|
||||
customSchemas = setOf(CashSchemaV1),
|
||||
cordappPackages = cordappPackages)
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.entropyToKeyPair
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.node.services.vault.*
|
||||
import net.corda.core.node.services.vault.QueryCriteria.*
|
||||
@ -45,10 +46,9 @@ import java.time.temporal.ChronoUnit
|
||||
import java.util.*
|
||||
|
||||
class VaultQueryTests : TestDependencyInjectionBase() {
|
||||
companion object {
|
||||
private val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts")
|
||||
}
|
||||
|
||||
private val cordappPackages = setOf(
|
||||
"net.corda.testing.contracts", "net.corda.finance.contracts",
|
||||
CashSchemaV1::class.packageName, CommercialPaperSchemaV1::class.packageName, DummyLinearStateSchemaV1::class.packageName).toMutableList()
|
||||
private lateinit var services: MockServices
|
||||
private lateinit var notaryServices: MockServices
|
||||
private val vaultService: VaultService get() = services.vaultService
|
||||
@ -67,7 +67,6 @@ class VaultQueryTests : TestDependencyInjectionBase() {
|
||||
identitySvc.verifyAndRegisterIdentity(BOC_IDENTITY)
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY),
|
||||
createIdentityService = { identitySvc },
|
||||
customSchemas = setOf(CashSchemaV1, CommercialPaperSchemaV1, DummyLinearStateSchemaV1),
|
||||
cordappPackages = cordappPackages)
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
@ -85,8 +84,7 @@ class VaultQueryTests : TestDependencyInjectionBase() {
|
||||
@Ignore
|
||||
@Test
|
||||
fun createPersistentTestDb() {
|
||||
val database = configureDatabase(makePersistentDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = { identitySvc })
|
||||
|
||||
val database = configureDatabase(makePersistentDataSourceProperties(), makeTestDatabaseProperties(), { identitySvc })
|
||||
setUpDb(database, 5000)
|
||||
|
||||
database.close()
|
||||
@ -1753,6 +1751,9 @@ class VaultQueryTests : TestDependencyInjectionBase() {
|
||||
|
||||
@Test
|
||||
fun `query attempting to use unregistered schema`() {
|
||||
tearDown()
|
||||
cordappPackages -= SampleCashSchemaV3::class.packageName
|
||||
setUp()
|
||||
database.transaction {
|
||||
services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L))
|
||||
services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L))
|
||||
|
@ -4,6 +4,7 @@ import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.LinearState
|
||||
import net.corda.core.contracts.UniqueIdentifier
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.VaultService
|
||||
import net.corda.core.node.services.queryBy
|
||||
@ -35,7 +36,7 @@ import kotlin.test.assertEquals
|
||||
|
||||
class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
companion object {
|
||||
private val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset")
|
||||
private val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName)
|
||||
}
|
||||
|
||||
lateinit var services: MockServices
|
||||
@ -48,7 +49,6 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(VaultWithCashTest::class)
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(DUMMY_CASH_ISSUER_KEY, DUMMY_NOTARY_KEY),
|
||||
customSchemas = setOf(CashSchemaV1),
|
||||
cordappPackages = cordappPackages)
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
|
@ -21,7 +21,7 @@ class ObservablesTests {
|
||||
val toBeClosed = mutableListOf<Closeable>()
|
||||
|
||||
fun createDatabase(): CordaPersistence {
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService)
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
toBeClosed += database
|
||||
return database
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
|
||||
database.transaction {
|
||||
oracle = createMockCordaService(services, NodeInterestRates::Oracle)
|
||||
oracle.knownFixes = TEST_DATA
|
||||
|
@ -12,7 +12,6 @@ import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.statemachine.StateMachineManager
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.nodeapi.internal.ServiceType
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||
import net.corda.testing.node.MockNetwork
|
||||
@ -270,9 +269,3 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for verifying that a service info contains the given type of advertised service. For non-simulation cases
|
||||
* this is a configuration matter rather than implementation.
|
||||
*/
|
||||
fun Iterable<ServiceInfo>.containsType(type: ServiceType) = any { it.type == type }
|
@ -1,6 +1,7 @@
|
||||
package net.corda.traderdemo
|
||||
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.millis
|
||||
import net.corda.finance.DOLLARS
|
||||
@ -20,7 +21,9 @@ import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class TraderDemoTest : NodeBasedTest(listOf("net.corda.finance.contracts.asset", "net.corda.finance.contracts")) {
|
||||
class TraderDemoTest : NodeBasedTest(listOf(
|
||||
"net.corda.finance.contracts.asset", "net.corda.finance.contracts",
|
||||
CashSchemaV1::class.packageName, CommercialPaperSchemaV1::class.packageName)) {
|
||||
@Test
|
||||
fun `runs trader demo`() {
|
||||
val demoUser = User("demo", "demo", setOf(startFlowPermission<SellerFlow>()))
|
||||
@ -35,9 +38,6 @@ class TraderDemoTest : NodeBasedTest(listOf("net.corda.finance.contracts.asset",
|
||||
val (nodeA, nodeB, bankNode) = listOf(nodeAFuture, nodeBFuture, bankNodeFuture, notaryFuture).map { it.getOrThrow() }
|
||||
|
||||
nodeA.internals.registerInitiatedFlow(BuyerFlow::class.java)
|
||||
nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1))
|
||||
nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1, CommercialPaperSchemaV1))
|
||||
|
||||
val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map {
|
||||
val client = CordaRPCClient(it.internals.configuration.rpcAddress!!)
|
||||
client.start(demoUser.username, demoUser.password).proxy
|
||||
|
@ -1,7 +1,6 @@
|
||||
package net.corda.node.testing
|
||||
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import net.corda.core.cordapp.CordappProvider
|
||||
import net.corda.core.flows.FlowInitiator
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
@ -13,11 +12,11 @@ import net.corda.node.internal.InitiatedFlowFactory
|
||||
import net.corda.node.internal.StateLoaderImpl
|
||||
import net.corda.node.internal.cordapp.CordappLoader
|
||||
import net.corda.node.internal.cordapp.CordappProviderImpl
|
||||
import net.corda.node.internal.cordapp.CordappProviderInternal
|
||||
import net.corda.node.serialization.NodeClock
|
||||
import net.corda.node.services.api.*
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.messaging.MessagingService
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.node.services.statemachine.FlowStateMachineImpl
|
||||
import net.corda.node.services.statemachine.StateMachineManager
|
||||
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
|
||||
@ -46,10 +45,9 @@ open class MockServiceHubInternal(
|
||||
val mapCache: NetworkMapCacheInternal? = null,
|
||||
val scheduler: SchedulerService? = null,
|
||||
val overrideClock: Clock? = NodeClock(),
|
||||
val schemas: SchemaService? = NodeSchemaService(),
|
||||
val customContractUpgradeService: ContractUpgradeService? = null,
|
||||
val customTransactionVerifierService: TransactionVerifierService? = InMemoryTransactionVerifierService(2),
|
||||
override val cordappProvider: CordappProvider = CordappProviderImpl(CordappLoader.createDefault(Paths.get("."))).start(attachments),
|
||||
override val cordappProvider: CordappProviderInternal = CordappProviderImpl(CordappLoader.createDefault(Paths.get(".")), attachments),
|
||||
protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions)
|
||||
) : ServiceHubInternal, StateLoader by stateLoader {
|
||||
override val transactionVerifierService: TransactionVerifierService
|
||||
@ -75,8 +73,7 @@ open class MockServiceHubInternal(
|
||||
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
|
||||
override val rpcFlows: List<Class<out FlowLogic<*>>>
|
||||
get() = throw UnsupportedOperationException()
|
||||
override val schemaService: SchemaService
|
||||
get() = schemas ?: throw UnsupportedOperationException()
|
||||
override val schemaService get() = throw UnsupportedOperationException()
|
||||
override val auditService: AuditService = DummyAuditService()
|
||||
|
||||
lateinit var smm: StateMachineManager
|
||||
|
@ -14,7 +14,6 @@ import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.StateLoader
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -51,7 +50,7 @@ import java.util.*
|
||||
* building chains of transactions and verifying them. It isn't sufficient for testing flows however.
|
||||
*/
|
||||
open class MockServices(
|
||||
cordappPackages: List<String>,
|
||||
cordappLoader: CordappLoader,
|
||||
override val validatedTransactions: WritableTransactionStorage,
|
||||
protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions),
|
||||
vararg val keys: KeyPair
|
||||
@ -101,24 +100,22 @@ open class MockServices(
|
||||
|
||||
/**
|
||||
* Makes database and mock services appropriate for unit tests.
|
||||
*
|
||||
* @param customSchemas a set of schemas being used by [NodeSchemaService]
|
||||
* @param keys a lis of [KeyPair] instances to be used by [MockServices]. Defualts to [MEGA_CORP_KEY]
|
||||
* @param keys a list of [KeyPair] instances to be used by [MockServices]. Defualts to [MEGA_CORP_KEY]
|
||||
* @param createIdentityService a lambda function returning an instance of [IdentityService]. Defauts to [InMemoryIdentityService].
|
||||
*
|
||||
* @return a pair where the first element is the instance of [CordaPersistence] and the second is [MockServices].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun makeTestDatabaseAndMockServices(customSchemas: Set<MappedSchema> = emptySet(),
|
||||
keys: List<KeyPair> = listOf(MEGA_CORP_KEY),
|
||||
fun makeTestDatabaseAndMockServices(keys: List<KeyPair> = listOf(MEGA_CORP_KEY),
|
||||
createIdentityService: () -> IdentityService = { makeTestIdentityService() },
|
||||
cordappPackages: List<String> = emptyList()): Pair<CordaPersistence, MockServices> {
|
||||
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
val databaseProperties = makeTestDatabaseProperties()
|
||||
val identityServiceRef: IdentityService by lazy { createIdentityService() }
|
||||
val database = configureDatabase(dataSourceProps, databaseProperties, NodeSchemaService(customSchemas), { identityServiceRef })
|
||||
val database = configureDatabase(dataSourceProps, databaseProperties, { identityServiceRef }, NodeSchemaService(cordappLoader))
|
||||
val mockService = database.transaction {
|
||||
object : MockServices(cordappPackages, *(keys.toTypedArray())) {
|
||||
object : MockServices(cordappLoader, *(keys.toTypedArray())) {
|
||||
override val identityService: IdentityService = database.transaction { identityServiceRef }
|
||||
override val vaultService = makeVaultService(database.hibernateConfig)
|
||||
|
||||
@ -137,7 +134,8 @@ open class MockServices(
|
||||
}
|
||||
}
|
||||
|
||||
constructor(cordappPackages: List<String>, vararg keys: KeyPair) : this(cordappPackages, MockTransactionStorage(), keys = *keys)
|
||||
private constructor(cordappLoader: CordappLoader, vararg keys: KeyPair) : this(cordappLoader, MockTransactionStorage(), keys = *keys)
|
||||
constructor(cordappPackages: List<String>, vararg keys: KeyPair) : this(CordappLoader.createWithTestPackages(cordappPackages), keys = *keys)
|
||||
constructor(vararg keys: KeyPair) : this(emptyList(), *keys)
|
||||
constructor() : this(generateKeyPair())
|
||||
|
||||
@ -167,11 +165,11 @@ open class MockServices(
|
||||
return NodeInfo(emptyList(), listOf(identity), 1, serial = 1L)
|
||||
}
|
||||
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
|
||||
val mockCordappProvider = MockCordappProvider(CordappLoader.createWithTestPackages(cordappPackages)).start(attachments) as MockCordappProvider
|
||||
val mockCordappProvider = MockCordappProvider(cordappLoader, attachments)
|
||||
override val cordappProvider: CordappProvider get() = mockCordappProvider
|
||||
lateinit var hibernatePersister: HibernateObserver
|
||||
|
||||
fun makeVaultService(hibernateConfig: HibernateConfiguration = HibernateConfiguration(NodeSchemaService(), makeTestDatabaseProperties(), { identityService })): VaultServiceInternal {
|
||||
fun makeVaultService(hibernateConfig: HibernateConfiguration): VaultServiceInternal {
|
||||
val vaultService = NodeVaultService(Clock.systemUTC(), keyManagementService, stateLoader, hibernateConfig)
|
||||
hibernatePersister = HibernateObserver(vaultService.rawUpdates, hibernateConfig)
|
||||
return vaultService
|
||||
|
@ -37,7 +37,7 @@ class SimpleNode(val config: NodeConfiguration, val address: NetworkHostAndPort
|
||||
val monitoringService = MonitoringService(MetricRegistry())
|
||||
val identity: KeyPair = generateKeyPair()
|
||||
val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot)
|
||||
val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, NodeSchemaService(), { InMemoryIdentityService(trustRoot = trustRoot) })
|
||||
val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, { InMemoryIdentityService(trustRoot = trustRoot) })
|
||||
val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity))
|
||||
val executor = ServiceAffinityExecutor(config.myLegalName.organisation, 1)
|
||||
// TODO: We should have a dummy service hub rather than change behaviour in tests
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.testing
|
||||
|
||||
import net.corda.core.internal.packageName
|
||||
import org.apache.logging.log4j.Level
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.core.LoggerContext
|
||||
@ -25,7 +26,7 @@ object LogHelper {
|
||||
}
|
||||
}
|
||||
|
||||
fun setLevel(vararg classes: KClass<*>) = setLevel(*classes.map { "+" + it.java.`package`.name }.toTypedArray())
|
||||
fun setLevel(vararg classes: KClass<*>) = setLevel(*classes.map { "+" + it.packageName }.toTypedArray())
|
||||
|
||||
/** Removes custom configuration for the specified logger names */
|
||||
fun reset(vararg names: String) {
|
||||
@ -35,7 +36,7 @@ object LogHelper {
|
||||
loggerContext.updateLoggers(config)
|
||||
}
|
||||
|
||||
fun reset(vararg classes: KClass<*>) = reset(*classes.map { it.java.`package`.name }.toTypedArray())
|
||||
fun reset(vararg classes: KClass<*>) = reset(*classes.map { it.packageName }.toTypedArray())
|
||||
|
||||
/** Updates logging level for the specified Log4j logger name */
|
||||
private fun setLevel(name: String, level: Level) {
|
||||
|
@ -4,12 +4,13 @@ import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.cordapp.CordappImpl
|
||||
import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.node.internal.cordapp.CordappLoader
|
||||
import net.corda.node.internal.cordapp.CordappProviderImpl
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
|
||||
class MockCordappProvider(cordappLoader: CordappLoader) : CordappProviderImpl(cordappLoader) {
|
||||
class MockCordappProvider(cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage) : CordappProviderImpl(cordappLoader, attachmentStorage) {
|
||||
val cordappRegistry = mutableListOf<Pair<Cordapp, AttachmentId>>()
|
||||
|
||||
fun addMockCordapp(contractClassName: ContractClassName, attachments: MockAttachmentStorage) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user