From 85caa9ee9da6c0303e680712113012f7674b6172 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Tue, 31 Jul 2018 13:52:13 +0100 Subject: [PATCH] Feature/corda 1847/remove hibernate observers (#3696) * CORDA-1847 Fix hibernate observer issue * CORDA-1847 Fix hibernate observer issue * CORDA-1847 Fix hibernate observer issue * CORDA-1847 Fix tests * CORDA-1847 Fix tests * CORDA-1847 Fix tests --- .../confidential/IdentitySyncFlowTests.kt | 2 +- .../core/flows/CollectSignaturesFlowTests.kt | 3 +- .../core/flows/ContractUpgradeFlowTest.kt | 2 +- .../net/corda/core/flows/FinalityFlowTests.kt | 2 +- .../docs/JavaIntegrationTestingTutorial.java | 6 ++-- .../docs/KotlinIntegrationTestingTutorial.kt | 2 +- .../finance/contracts/CommercialPaperTests.kt | 10 +++---- .../finance/contracts/asset/CashTests.kt | 7 +++-- .../contracts/asset/ObligationTests.kt | 3 +- .../corda/finance/flows/CashExitFlowTests.kt | 2 +- .../corda/finance/flows/CashIssueFlowTests.kt | 2 +- .../finance/flows/CashPaymentFlowTests.kt | 2 +- ...owCheckpointVersionNodeStartupCheckTest.kt | 2 ++ .../distributed/DistributedServiceTests.kt | 2 +- .../net/corda/node/internal/AbstractNode.kt | 4 +-- ...eObserver.kt => PersistentStateService.kt} | 28 +++++-------------- .../node/services/vault/NodeVaultService.kt | 12 ++++---- .../net/corda/node/CordaRPCOpsImplTest.kt | 2 +- .../node/messaging/TwoPartyTradeFlowTests.kt | 2 +- .../services/ServiceHubConcurrentUsageTest.kt | 2 +- .../persistence/HibernateConfigurationTest.kt | 18 ++++++------ ...ests.kt => PersistentStateServiceTests.kt} | 19 +++++++------ .../services/vault/NodeVaultServiceTest.kt | 9 ++---- .../vault/VaultQueryExceptionsTests.kt | 6 +--- .../vault/VaultSoftLockManagerTest.kt | 1 + .../node/services/vault/VaultWithCashTest.kt | 4 +-- .../traderdemo/TransactionGraphSearchTests.kt | 5 ++-- .../net/corda/testing/node/MockServices.kt | 15 ++++++---- 28 files changed, 83 insertions(+), 91 deletions(-) rename node/src/main/kotlin/net/corda/node/services/schema/{HibernateObserver.kt => PersistentStateService.kt} (57%) rename node/src/test/kotlin/net/corda/node/services/schema/{HibernateObserverTests.kt => PersistentStateServiceTests.kt} (80%) diff --git a/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt b/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt index c094749d4a..bf9bb223da 100644 --- a/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt +++ b/confidential-identities/src/test/kotlin/net/corda/confidential/IdentitySyncFlowTests.kt @@ -35,7 +35,7 @@ class IdentitySyncFlowTests { fun before() { // We run this in parallel threads to help catch any race conditions that may exist. mockNet = InternalMockNetwork( - cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts.asset"), + cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts.asset", "net.corda.finance.schemas"), networkSendManuallyPumped = false, threadPerNode = true ) diff --git a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt index 68811a093b..96d9b77f5a 100644 --- a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt @@ -12,6 +12,7 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.excludeHostNode import net.corda.core.identity.groupAbstractPartyByWellKnownParty +import net.corda.core.node.services.IdentityService import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.testing.contracts.DummyContract @@ -27,7 +28,7 @@ import org.junit.Test class CollectSignaturesFlowTests : WithContracts { companion object { private val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")) - private val miniCorpServices = MockServices(listOf("net.corda.testing.contracts"), miniCorp, rigorousMock()) + private val miniCorpServices = MockServices(listOf("net.corda.testing.contracts"), miniCorp, rigorousMock()) private val classMockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.testing.contracts", "net.corda.core.flows")) private const val MAGIC_NUMBER = 1337 diff --git a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt index 57726d82c5..9f4bbc7bf1 100644 --- a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt +++ b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt @@ -33,7 +33,7 @@ import java.util.* class ContractUpgradeFlowTest : WithContracts, WithFinality { companion object { - private val classMockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.testing.contracts", "net.corda.finance.contracts.asset", "net.corda.core.flows")) + private val classMockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.testing.contracts", "net.corda.finance.contracts.asset", "net.corda.core.flows", "net.corda.finance.schemas")) @JvmStatic @AfterClass diff --git a/core/src/test/kotlin/net/corda/core/flows/FinalityFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/FinalityFlowTests.kt index 50718ccea0..17e2a5c6ec 100644 --- a/core/src/test/kotlin/net/corda/core/flows/FinalityFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/FinalityFlowTests.kt @@ -21,7 +21,7 @@ import org.junit.Test class FinalityFlowTests : WithFinality { companion object { private val CHARLIE = TestIdentity(CHARLIE_NAME, 90).party - private val classMockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts.asset")) + private val classMockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts.asset","net.corda.finance.schemas")) @JvmStatic @AfterClass diff --git a/docs/source/example-code/src/integration-test/java/net/corda/docs/JavaIntegrationTestingTutorial.java b/docs/source/example-code/src/integration-test/java/net/corda/docs/JavaIntegrationTestingTutorial.java index 912a996537..935c20b8f5 100644 --- a/docs/source/example-code/src/integration-test/java/net/corda/docs/JavaIntegrationTestingTutorial.java +++ b/docs/source/example-code/src/integration-test/java/net/corda/docs/JavaIntegrationTestingTutorial.java @@ -18,9 +18,7 @@ import net.corda.testing.node.User; import org.junit.Test; import rx.Observable; -import java.util.Currency; -import java.util.HashSet; -import java.util.List; +import java.util.*; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -40,7 +38,7 @@ public class JavaIntegrationTestingTutorial { // START 1 driver(new DriverParameters() .withStartNodesInProcess(true) - .withExtraCordappPackagesToScan(singletonList("net.corda.finance.contracts.asset")), dsl -> { + .withExtraCordappPackagesToScan(Arrays.asList("net.corda.finance.contracts.asset", "net.corda.finance.schemas")), dsl -> { User aliceUser = new User("aliceUser", "testPassword1", new HashSet<>(asList( startFlow(CashIssueAndPaymentFlow.class), diff --git a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/KotlinIntegrationTestingTutorial.kt b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/KotlinIntegrationTestingTutorial.kt index ee017c77a7..d27bc0dd24 100644 --- a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/KotlinIntegrationTestingTutorial.kt +++ b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/KotlinIntegrationTestingTutorial.kt @@ -31,7 +31,7 @@ class KotlinIntegrationTestingTutorial { // START 1 driver(DriverParameters( startNodesInProcess = true, - extraCordappPackagesToScan = listOf("net.corda.finance.contracts.asset") + extraCordappPackagesToScan = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas") )) { val aliceUser = User("aliceUser", "testPassword1", permissions = setOf( startFlow(), diff --git a/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt b/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt index 5c133b9020..a721f07f36 100644 --- a/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt @@ -109,7 +109,7 @@ class CommercialPaperTestsGeneric { val testSerialization = SerializationEnvironmentRule() private val megaCorpRef = megaCorp.ref(123) - private val ledgerServices = MockServices(megaCorp, miniCorp) + private val ledgerServices = MockServices(listOf("net.corda.finance.schemas"), megaCorp, miniCorp) @Test fun `trade lifecycle test`() { @@ -245,10 +245,10 @@ class CommercialPaperTestsGeneric { // of the dummy cash issuer. val allIdentities = arrayOf(megaCorp.identity, alice.identity, dummyCashIssuer.identity, dummyNotary.identity) - val notaryServices = MockServices(dummyNotary) - val issuerServices = MockServices(dummyCashIssuer, dummyNotary) + val notaryServices = MockServices(listOf("net.corda.finance.contracts", "net.corda.finance.contracts.asset", "net.corda.finance.schemas"), dummyNotary) + val issuerServices = MockServices(listOf("net.corda.finance.contracts", "net.corda.finance.contracts.asset", "net.corda.finance.schemas"), dummyCashIssuer, dummyNotary) val (aliceDatabase, aliceServices) = makeTestDatabaseAndMockServices( - listOf("net.corda.finance.contracts"), + listOf("net.corda.finance.contracts", "net.corda.finance.contracts.asset", "net.corda.finance.schemas"), makeTestIdentityService(*allIdentities), alice ) @@ -257,7 +257,7 @@ class CommercialPaperTestsGeneric { } val (megaCorpDatabase, megaCorpServices) = makeTestDatabaseAndMockServices( - listOf("net.corda.finance.contracts"), + listOf("net.corda.finance.contracts", "net.corda.finance.contracts.asset", "net.corda.finance.schemas"), makeTestIdentityService(*allIdentities), megaCorp ) diff --git a/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt b/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt index 83faeb168f..6ae37494af 100644 --- a/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt @@ -79,12 +79,13 @@ class CashTests { // TODO: Optimise this so that we don't throw away and rebuild state that can be shared across tests. @Before fun setUp() { + val cordapps = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas") LogHelper.setLevel(NodeVaultService::class) - megaCorpServices = MockServices(megaCorp) - miniCorpServices = MockServices(miniCorp) + megaCorpServices = MockServices(cordapps, megaCorp) + miniCorpServices = MockServices(cordapps, miniCorp) val myself = TestIdentity(CordaX500Name("Me", "London", "GB")) val databaseAndServices = makeTestDatabaseAndMockServices( - listOf("net.corda.finance.contracts.asset"), + cordapps, makeTestIdentityService(megaCorp.identity, miniCorp.identity, dummyCashIssuer.identity, dummyNotary.identity, myself.identity), myself ) diff --git a/finance/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt b/finance/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt index 7db53df1a8..7c5edaeea1 100644 --- a/finance/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/contracts/asset/ObligationTests.kt @@ -9,6 +9,7 @@ import net.corda.core.crypto.sha256 import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.CordaX500Name +import net.corda.core.node.services.IdentityService import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.NonEmptySet import net.corda.core.utilities.OpaqueBytes @@ -80,7 +81,7 @@ class ObligationTests { beneficiary = CHARLIE ) private val outState = inState.copy(beneficiary = AnonymousParty(BOB_PUBKEY)) - private val miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), miniCorp, rigorousMock()) + private val miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), miniCorp, rigorousMock()) private val notaryServices = MockServices(emptyList(), MEGA_CORP.name, rigorousMock(), dummyNotary.keyPair) private val identityService = rigorousMock().also { doReturn(null).whenever(it).partyFromKey(ALICE_PUBKEY) diff --git a/finance/src/test/kotlin/net/corda/finance/flows/CashExitFlowTests.kt b/finance/src/test/kotlin/net/corda/finance/flows/CashExitFlowTests.kt index 541dcc7d4c..7d4ed7687c 100644 --- a/finance/src/test/kotlin/net/corda/finance/flows/CashExitFlowTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/flows/CashExitFlowTests.kt @@ -27,7 +27,7 @@ class CashExitFlowTests { @Before fun start() { mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), - cordappPackages = listOf("net.corda.finance.contracts.asset")) + cordappPackages = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas")) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) notary = mockNet.defaultNotaryIdentity diff --git a/finance/src/test/kotlin/net/corda/finance/flows/CashIssueFlowTests.kt b/finance/src/test/kotlin/net/corda/finance/flows/CashIssueFlowTests.kt index 3a732a6679..ecb9573be9 100644 --- a/finance/src/test/kotlin/net/corda/finance/flows/CashIssueFlowTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/flows/CashIssueFlowTests.kt @@ -24,7 +24,7 @@ class CashIssueFlowTests { @Before fun start() { - mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts.asset")) + mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts", "net.corda.finance.contracts.asset", "net.corda.finance.schemas")) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) notary = mockNet.defaultNotaryIdentity diff --git a/finance/src/test/kotlin/net/corda/finance/flows/CashPaymentFlowTests.kt b/finance/src/test/kotlin/net/corda/finance/flows/CashPaymentFlowTests.kt index b7c6153e4a..8b9ba26423 100644 --- a/finance/src/test/kotlin/net/corda/finance/flows/CashPaymentFlowTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/flows/CashPaymentFlowTests.kt @@ -29,7 +29,7 @@ class CashPaymentFlowTests { @Before fun start() { - mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts.asset")) + mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas")) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) aliceNode = mockNet.createPartyNode(ALICE_NAME) diff --git a/node/src/integration-test/kotlin/net/corda/node/flows/FlowCheckpointVersionNodeStartupCheckTest.kt b/node/src/integration-test/kotlin/net/corda/node/flows/FlowCheckpointVersionNodeStartupCheckTest.kt index e4640b4ab2..ab2d706403 100644 --- a/node/src/integration-test/kotlin/net/corda/node/flows/FlowCheckpointVersionNodeStartupCheckTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/flows/FlowCheckpointVersionNodeStartupCheckTest.kt @@ -33,6 +33,8 @@ class FlowCheckpointVersionNodeStartupCheckTest { val classes = setOf(net.corda.testMessage.MessageState::class.java, net.corda.testMessage.MessageContract::class.java, net.test.cordapp.v1.SendMessageFlow::class.java, + net.corda.testMessage.MessageSchema::class.java, + net.corda.testMessage.MessageSchemaV1::class.java, net.test.cordapp.v1.Record::class.java) val user = User("mark", "dadada", setOf(startFlow(), invokeRpc("vaultQuery"), invokeRpc("vaultTrack"))) } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt index deff122b8d..9bebdc794c 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt @@ -42,7 +42,7 @@ class DistributedServiceTests { invokeRpc(CordaRPCOps::stateMachinesFeed)) ) driver(DriverParameters( - extraCordappPackagesToScan = listOf("net.corda.finance.contracts"), + extraCordappPackagesToScan = listOf("net.corda.finance.contracts", "net.corda.finance.schemas"), notarySpecs = listOf( NotarySpec( DUMMY_NOTARY_NAME, 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 3c6b59b6dd..258755982f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -53,7 +53,6 @@ import net.corda.node.services.messaging.DeduplicationHandler import net.corda.node.services.messaging.MessagingService import net.corda.node.services.network.* import net.corda.node.services.persistence.* -import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.statemachine.* import net.corda.node.services.transactions.* @@ -334,7 +333,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration, contractUpgradeService.start() vaultService.start() ScheduledActivityObserver.install(vaultService, schedulerService, flowLogicRefFactory) - HibernateObserver.install(vaultService.rawUpdates, database.hibernateConfig, schemaService) val frozenTokenizableServices = tokenizableServices!! tokenizableServices = null @@ -864,7 +862,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, protected open fun makeVaultService(keyManagementService: KeyManagementService, services: ServicesForResolution, database: CordaPersistence): VaultServiceInternal { - return NodeVaultService(platformClock, keyManagementService, services, database) + return NodeVaultService(platformClock, keyManagementService, services, database, schemaService) } /** Load configured JVM agents */ diff --git a/node/src/main/kotlin/net/corda/node/services/schema/HibernateObserver.kt b/node/src/main/kotlin/net/corda/node/services/schema/PersistentStateService.kt similarity index 57% rename from node/src/main/kotlin/net/corda/node/services/schema/HibernateObserver.kt rename to node/src/main/kotlin/net/corda/node/services/schema/PersistentStateService.kt index e5c181bf6a..3bb806cdcd 100644 --- a/node/src/main/kotlin/net/corda/node/services/schema/HibernateObserver.kt +++ b/node/src/main/kotlin/net/corda/node/services/schema/PersistentStateService.kt @@ -4,16 +4,12 @@ import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef import net.corda.core.internal.VisibleForTesting -import net.corda.core.node.services.Vault import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.PersistentStateRef import net.corda.core.utilities.contextLogger import net.corda.core.utilities.debug import net.corda.node.services.api.SchemaService -import net.corda.nodeapi.internal.persistence.HibernateConfiguration -import net.corda.nodeapi.internal.persistence.contextTransaction -import org.hibernate.FlushMode -import rx.Observable +import net.corda.nodeapi.internal.persistence.currentDBSession /** * Small data class bundling together a ContractState and a StateRef (as opposed to a TransactionState and StateRef @@ -25,17 +21,12 @@ data class ContractStateAndRef(val state: ContractState, val ref: StateRef) * A vault observer that extracts Object Relational Mappings for contract states that support it, and persists them with Hibernate. */ // TODO: Manage version evolution of the schemas via additional tooling. -class HibernateObserver private constructor(private val config: HibernateConfiguration, private val schemaService: SchemaService) { +class PersistentStateService(private val schemaService: SchemaService) { companion object { private val log = contextLogger() - fun install(vaultUpdates: Observable>, config: HibernateConfiguration, schemaService: SchemaService): HibernateObserver { - val observer = HibernateObserver(config, schemaService) - vaultUpdates.subscribe { observer.persist(it.produced) } - return observer - } } - private fun persist(produced: Set>) { + fun persist(produced: Set>) { val stateBySchema: MutableMap> = mutableMapOf() // map all states by their referenced schemas produced.forEach { @@ -51,15 +42,10 @@ class HibernateObserver private constructor(private val config: HibernateConfigu @VisibleForTesting internal fun persistStatesWithSchema(statesAndRefs: List, schema: MappedSchema) { - val sessionFactory = config.sessionFactoryForSchemas(setOf(schema)) - val session = sessionFactory.withOptions().connection(contextTransaction.connection).flushMode(FlushMode.MANUAL).openSession() - session.use { thisSession -> - statesAndRefs.forEach { - val mappedObject = schemaService.generateMappedObject(it.state, schema) - mappedObject.stateRef = PersistentStateRef(it.ref) - thisSession.persist(mappedObject) - } - thisSession.flush() + statesAndRefs.forEach { + val mappedObject = schemaService.generateMappedObject(it.state, schema) + mappedObject.stateRef = PersistentStateRef(it.ref) + currentDBSession().persist(mappedObject) } } } 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 65bd5ffe75..2062762711 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 @@ -14,12 +14,11 @@ import net.corda.core.schemas.PersistentStateRef import net.corda.core.serialization.SingletonSerializeAsToken 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.nodeapi.internal.persistence.CordaPersistence -import net.corda.nodeapi.internal.persistence.bufferUntilDatabaseCommit -import net.corda.nodeapi.internal.persistence.currentDBSession -import net.corda.nodeapi.internal.persistence.wrapWithDatabaseTransaction +import net.corda.nodeapi.internal.persistence.* import org.hibernate.Session import rx.Observable import rx.subjects.PublishSubject @@ -51,7 +50,8 @@ class NodeVaultService( private val clock: Clock, private val keyManagementService: KeyManagementService, private val servicesForResolution: ServicesForResolution, - private val database: CordaPersistence + private val database: CordaPersistence, + private val schemaService: SchemaService ) : SingletonSerializeAsToken(), VaultServiceInternal { private companion object { private val log = contextLogger() @@ -68,6 +68,7 @@ class NodeVaultService( private val mutex = ThreadBox(InnerState()) private lateinit var criteriaBuilder: CriteriaBuilder + private val persistentStateService = PersistentStateService(schemaService) /** * Maintain a list of contract state interfaces to concrete types stored in the vault @@ -247,6 +248,7 @@ class NodeVaultService( softLockReserve(uuid, stateRefs) } } + persistentStateService.persist(vaultUpdate.produced) updatesPublisher.onNext(vaultUpdate) } } diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt index 8996e1892c..8c8c794378 100644 --- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt @@ -81,7 +81,7 @@ class CordaRPCOpsImplTest { @Before fun setup() { - mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts.asset")) + mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.finance.contracts.asset", "net.corda.finance.schemas")) aliceNode = mockNet.createNode(InternalMockNodeParameters(legalName = ALICE_NAME)) rpc = aliceNode.rpcOps CURRENT_RPC_CONTEXT.set(RpcAuthContext(InvocationContext.rpc(testActor()), buildSubject("TEST_USER", emptySet()))) diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 66a8430516..8303cacefd 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -74,7 +74,7 @@ import kotlin.test.assertTrue @RunWith(Parameterized::class) class TwoPartyTradeFlowTests(private val anonymous: Boolean) { companion object { - private val cordappPackages = setOf("net.corda.finance.contracts") + private val cordappPackages = listOf("net.corda.finance.contracts", "net.corda.finance.schemas") @JvmStatic @Parameterized.Parameters(name = "Anonymous = {0}") fun data(): Collection = listOf(true, false) diff --git a/node/src/test/kotlin/net/corda/node/services/ServiceHubConcurrentUsageTest.kt b/node/src/test/kotlin/net/corda/node/services/ServiceHubConcurrentUsageTest.kt index 3329cc7259..4d2b8147b7 100644 --- a/node/src/test/kotlin/net/corda/node/services/ServiceHubConcurrentUsageTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/ServiceHubConcurrentUsageTest.kt @@ -25,7 +25,7 @@ import java.util.concurrent.CountDownLatch class ServiceHubConcurrentUsageTest { - private val mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(Cash::class.packageName)) + private val mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages("net.corda.finance.schemas", "net.corda.node.services.vault.VaultQueryExceptionsTests", Cash::class.packageName)) @After fun stopNodes() { 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 cdcd05f38f..abcf7e009a 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 @@ -24,6 +24,7 @@ import net.corda.finance.SWISS_FRANCS import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.DummyFungibleContract import net.corda.finance.schemas.CashSchemaV1 +import net.corda.finance.schemas.SampleCashSchemaV1 import net.corda.finance.schemas.SampleCashSchemaV2 import net.corda.finance.schemas.SampleCashSchemaV3 import net.corda.finance.utils.sumCash @@ -31,7 +32,7 @@ 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 -import net.corda.node.services.schema.HibernateObserver +import net.corda.node.services.schema.PersistentStateService import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.vault.NodeVaultService import net.corda.node.services.vault.VaultSchemaV1 @@ -40,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.rigorousMock +import net.corda.testing.internal.vault.DummyDealStateSchemaV1 import net.corda.testing.internal.vault.DummyLinearStateSchemaV1 import net.corda.testing.internal.vault.DummyLinearStateSchemaV2 import net.corda.testing.internal.vault.VaultFiller @@ -81,7 +83,7 @@ class HibernateConfigurationTest { // Hibernate configuration objects lateinit var hibernateConfig: HibernateConfiguration - private lateinit var hibernatePersister: HibernateObserver + private lateinit var hibernatePersister: PersistentStateService private lateinit var sessionFactory: SessionFactory private lateinit var entityManager: EntityManager private lateinit var criteriaBuilder: CriteriaBuilder @@ -96,10 +98,10 @@ class HibernateConfigurationTest { @Before fun setUp() { - val cordappPackages = listOf("net.corda.testing.internal.vault", "net.corda.finance.contracts.asset") + val cordappPackages = listOf("net.corda.testing.internal.vault", "net.corda.finance.contracts.asset", "net.corda.finance.schemas") bankServices = MockServices(cordappPackages, BOC.name, rigorousMock(), BOC_KEY) - issuerServices = MockServices(cordappPackages, dummyCashIssuer, rigorousMock()) - notaryServices = MockServices(cordappPackages, dummyNotary, rigorousMock()) + issuerServices = MockServices(cordappPackages, dummyCashIssuer, rigorousMock()) + notaryServices = MockServices(cordappPackages, dummyNotary, rigorousMock()) notary = notaryServices.myInfo.singleIdentity() val dataSourceProps = makeTestDataSourceProperties() val identityService = rigorousMock().also { mock -> @@ -109,7 +111,7 @@ class HibernateConfigurationTest { doReturn(it.party).whenever(mock).wellKnownPartyFromX500Name(it.name) } } - val schemaService = NodeSchemaService() + val schemaService = NodeSchemaService(extraSchemas = setOf(CashSchemaV1, SampleCashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3, DummyLinearStateSchemaV1, DummyLinearStateSchemaV2, DummyDealStateSchemaV1)) database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, schemaService) database.transaction { hibernateConfig = database.hibernateConfig @@ -118,7 +120,7 @@ class HibernateConfigurationTest { services = object : MockServices(cordappPackages, BOB_NAME, rigorousMock().also { doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == BOB_NAME }) }, generateKeyPair(), dummyNotary.keyPair) { - override val vaultService = NodeVaultService(Clock.systemUTC(), keyManagementService, servicesForResolution, database).apply { start() } + override val vaultService = NodeVaultService(Clock.systemUTC(), keyManagementService, servicesForResolution, database, schemaService).apply { start() } override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable) { for (stx in txs) { (validatedTransactions as WritableTransactionStorage).addTransaction(stx) @@ -130,7 +132,7 @@ class HibernateConfigurationTest { override fun jdbcSession() = database.createSession() } vaultFiller = VaultFiller(services, dummyNotary, notary, ::Random) - hibernatePersister = HibernateObserver.install(services.vaultService.rawUpdates, hibernateConfig, schemaService) + hibernatePersister = PersistentStateService(schemaService) } identity = services.myInfo.singleIdentity() diff --git a/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt b/node/src/test/kotlin/net/corda/node/services/schema/PersistentStateServiceTests.kt similarity index 80% rename from node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt rename to node/src/test/kotlin/net/corda/node/services/schema/PersistentStateServiceTests.kt index 4090ac02dd..f1abf5e618 100644 --- a/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/schema/PersistentStateServiceTests.kt @@ -14,25 +14,28 @@ 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.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 HibernateObserverTests { +class PersistentStateServiceTests { @Before fun setUp() { - LogHelper.setLevel(HibernateObserver::class) + LogHelper.setLevel(PersistentStateService::class) } @After fun cleanUp() { - LogHelper.reset(HibernateObserver::class) + LogHelper.reset(PersistentStateService::class) } class TestState : QueryableState { @@ -51,9 +54,8 @@ class HibernateObserverTests { @Test fun `test child objects are persisted`() { val testSchema = TestSchema - val rawUpdatesPublisher = PublishSubject.create>() val schemaService = object : SchemaService { - override val schemaOptions: Map = emptyMap() + override val schemaOptions: Map = mapOf(testSchema to SchemaService.SchemaOptions()) override fun selectSchemas(state: ContractState): Iterable = setOf(testSchema) @@ -64,11 +66,12 @@ class HibernateObserverTests { return parent } } - val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), { null }, { null }, schemaService) - HibernateObserver.install(rawUpdatesPublisher, database.hibernateConfig, schemaService) + val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock(), rigorousMock(), schemaService) + val persistentStateService = PersistentStateService(schemaService) database.transaction { val MEGA_CORP = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party - rawUpdatesPublisher.onNext(Vault.Update(emptySet(), setOf(StateAndRef(TransactionState(TestState(), DummyContract.PROGRAM_ID, MEGA_CORP), StateRef(SecureHash.sha256("dummy"), 0))))) + persistentStateService.persist(setOf(StateAndRef(TransactionState(TestState(), DummyContract.PROGRAM_ID, MEGA_CORP), StateRef(SecureHash.sha256("dummy"), 0)))) + currentDBSession().flush() val parentRowCountResult = connection.prepareStatement("select count(*) from Parents").executeQuery() parentRowCountResult.next() val parentRows = parentRowCountResult.getInt(1) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt index dce2e9bf50..d0506cfe07 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt @@ -11,10 +11,7 @@ import net.corda.core.identity.* import net.corda.core.internal.NotaryChangeTransactionBuilder import net.corda.core.internal.packageName import net.corda.core.node.StatesToRecord -import net.corda.core.node.services.StatesNotAvailableException -import net.corda.core.node.services.Vault -import net.corda.core.node.services.VaultService -import net.corda.core.node.services.queryBy +import net.corda.core.node.services.* import net.corda.core.node.services.vault.PageSpecification import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.QueryCriteria.* @@ -97,8 +94,8 @@ class NodeVaultServiceTest { vaultFiller = VaultFiller(services, dummyNotary) // This is safe because MockServices only ever have a single identity identity = services.myInfo.singleIdentityAndCert() - issuerServices = MockServices(cordappPackages, dummyCashIssuer, rigorousMock()) - bocServices = MockServices(cordappPackages, bankOfCorda, rigorousMock()) + issuerServices = MockServices(cordappPackages, dummyCashIssuer, rigorousMock()) + bocServices = MockServices(cordappPackages, bankOfCorda, rigorousMock()) services.identityService.verifyAndRegisterIdentity(DUMMY_CASH_ISSUER_IDENTITY) services.identityService.verifyAndRegisterIdentity(BOC_IDENTITY) } diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt index 59338d5f06..a1018d5526 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryExceptionsTests.kt @@ -23,8 +23,7 @@ class VaultQueryExceptionsTests : VaultQueryParties by rule { override val cordappPackages = listOf( "net.corda.testing.contracts", "net.corda.finance.contracts", - CashSchemaV1::class.packageName, - DummyLinearStateSchemaV1::class.packageName) - SampleCashSchemaV3::class.packageName + DummyLinearStateSchemaV1::class.packageName) } } @@ -43,9 +42,6 @@ class VaultQueryExceptionsTests : VaultQueryParties by rule { @Test fun `query attempting to use unregistered schema`() { database.transaction { - vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 1, DUMMY_CASH_ISSUER) - vaultFiller.fillWithSomeTestCash(100.POUNDS, notaryServices, 1, DUMMY_CASH_ISSUER) - vaultFiller.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, 1, DUMMY_CASH_ISSUER) // CashSchemaV3 NOT registered with NodeSchemaService val logicalExpression = builder { SampleCashSchemaV3.PersistentCashState::currency.equal(GBP.currencyCode) } val criteria = VaultCustomQueryCriteria(logicalExpression) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt index 29c1fccf83..6784d43362 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt @@ -24,6 +24,7 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap import net.corda.node.internal.InitiatedFlowFactory +import net.corda.node.services.api.SchemaService import net.corda.node.services.api.VaultServiceInternal import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.testing.core.singleIdentity diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt index a22723697d..3bcf3ee48f 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt @@ -45,7 +45,7 @@ import kotlin.test.fail class VaultWithCashTest { private companion object { - val cordappPackages = listOf("net.corda.testing.internal.vault", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName) + val cordappPackages = listOf("net.corda.testing.internal.vault", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName, "net.corda.core.contracts") val BOB = TestIdentity(BOB_NAME, 80).party val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10) val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1) @@ -83,7 +83,7 @@ class VaultWithCashTest { services = databaseAndServices.second vaultFiller = VaultFiller(services, dummyNotary) issuerServices = MockServices(cordappPackages, dummyCashIssuer, rigorousMock(), MEGA_CORP_KEY) - notaryServices = MockServices(cordappPackages, dummyNotary, rigorousMock()) + notaryServices = MockServices(cordappPackages, dummyNotary, rigorousMock()) notary = notaryServices.myInfo.legalIdentitiesAndCerts.single().party } diff --git a/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/TransactionGraphSearchTests.kt b/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/TransactionGraphSearchTests.kt index 74d8b78c25..5cad922236 100644 --- a/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/TransactionGraphSearchTests.kt +++ b/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/TransactionGraphSearchTests.kt @@ -3,6 +3,7 @@ package net.corda.traderdemo import net.corda.core.contracts.CommandData import net.corda.core.crypto.newSecureRandom import net.corda.core.identity.CordaX500Name +import net.corda.core.node.services.IdentityService import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction @@ -46,8 +47,8 @@ class TransactionGraphSearchTests { * @param signer signer for the two transactions and their commands. */ fun buildTransactions(command: CommandData): GraphTransactionStorage { - val megaCorpServices = MockServices(listOf("net.corda.testing.contracts"), megaCorp, rigorousMock()) - val notaryServices = MockServices(listOf("net.corda.testing.contracts"), dummyNotary, rigorousMock()) + val megaCorpServices = MockServices(listOf("net.corda.testing.contracts"), megaCorp, rigorousMock()) + val notaryServices = MockServices(listOf("net.corda.testing.contracts"), dummyNotary, rigorousMock()) val originBuilder = TransactionBuilder(dummyNotary.party) .addOutputState(DummyState(random31BitValue()), DummyContract.PROGRAM_ID) .addCommand(command, megaCorp.publicKey) 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 b4351a2953..cfd6eeee6a 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 @@ -24,7 +24,6 @@ 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 -import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.vault.NodeVaultService @@ -115,7 +114,7 @@ open class MockServices private constructor( val database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, schemaService) val mockService = database.transaction { object : MockServices(cordappLoader, identityService, networkParameters, initialIdentity, moreKeys) { - override val vaultService: VaultService = makeVaultService(database.hibernateConfig, schemaService, database) + override val vaultService: VaultService = makeVaultService(schemaService, database) override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable) { ServiceHubInternal.recordTransactions(statesToRecord, txs, @@ -212,6 +211,12 @@ open class MockServices private constructor( constructor(firstIdentity: TestIdentity, vararg moreIdentities: TestIdentity) : this( listOf(getCallerPackage(MockServices::class)!!), firstIdentity, + *moreIdentities + ) + + constructor(cordappPackages: List, firstIdentity: TestIdentity, vararg moreIdentities: TestIdentity) : this( + cordappPackages, + firstIdentity, makeTestIdentityService(*listOf(firstIdentity, *moreIdentities).map { it.identity }.toTypedArray()), firstIdentity.keyPair ) @@ -251,10 +256,8 @@ open class MockServices private constructor( } } - internal fun makeVaultService(hibernateConfig: HibernateConfiguration, schemaService: SchemaService, database: CordaPersistence): VaultServiceInternal { - val vaultService = NodeVaultService(clock, keyManagementService, servicesForResolution, database).apply { start() } - HibernateObserver.install(vaultService.rawUpdates, hibernateConfig, schemaService) - return vaultService + internal fun makeVaultService(schemaService: SchemaService, database: CordaPersistence): VaultServiceInternal { + return NodeVaultService(clock, keyManagementService, servicesForResolution, database, schemaService).apply { start() } } // This needs to be internal as MutableClassToInstanceMap is a guava type and shouldn't be part of our public API