From 5bdbd2457a53777d22987206b10b3ddfa954fd60 Mon Sep 17 00:00:00 2001 From: josecoll Date: Wed, 15 Nov 2017 19:28:04 +0000 Subject: [PATCH] Removal of transaction contract state as BLOB in VaultStates table. (#2034) * Removal of transaction contract state as BLOB in VaultStates table. Transaction contract state now resolved using StateLoader (from DBTransactionStorage). Fixed broken JUnits. * Changes to address review comments by RP Address logic error. * Fixed failing JUnit (CashExitFlowTests.exit zero cash). * Fix VaultQueryTests to respect transaction visibility boundaries. * Adopt consistent use of "session" using DatabaseTransactionManager. * Removed redundant transaction demarcation boundaries in Vault Query tests. --- .../kotlin/net/corda/core/node/ServiceHub.kt | 10 + .../cash/selection/AbstractCashSelection.kt | 16 +- .../cash/selection/CashSelectionH2Impl.kt | 2 +- .../selection/CashSelectionPostgreSQLImpl.kt | 4 +- .../net/corda/node/internal/StartedNode.kt | 10 +- .../node/services/vault/NodeVaultService.kt | 186 ++++---- .../corda/node/services/vault/VaultSchema.kt | 8 +- .../persistence/HibernateConfigurationTest.kt | 14 +- .../services/vault/NodeVaultServiceTest.kt | 36 +- .../node/services/vault/VaultQueryTests.kt | 428 +++++++----------- 10 files changed, 300 insertions(+), 414 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt index 59d0b3adfc..68ae3fc5f3 100644 --- a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt @@ -31,6 +31,16 @@ interface StateLoader { */ @Throws(TransactionResolutionException::class) fun loadState(stateRef: StateRef): TransactionState<*> + + /** + * Given a [Set] of [StateRef]'s loads the referenced transaction and looks up the specified output [ContractState]. + * + * @throws TransactionResolutionException if [stateRef] points to a non-existent transaction. + */ + // TODO: future implementation to use a Vault state ref -> contract state BLOB table and perform single query bulk load + // as the existing transaction store will become encrypted at some point + @Throws(TransactionResolutionException::class) + fun loadStates(stateRefs: Set): Set> } /** diff --git a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/AbstractCashSelection.kt b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/AbstractCashSelection.kt index fdc3d0d5a7..34dfb3b3ea 100644 --- a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/AbstractCashSelection.kt +++ b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/AbstractCashSelection.kt @@ -131,17 +131,19 @@ abstract class AbstractCashSelection { stateAndRefs.clear() var totalPennies = 0L + val stateRefs = mutableSetOf() while (rs.next()) { val txHash = SecureHash.parse(rs.getString(1)) val index = rs.getInt(2) - val stateRef = StateRef(txHash, index) - val state = rs.getBlob(3).deserialize>(context = SerializationDefaults.STORAGE_CONTEXT) - val pennies = rs.getLong(4) - totalPennies = rs.getLong(5) - val rowLockId = rs.getString(6) - stateAndRefs.add(StateAndRef(state, stateRef)) - log.trace { "ROW: $rowLockId ($lockId): $stateRef : $pennies ($totalPennies)" } + val pennies = rs.getLong(3) + totalPennies = rs.getLong(4) + val rowLockId = rs.getString(5) + stateRefs.add(StateRef(txHash, index)) + log.trace { "ROW: $rowLockId ($lockId): ${StateRef(txHash, index)} : $pennies ($totalPennies)" } } + if (stateRefs.isNotEmpty()) + // TODO: future implementation to retrieve contract states from a Vault BLOB store + stateAndRefs.addAll(services.loadStates(stateRefs) as Collection>) if (stateAndRefs.isNotEmpty() && totalPennies >= amount.quantity) { // we should have a minimum number of states to satisfy our selection `amount` criteria diff --git a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionH2Impl.kt b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionH2Impl.kt index 0a072897cd..ef46782996 100644 --- a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionH2Impl.kt +++ b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionH2Impl.kt @@ -35,7 +35,7 @@ class CashSelectionH2Impl : AbstractCashSelection() { connection.createStatement().execute("CALL SET(@t, 0);") val selectJoin = """ - SELECT vs.transaction_id, vs.output_index, vs.contract_state, ccs.pennies, SET(@t, ifnull(@t,0)+ccs.pennies) total_pennies, vs.lock_id + SELECT vs.transaction_id, vs.output_index, ccs.pennies, SET(@t, ifnull(@t,0)+ccs.pennies) total_pennies, vs.lock_id FROM vault_states AS vs, contract_cash_states AS ccs WHERE vs.transaction_id = ccs.transaction_id AND vs.output_index = ccs.output_index AND vs.state_status = 0 diff --git a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionPostgreSQLImpl.kt b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionPostgreSQLImpl.kt index d8154336e3..a792c60501 100644 --- a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionPostgreSQLImpl.kt +++ b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionPostgreSQLImpl.kt @@ -32,10 +32,10 @@ class CashSelectionPostgreSQLImpl : AbstractCashSelection() { // 3) Currently (version 9.6), FOR UPDATE cannot be specified with window functions override fun executeQuery(connection: Connection, amount: Amount, lockId: UUID, notary: Party?, onlyFromIssuerParties: Set, withIssuerRefs: Set) : ResultSet { - val selectJoin = """SELECT nested.transaction_id, nested.output_index, nested.contract_state, nested.pennies, + val selectJoin = """SELECT nested.transaction_id, nested.output_index, nested.pennies, nested.total+nested.pennies as total_pennies, nested.lock_id FROM - (SELECT vs.transaction_id, vs.output_index, vs.contract_state, ccs.pennies, + (SELECT vs.transaction_id, vs.output_index, ccs.pennies, coalesce((SUM(ccs.pennies) OVER (PARTITION BY 1 ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)), 0) AS total, vs.lock_id FROM vault_states AS vs, contract_cash_states AS ccs diff --git a/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt b/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt index 300e5a7d60..88c09de5cc 100644 --- a/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt @@ -1,8 +1,6 @@ package net.corda.node.internal -import net.corda.core.contracts.StateRef -import net.corda.core.contracts.TransactionResolutionException -import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.* import net.corda.core.flows.FlowLogic import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo @@ -37,4 +35,10 @@ class StateLoaderImpl(private val validatedTransactions: TransactionStorage) : S val stx = validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) return stx.resolveBaseTransaction(this).outputs[stateRef.index] } + + @Throws(TransactionResolutionException::class) + // TODO: future implementation to retrieve contract states from a Vault BLOB store + override fun loadStates(stateRefs: Set): Set> { + return (stateRefs.map { StateAndRef(loadState(it), it) }).toSet() + } } 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 8636e3ee90..13023a6c68 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 @@ -8,16 +8,10 @@ import net.corda.core.internal.* import net.corda.core.messaging.DataFeed import net.corda.core.node.StateLoader import net.corda.core.node.StatesToRecord -import net.corda.core.node.services.KeyManagementService -import net.corda.core.node.services.StatesNotAvailableException -import net.corda.core.node.services.Vault -import net.corda.core.node.services.VaultQueryException +import net.corda.core.node.services.* import net.corda.core.node.services.vault.* import net.corda.core.schemas.PersistentStateRef -import net.corda.core.serialization.SerializationDefaults.STORAGE_CONTEXT import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.serialization.deserialize -import net.corda.core.serialization.serialize import net.corda.core.transactions.CoreTransaction import net.corda.core.transactions.NotaryChangeWireTransaction import net.corda.core.transactions.WireTransaction @@ -89,7 +83,6 @@ class NodeVaultService( val state = VaultSchemaV1.VaultStates( notary = stateAndRef.value.state.notary, contractStateClassName = stateAndRef.value.state.data.javaClass.name, - contractState = stateAndRef.value.state.serialize(context = STORAGE_CONTEXT).bytes, stateStatus = Vault.StateStatus.UNCONSUMED, recordedTime = clock.instant()) state.stateRef = PersistentStateRef(stateAndRef.key) @@ -169,7 +162,7 @@ class NodeVaultService( return Vault.NoUpdate } - return Vault.Update(consumedStates, ourNewStates.toHashSet()) + return Vault.Update(consumedStates.toSet(), ourNewStates.toSet()) } val netDelta = txns.fold(Vault.NoUpdate) { netDelta, txn -> netDelta + makeUpdate(txn) } @@ -207,28 +200,10 @@ class NodeVaultService( processAndNotify(netDelta) } - // TODO: replace this method in favour of a VaultQuery query - private fun loadStates(refs: Collection): HashSet> { - val states = HashSet>() - if (refs.isNotEmpty()) { - val session = currentDBSession() - val criteriaBuilder = session.criteriaBuilder - val criteriaQuery = criteriaBuilder.createQuery(VaultSchemaV1.VaultStates::class.java) - val vaultStates = criteriaQuery.from(VaultSchemaV1.VaultStates::class.java) - val statusPredicate = criteriaBuilder.equal(vaultStates.get(VaultSchemaV1.VaultStates::stateStatus.name), Vault.StateStatus.UNCONSUMED) - val persistentStateRefs = refs.map(::PersistentStateRef) - val compositeKey = vaultStates.get(VaultSchemaV1.VaultStates::stateRef.name) - val stateRefsPredicate = criteriaBuilder.and(compositeKey.`in`(persistentStateRefs)) - criteriaQuery.where(statusPredicate, stateRefsPredicate) - val results = session.createQuery(criteriaQuery).resultList - results.asSequence().forEach { - val txHash = SecureHash.parse(it.stateRef?.txId!!) - val index = it.stateRef?.index!! - val state = it.contractState.deserialize>(context = STORAGE_CONTEXT) - states.add(StateAndRef(state, StateRef(txHash, index))) - } - } - return states + private fun loadStates(refs: Collection): Collection> { + return if (refs.isNotEmpty()) + queryBy(QueryCriteria.VaultQueryCriteria(stateRefs = refs.toList())).states + else emptySet() } private fun processAndNotify(update: Vault.Update) { @@ -428,70 +403,70 @@ class NodeVaultService( val session = getSession() - session.use { - val criteriaQuery = criteriaBuilder.createQuery(Tuple::class.java) - val queryRootVaultStates = criteriaQuery.from(VaultSchemaV1.VaultStates::class.java) + val criteriaQuery = criteriaBuilder.createQuery(Tuple::class.java) + val queryRootVaultStates = criteriaQuery.from(VaultSchemaV1.VaultStates::class.java) - // TODO: revisit (use single instance of parser for all queries) - val criteriaParser = HibernateQueryCriteriaParser(contractStateType, contractStateTypeMappings, criteriaBuilder, criteriaQuery, queryRootVaultStates) + // TODO: revisit (use single instance of parser for all queries) + val criteriaParser = HibernateQueryCriteriaParser(contractStateType, contractStateTypeMappings, criteriaBuilder, criteriaQuery, queryRootVaultStates) - try { - // parse criteria and build where predicates - criteriaParser.parse(criteria, sorting) + try { + // parse criteria and build where predicates + criteriaParser.parse(criteria, sorting) - // prepare query for execution - val query = session.createQuery(criteriaQuery) + // prepare query for execution + val query = session.createQuery(criteriaQuery) - // pagination checks - if (!paging.isDefault) { - // pagination - if (paging.pageNumber < DEFAULT_PAGE_NUM) throw VaultQueryException("Page specification: invalid page number ${paging.pageNumber} [page numbers start from $DEFAULT_PAGE_NUM]") - if (paging.pageSize < 1) throw VaultQueryException("Page specification: invalid page size ${paging.pageSize} [must be a value between 1 and $MAX_PAGE_SIZE]") - } - - query.firstResult = (paging.pageNumber - 1) * paging.pageSize - query.maxResults = paging.pageSize + 1 // detection too many results - - // execution - val results = query.resultList - - // final pagination check (fail-fast on too many results when no pagination specified) - if (paging.isDefault && results.size > DEFAULT_PAGE_SIZE) - throw VaultQueryException("Please specify a `PageSpecification` as there are more results [${results.size}] than the default page size [$DEFAULT_PAGE_SIZE]") - - val statesAndRefs: MutableList> = mutableListOf() - val statesMeta: MutableList = mutableListOf() - val otherResults: MutableList = mutableListOf() - - results.asSequence() - .forEachIndexed { index, result -> - if (result[0] is VaultSchemaV1.VaultStates) { - if (!paging.isDefault && index == paging.pageSize) // skip last result if paged - return@forEachIndexed - val vaultState = result[0] as VaultSchemaV1.VaultStates - val stateRef = StateRef(SecureHash.parse(vaultState.stateRef!!.txId!!), vaultState.stateRef!!.index!!) - val state = vaultState.contractState.deserialize>(context = STORAGE_CONTEXT) - statesMeta.add(Vault.StateMetadata(stateRef, - vaultState.contractStateClassName, - vaultState.recordedTime, - vaultState.consumedTime, - vaultState.stateStatus, - vaultState.notary, - vaultState.lockId, - vaultState.lockUpdateTime)) - statesAndRefs.add(StateAndRef(state, stateRef)) - } else { - // TODO: improve typing of returned other results - log.debug { "OtherResults: ${Arrays.toString(result.toArray())}" } - otherResults.addAll(result.toArray().asList()) - } - } - - return Vault.Page(states = statesAndRefs, statesMetadata = statesMeta, stateTypes = criteriaParser.stateTypes, totalStatesAvailable = totalStates, otherResults = otherResults) - } catch (e: java.lang.Exception) { - log.error(e.message) - throw e.cause ?: e + // pagination checks + if (!paging.isDefault) { + // pagination + if (paging.pageNumber < DEFAULT_PAGE_NUM) throw VaultQueryException("Page specification: invalid page number ${paging.pageNumber} [page numbers start from $DEFAULT_PAGE_NUM]") + if (paging.pageSize < 1) throw VaultQueryException("Page specification: invalid page size ${paging.pageSize} [must be a value between 1 and $MAX_PAGE_SIZE]") } + + query.firstResult = (paging.pageNumber - 1) * paging.pageSize + query.maxResults = paging.pageSize + 1 // detection too many results + + // execution + val results = query.resultList + + // final pagination check (fail-fast on too many results when no pagination specified) + if (paging.isDefault && results.size > DEFAULT_PAGE_SIZE) + throw VaultQueryException("Please specify a `PageSpecification` as there are more results [${results.size}] than the default page size [$DEFAULT_PAGE_SIZE]") + + val statesAndRefs: MutableList> = mutableListOf() + val statesMeta: MutableList = mutableListOf() + val otherResults: MutableList = mutableListOf() + val stateRefs = mutableSetOf() + + results.asSequence() + .forEachIndexed { index, result -> + if (result[0] is VaultSchemaV1.VaultStates) { + if (!paging.isDefault && index == paging.pageSize) // skip last result if paged + return@forEachIndexed + val vaultState = result[0] as VaultSchemaV1.VaultStates + val stateRef = StateRef(SecureHash.parse(vaultState.stateRef!!.txId!!), vaultState.stateRef!!.index!!) + stateRefs.add(stateRef) + statesMeta.add(Vault.StateMetadata(stateRef, + vaultState.contractStateClassName, + vaultState.recordedTime, + vaultState.consumedTime, + vaultState.stateStatus, + vaultState.notary, + vaultState.lockId, + vaultState.lockUpdateTime)) + } else { + // TODO: improve typing of returned other results + log.debug { "OtherResults: ${Arrays.toString(result.toArray())}" } + otherResults.addAll(result.toArray().asList()) + } + } + if (stateRefs.isNotEmpty()) + statesAndRefs.addAll(stateLoader.loadStates(stateRefs) as Collection>) + + return Vault.Page(states = statesAndRefs, statesMetadata = statesMeta, stateTypes = criteriaParser.stateTypes, totalStatesAvailable = totalStates, otherResults = otherResults) + } catch (e: java.lang.Exception) { + log.error(e.message) + throw e.cause ?: e } } @@ -504,11 +479,7 @@ class NodeVaultService( } } - private fun getSession(): Session { - return sessionFactory.withOptions(). - connection(DatabaseTransactionManager.current().connection). - openSession() - } + private fun getSession() = DatabaseTransactionManager.currentOrNew().session /** * Derive list from existing vault states and then incrementally update using vault observables @@ -518,22 +489,21 @@ class NodeVaultService( val vaultStates = criteria.from(VaultSchemaV1.VaultStates::class.java) criteria.select(vaultStates.get("contractStateClassName")).distinct(true) val session = getSession() - session.use { - val query = session.createQuery(criteria) - val results = query.resultList - val distinctTypes = results.map { it } - val contractInterfaceToConcreteTypes = mutableMapOf>() - distinctTypes.forEach { type -> - val concreteType: Class = uncheckedCast(Class.forName(type)) - val contractInterfaces = deriveContractInterfaces(concreteType) - contractInterfaces.map { - val contractInterface = contractInterfaceToConcreteTypes.getOrPut(it.name, { mutableSetOf() }) - contractInterface.add(concreteType.name) - } + val query = session.createQuery(criteria) + val results = query.resultList + val distinctTypes = results.map { it } + + val contractInterfaceToConcreteTypes = mutableMapOf>() + distinctTypes.forEach { type -> + val concreteType: Class = uncheckedCast(Class.forName(type)) + val contractInterfaces = deriveContractInterfaces(concreteType) + contractInterfaces.map { + val contractInterface = contractInterfaceToConcreteTypes.getOrPut(it.name, { mutableSetOf() }) + contractInterface.add(concreteType.name) } - return contractInterfaceToConcreteTypes } + return contractInterfaceToConcreteTypes } private fun deriveContractInterfaces(clazz: Class): Set> { diff --git a/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt b/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt index ae4f34e0fd..d98dbb4c0b 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt @@ -29,6 +29,9 @@ object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, versio @Table(name = "vault_states", indexes = arrayOf(Index(name = "state_status_idx", columnList = "state_status"))) class VaultStates( + /** NOTE: serialized transaction state (including contract state) is now resolved from transaction store */ + // TODO: create a distinct table to hold serialized state data (once DBTransactionStore is encrypted) + /** refers to the X500Name of the notary a state is attached to */ @Column(name = "notary_name") var notary: Party, @@ -37,11 +40,6 @@ object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, versio @Column(name = "contract_state_class_name") var contractStateClassName: String, - /** refers to serialized transaction Contract State */ - @Lob - @Column(name = "contract_state") - var contractState: ByteArray, - /** state lifecycle: unconsumed, consumed */ @Column(name = "state_status") var stateStatus: Vault.StateStatus, 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 73f7570e4d..f3213f5e0c 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 @@ -139,7 +139,9 @@ class HibernateConfigurationTest { // execute query val queryResults = entityManager.createQuery(criteriaQuery).resultList - val coins = queryResults.map { it.contractState.deserialize>(context = SerializationDefaults.STORAGE_CONTEXT).data }.sumCash() + val coins = queryResults.map { + (services.loadState(toStateRef(it.stateRef!!)) as TransactionState).data + }.sumCash() assertThat(coins.toDecimal() >= BigDecimal("50.00")) } @@ -657,8 +659,7 @@ class HibernateConfigurationTest { val queryResults = entityManager.createQuery(criteriaQuery).resultList queryResults.forEach { - val contractState = it.contractState.deserialize>(context = SerializationDefaults.STORAGE_CONTEXT) - val cashState = contractState.data as Cash.State + val cashState = (services.loadState(toStateRef(it.stateRef!!)) as TransactionState).data println("${it.stateRef} with owner: ${cashState.owner.owningKey.toBase58String()}") } @@ -742,8 +743,7 @@ class HibernateConfigurationTest { // execute query val queryResults = entityManager.createQuery(criteriaQuery).resultList queryResults.forEach { - val contractState = it.contractState.deserialize>(context = SerializationDefaults.STORAGE_CONTEXT) - val cashState = contractState.data as Cash.State + val cashState = (services.loadState(toStateRef(it.stateRef!!)) as TransactionState).data println("${it.stateRef} with owner ${cashState.owner.owningKey.toBase58String()} and participants ${cashState.participants.map { it.owningKey.toBase58String() }}") } @@ -880,4 +880,8 @@ class HibernateConfigurationTest { Assert.assertEquals(cashStates.count(), count) } } + + private fun toStateRef(pStateRef: PersistentStateRef): StateRef { + return StateRef(SecureHash.parse(pStateRef.txId!!), pStateRef.index!!) + } } \ No newline at end of file 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 5ae3d2f81c..ed6b391e9a 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 @@ -5,7 +5,7 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.Issued import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef -import net.corda.core.crypto.generateKeyPair +import net.corda.core.crypto.* import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party @@ -517,22 +517,32 @@ class NodeVaultServiceTest { val amount = Amount(1000, Issued(BOC.ref(1), GBP)) // Issue then move some cash - val issueTx = TransactionBuilder(identity.party).apply { + val builder = TransactionBuilder(identity.party).apply { Cash().generateIssue(this, amount, anonymousIdentity.party.anonymise(), identity.party) - }.toWireTransaction(bocServices) + } + val issueTx = builder.toWireTransaction(bocServices) val cashState = StateAndRef(issueTx.outputs.single(), StateRef(issueTx.id, 0)) + // ensure transaction contract state is persisted in DBStorage + val signedIssuedTx = services.signInitialTransaction(builder) + services.validatedTransactions.addTransaction(signedIssuedTx) + database.transaction { service.notify(StatesToRecord.ONLY_RELEVANT, issueTx) } val expectedIssueUpdate = Vault.Update(emptySet(), setOf(cashState), null) database.transaction { - val moveTx = TransactionBuilder(services.myInfo.chooseIdentity()).apply { + val builder = TransactionBuilder(services.myInfo.chooseIdentity()).apply { Cash.generateSpend(services, this, Amount(1000, GBP), thirdPartyIdentity) - }.toWireTransaction(services) + } + val moveTx = builder.toWireTransaction(services) service.notify(StatesToRecord.ONLY_RELEVANT, moveTx) } val expectedMoveUpdate = Vault.Update(setOf(cashState), emptySet(), null) + // ensure transaction contract state is persisted in DBStorage + val signedMoveTx = services.signInitialTransaction(builder) + services.validatedTransactions.addTransaction(signedMoveTx) + val observedUpdates = vaultSubscriber.onNextEvents assertEquals(observedUpdates, listOf(expectedIssueUpdate, expectedMoveUpdate)) } @@ -572,12 +582,20 @@ class NodeVaultServiceTest { service.notifyAll(StatesToRecord.ONLY_RELEVANT, listOf(issueStx.tx, changeNotaryTx)) } + // ensure transaction contract state is persisted in DBStorage + services.validatedTransactions.addTransaction(SignedTransaction(changeNotaryTx, listOf(NullKeys.NULL_SIGNATURE))) + // Move cash - val moveTx = database.transaction { + val moveTxBuilder = database.transaction { TransactionBuilder(newNotary).apply { Cash.generateSpend(services, this, Amount(amount.quantity, GBP), anonymousIdentity, thirdPartyIdentity.party.anonymise()) - }.toWireTransaction(services) + } } + val moveTx = moveTxBuilder.toWireTransaction(services) + + // ensure transaction contract state is persisted in DBStorage + val signedMoveTx = services.signInitialTransaction(moveTxBuilder) + services.validatedTransactions.addTransaction(signedMoveTx) database.transaction { service.notify(StatesToRecord.ONLY_RELEVANT, moveTx) @@ -609,6 +627,10 @@ class NodeVaultServiceTest { vaultService.notify(StatesToRecord.ONLY_RELEVANT, wtx) } + // ensure transaction contract state is persisted in DBStorage + val signedTxb = services.signInitialTransaction(txb) + services.validatedTransactions.addTransaction(signedTxb) + // Check that it was ignored as irrelevant. assertEquals(currentCashStates, countCash()) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt index e885390538..7491a91969 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt @@ -95,18 +95,14 @@ class VaultQueryTests { } private fun setUpDb(_database: CordaPersistence, delay: Long = 0) { - _database.transaction { - // create new states services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 10, 10, Random(0L)) val linearStatesXYZ = services.fillWithSomeTestLinearStates(1, "XYZ") val linearStatesJKL = services.fillWithSomeTestLinearStates(2, "JKL") services.fillWithSomeTestLinearStates(3, "ABC") val dealStates = services.fillWithSomeTestDeals(listOf("123", "456", "789")) - // Total unconsumed states = 10 + 1 + 2 + 3 + 3 = 19 - sleep(delay) // consume some states @@ -114,7 +110,6 @@ class VaultQueryTests { services.consumeLinearStates(linearStatesJKL.states.toList(), DUMMY_NOTARY) services.consumeDeals(dealStates.states.filter { it.state.data.linearId.externalId == "456" }, DUMMY_NOTARY) services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) - // Total unconsumed states = 4 + 3 + 2 + 1 (new cash change) = 10 // Total consumed states = 6 + 1 + 2 + 1 = 10 } @@ -145,8 +140,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + // DOCSTART VaultQueryExample1 val result = vaultService.queryBy() @@ -172,8 +166,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + val criteria = VaultQueryCriteria() // default is UNCONSUMED val result = vaultService.queryBy(criteria) @@ -189,18 +182,15 @@ class VaultQueryTests { services.fillWithSomeTestCash(25.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(25.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(25.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - val paging = PageSpecification(DEFAULT_PAGE_NUM, 10) - database.transaction { + + val paging = PageSpecification(DEFAULT_PAGE_NUM, 10) val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) val resultsBeforeConsume = vaultService.queryBy(criteria, paging) assertThat(resultsBeforeConsume.states).hasSize(4) assertThat(resultsBeforeConsume.totalStatesAvailable).isEqualTo(4) - } - database.transaction { + services.consumeCash(75.DOLLARS, notary = DUMMY_NOTARY) - } - database.transaction { + val consumedCriteria = VaultQueryCriteria(status = Vault.StateStatus.UNCONSUMED) val resultsAfterConsume = vaultService.queryBy(consumedCriteria, paging) assertThat(resultsAfterConsume.states).hasSize(1) @@ -214,8 +204,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + val result = vaultService.queryBy() assertThat(result.states).hasSize(3) @@ -229,8 +218,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + val criteria = VaultQueryCriteria() // default is UNCONSUMED val result = vaultService.queryBy(criteria) @@ -252,8 +240,7 @@ class VaultQueryTests { val consumedStateRefs = spentStates.consumed.map { it.ref }.toList() val producedStateRefs = spentStates.produced.map { it.ref }.toList() stateRefs.addAll(consumedStateRefs.plus(producedStateRefs)) - } - database.transaction { + val sortAttribute = SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF) val criteria = VaultQueryCriteria() val results = vaultService.queryBy(criteria, Sort(setOf(Sort.SortColumn(sortAttribute, Sort.Direction.ASC)))) @@ -280,8 +267,7 @@ class VaultQueryTests { database.transaction { services.consumeCash(10.DOLLARS, notary = DUMMY_NOTARY).consumed.forEach { consumed += it.ref.txhash } services.consumeCash(10.DOLLARS, notary = DUMMY_NOTARY).consumed.forEach { consumed += it.ref.txhash } - } - database.transaction { + val sortAttributeTxnId = SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_TXN_ID) val sortAttributeIndex = SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_INDEX) val sortBy = Sort(setOf(Sort.SortColumn(sortAttributeTxnId, Sort.Direction.ASC), @@ -301,13 +287,11 @@ class VaultQueryTests { @Test fun `unconsumed states for state refs`() { - val stateRefs = - database.transaction { - services.fillWithSomeTestLinearStates(8) - val issuedStates = services.fillWithSomeTestLinearStates(2) - issuedStates.states.map { it.ref }.toList() - } database.transaction { + services.fillWithSomeTestLinearStates(8) + val issuedStates = services.fillWithSomeTestLinearStates(2) + val stateRefs = issuedStates.states.map { it.ref }.toList() + // DOCSTART VaultQueryExample2 val sortAttribute = SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_TXN_ID) val criteria = VaultQueryCriteria(stateRefs = listOf(stateRefs.first(), stateRefs.last())) @@ -328,8 +312,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + // default State.Status is UNCONSUMED // DOCSTART VaultQueryExample3 val criteria = VaultQueryCriteria(contractStateTypes = setOf(Cash.State::class.java, DealState::class.java)) @@ -350,8 +333,7 @@ class VaultQueryTests { services.consumeLinearStates(linearStates.states.toList(), DUMMY_NOTARY) services.consumeDeals(dealStates.states.filter { it.state.data.linearId.externalId == "456" }, DUMMY_NOTARY) services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) - } - database.transaction { + val criteria = VaultQueryCriteria(status = Vault.StateStatus.CONSUMED) val results = vaultService.queryBy(criteria) assertThat(results.states).hasSize(5) @@ -365,18 +347,15 @@ class VaultQueryTests { services.fillWithSomeTestCash(25.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(25.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(25.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - val paging = PageSpecification(DEFAULT_PAGE_NUM, 10) - database.transaction { + + val paging = PageSpecification(DEFAULT_PAGE_NUM, 10) val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) val resultsBeforeConsume = vaultService.queryBy(criteria, paging) assertThat(resultsBeforeConsume.states).hasSize(4) assertThat(resultsBeforeConsume.totalStatesAvailable).isEqualTo(4) - } - database.transaction { + services.consumeCash(75.DOLLARS, notary = DUMMY_NOTARY) - } - database.transaction { + val consumedCriteria = VaultQueryCriteria(status = Vault.StateStatus.CONSUMED) val resultsAfterConsume = vaultService.queryBy(consumedCriteria, paging) assertThat(resultsAfterConsume.states).hasSize(3) @@ -395,8 +374,7 @@ class VaultQueryTests { services.consumeLinearStates(linearStates.states.toList(), DUMMY_NOTARY) services.consumeDeals(dealStates.states.filter { it.state.data.linearId.externalId == "456" }, DUMMY_NOTARY) services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) // generates a new change state! - } - database.transaction { + val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) val results = vaultService.queryBy(criteria) assertThat(results.states).hasSize(17) @@ -407,18 +385,16 @@ class VaultQueryTests { fun `all states with count`() { database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) - val paging = PageSpecification(DEFAULT_PAGE_NUM, 10) - database.transaction { + + val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) + val paging = PageSpecification(DEFAULT_PAGE_NUM, 10) + val resultsBeforeConsume = vaultService.queryBy(criteria, paging) assertThat(resultsBeforeConsume.states).hasSize(1) assertThat(resultsBeforeConsume.totalStatesAvailable).isEqualTo(1) - } - database.transaction { + services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) // consumed 100 (spent), produced 50 (change) - } - database.transaction { + val resultsAfterConsume = vaultService.queryBy(criteria, paging) assertThat(resultsAfterConsume.states).hasSize(2) assertThat(resultsAfterConsume.totalStatesAvailable).isEqualTo(2) @@ -431,8 +407,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, CASH_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + // DOCSTART VaultQueryExample4 val criteria = VaultQueryCriteria(notary = listOf(CASH_NOTARY)) val results = vaultService.queryBy(criteria) @@ -449,8 +424,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(2, "TEST", participants = listOf(MEGA_CORP, MINI_CORP)) services.fillWithSomeTestDeals(listOf("456"), participants = listOf(MEGA_CORP, BIG_CORP)) services.fillWithSomeTestDeals(listOf("123", "789"), participants = listOf(BIG_CORP)) - } - database.transaction { + val criteria = LinearStateQueryCriteria(participants = listOf(BIG_CORP)) val results = vaultService.queryBy(criteria) assertThat(results.states).hasSize(3) @@ -465,8 +439,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(2, "TEST", participants = listOf(MEGA_CORP, MINI_CORP)) services.fillWithSomeTestDeals(listOf("456"), participants = listOf(MEGA_CORP, BIG_CORP)) services.fillWithSomeTestDeals(listOf("123", "789"), participants = listOf(MEGA_CORP)) - } - database.transaction { + // DOCSTART VaultQueryExample5 val criteria = LinearStateQueryCriteria(participants = listOf(BIG_CORP, MINI_CORP)) val results = vaultService.queryBy(criteria) @@ -478,17 +451,14 @@ class VaultQueryTests { @Test fun `unconsumed states with soft locking`() { - val (lockId1, lockId2) = - database.transaction { - val issuedStates = services.fillWithSomeTestCash(100.DOLLARS, notaryServices, CASH_NOTARY, 10, 10, Random(0L)).states.toList() - vaultService.softLockReserve(UUID.randomUUID(), NonEmptySet.of(issuedStates[1].ref, issuedStates[2].ref, issuedStates[3].ref)) - val lockId1 = UUID.randomUUID() - vaultService.softLockReserve(lockId1, NonEmptySet.of(issuedStates[4].ref, issuedStates[5].ref)) - val lockId2 = UUID.randomUUID() - vaultService.softLockReserve(lockId2, NonEmptySet.of(issuedStates[6].ref)) - Pair(lockId1, lockId2) - } database.transaction { + val issuedStates = services.fillWithSomeTestCash(100.DOLLARS, notaryServices, CASH_NOTARY, 10, 10, Random(0L)).states.toList() + vaultService.softLockReserve(UUID.randomUUID(), NonEmptySet.of(issuedStates[1].ref, issuedStates[2].ref, issuedStates[3].ref)) + val lockId1 = UUID.randomUUID() + vaultService.softLockReserve(lockId1, NonEmptySet.of(issuedStates[4].ref, issuedStates[5].ref)) + val lockId2 = UUID.randomUUID() + vaultService.softLockReserve(lockId2, NonEmptySet.of(issuedStates[6].ref)) + // excluding soft locked states val criteriaExclusive = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_ONLY)) val resultsExclusive = vaultService.queryBy(criteriaExclusive) @@ -528,8 +498,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.equal(GBP.currencyCode) } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -543,8 +512,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.notEqual(GBP.currencyCode) } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -558,8 +526,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(1.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(10.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.greaterThan(1000L) } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -573,8 +540,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(1.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(10.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.greaterThanOrEqual(1000L) } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -588,8 +554,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(1.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(10.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.lessThan(1000L) } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -603,8 +568,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(1.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(10.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.lessThanOrEqual(1000L) } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -618,8 +582,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(1.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(10.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::pennies.between(500L, 1500L) } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -633,8 +596,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val currencies = listOf(CHF.currencyCode, GBP.currencyCode) val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.`in`(currencies) } val criteria = VaultCustomQueryCriteria(logicalExpression) @@ -649,8 +611,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val currencies = listOf(CHF.currencyCode, GBP.currencyCode) val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.notIn(currencies) } val criteria = VaultCustomQueryCriteria(logicalExpression) @@ -665,8 +626,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.like("%BP") } // GPB val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -680,8 +640,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.notLike("%BP") } // GPB val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -695,8 +654,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::issuerPartyHash.isNull() } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -710,8 +668,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val logicalExpression = builder { CashSchemaV1.PersistentCashState::issuerPartyHash.notNull() } val criteria = VaultCustomQueryCriteria(logicalExpression) val results = vaultService.queryBy(criteria) @@ -727,8 +684,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(300.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestCash(400.POUNDS, notaryServices, DUMMY_NOTARY, 4, 4, Random(0L)) services.fillWithSomeTestCash(500.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 5, 5, Random(0L)) - } - database.transaction { + // DOCSTART VaultQueryExample21 val sum = builder { CashSchemaV1.PersistentCashState::pennies.sum() } val sumCriteria = VaultCustomQueryCriteria(sum) @@ -769,8 +725,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(300.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestCash(400.POUNDS, notaryServices, DUMMY_NOTARY, 4, 4, Random(0L)) services.fillWithSomeTestCash(500.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 5, 5, Random(0L)) - } - database.transaction { + // DOCSTART VaultQueryExample22 val sum = builder { CashSchemaV1.PersistentCashState::pennies.sum(groupByColumns = listOf(CashSchemaV1.PersistentCashState::currency)) } val sumCriteria = VaultCustomQueryCriteria(sum) @@ -821,8 +776,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(200.DOLLARS, notaryServices, DUMMY_NOTARY, 2, 2, Random(0L), issuedBy = BOC.ref(1)) services.fillWithSomeTestCash(300.POUNDS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L), issuedBy = DUMMY_CASH_ISSUER) services.fillWithSomeTestCash(400.POUNDS, notaryServices, DUMMY_NOTARY, 4, 4, Random(0L), issuedBy = BOC.ref(2)) - } - database.transaction { + // DOCSTART VaultQueryExample23 val sum = builder { CashSchemaV1.PersistentCashState::pennies.sum(groupByColumns = listOf(CashSchemaV1.PersistentCashState::issuerPartyHash, @@ -859,8 +813,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(2, "JKL") services.fillWithSomeTestLinearStates(3, "ABC") services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + // count fungible assets val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() } val countCriteria = QueryCriteria.VaultCustomQueryCriteria(count) @@ -879,18 +832,16 @@ class VaultQueryTests { @Test fun `aggregate functions count by contract type and state status`() { - val (linearStatesJKL, linearStatesXYZ, dealStates) = - database.transaction { - // create new states - services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 10, 10, Random(0L)) - val linearStatesXYZ = services.fillWithSomeTestLinearStates(1, "XYZ") - val linearStatesJKL = services.fillWithSomeTestLinearStates(2, "JKL") - services.fillWithSomeTestLinearStates(3, "ABC") - val dealStates = services.fillWithSomeTestDeals(listOf("123", "456", "789")) - Triple(linearStatesJKL, linearStatesXYZ, dealStates) - } - val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() } database.transaction { + // create new states + services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 10, 10, Random(0L)) + val linearStatesXYZ = services.fillWithSomeTestLinearStates(1, "XYZ") + val linearStatesJKL = services.fillWithSomeTestLinearStates(2, "JKL") + services.fillWithSomeTestLinearStates(3, "ABC") + val dealStates = services.fillWithSomeTestDeals(listOf("123", "456", "789")) + + val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() } + // count fungible assets val countCriteria = QueryCriteria.VaultCustomQueryCriteria(count, Vault.StateStatus.ALL) val fungibleStateCount = vaultService.queryBy>(countCriteria).otherResults.single() as Long @@ -903,18 +854,15 @@ class VaultQueryTests { // count deal states val dealStateCount = vaultService.queryBy(countCriteria).otherResults.single() as Long assertThat(dealStateCount).isEqualTo(3L) - } - val cashUpdates = - database.transaction { - // consume some states - services.consumeLinearStates(linearStatesXYZ.states.toList(), DUMMY_NOTARY) - services.consumeLinearStates(linearStatesJKL.states.toList(), DUMMY_NOTARY) - services.consumeDeals(dealStates.states.filter { it.state.data.linearId.externalId == "456" }, DUMMY_NOTARY) - services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) - // UNCONSUMED states (default) - } - database.transaction { + // consume some states + services.consumeLinearStates(linearStatesXYZ.states.toList(), DUMMY_NOTARY) + services.consumeLinearStates(linearStatesJKL.states.toList(), DUMMY_NOTARY) + services.consumeDeals(dealStates.states.filter { it.state.data.linearId.externalId == "456" }, DUMMY_NOTARY) + val cashUpdates = services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) + + // UNCONSUMED states (default) + // count fungible assets val countCriteriaUnconsumed = QueryCriteria.VaultCustomQueryCriteria(count, Vault.StateStatus.UNCONSUMED) val fungibleStateCountUnconsumed = vaultService.queryBy>(countCriteriaUnconsumed).otherResults.single() as Long @@ -951,8 +899,7 @@ class VaultQueryTests { fun `unconsumed states recorded between two time intervals`() { database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, CASH_NOTARY, 3, 3, Random(0L)) - } - database.transaction { + // DOCSTART VaultQueryExample6 val start = TODAY val end = TODAY.plus(30, ChronoUnit.DAYS) @@ -982,8 +929,7 @@ class VaultQueryTests { } database.transaction { services.consumeCash(100.DOLLARS, notary = DUMMY_NOTARY) - } - database.transaction { + val asOfDateTime = TODAY val consumedAfterExpression = TimeCondition( QueryCriteria.TimeInstantType.CONSUMED, ColumnPredicate.BinaryComparison(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL, asOfDateTime)) @@ -1000,8 +946,7 @@ class VaultQueryTests { fun `all states with paging specification - first page`() { database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 100, 100, Random(0L)) - } - database.transaction { + // DOCSTART VaultQueryExample7 val pagingSpec = PageSpecification(DEFAULT_PAGE_NUM, 10) val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) @@ -1017,8 +962,7 @@ class VaultQueryTests { fun `all states with paging specification - last`() { database.transaction { services.fillWithSomeTestCash(95.DOLLARS, notaryServices, DUMMY_NOTARY, 95, 95, Random(0L)) - } - database.transaction { + // Last page implies we need to perform a row count for the Query first, // and then re-query for a given offset defined by (count - pageSize) val pagingSpec = PageSpecification(10, 10) @@ -1038,8 +982,7 @@ class VaultQueryTests { database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 100, 100, Random(0L)) - } - database.transaction { + val pagingSpec = PageSpecification(0, 10) val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) @@ -1055,8 +998,7 @@ class VaultQueryTests { database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 100, 100, Random(0L)) - } - database.transaction { + @Suppress("EXPECTED_CONDITION") val pagingSpec = PageSpecification(DEFAULT_PAGE_NUM, @Suppress("INTEGER_OVERFLOW") MAX_PAGE_SIZE + 1) // overflow = -2147483648 val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) @@ -1072,8 +1014,7 @@ class VaultQueryTests { database.transaction { services.fillWithSomeTestCash(201.DOLLARS, notaryServices, DUMMY_NOTARY, 201, 201, Random(0L)) - } - database.transaction { + val criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) vaultService.queryBy(criteria) } @@ -1114,8 +1055,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestCommodity(Amount(100, Commodity.getInstance("FCOJ")!!), notaryServices) services.fillWithSomeTestLinearStates(10) - } - database.transaction { + val results = vaultService.queryBy>() assertThat(results.states).hasSize(4) } @@ -1128,12 +1068,10 @@ class VaultQueryTests { } database.transaction { services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) - } - database.transaction { + services.fillWithSomeTestCommodity(Amount(100, Commodity.getInstance("FCOJ")!!), notaryServices) services.fillWithSomeTestLinearStates(10) - } - database.transaction { + val criteria = VaultQueryCriteria(status = Vault.StateStatus.CONSUMED) val results = vaultService.queryBy>(criteria) assertThat(results.states).hasSize(2) @@ -1145,8 +1083,7 @@ class VaultQueryTests { database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) - } - database.transaction { + val results = vaultService.queryBy() assertThat(results.states).hasSize(3) } @@ -1159,9 +1096,7 @@ class VaultQueryTests { } database.transaction { services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) - } - // should now have x2 CONSUMED + x2 UNCONSUMED (one spent + one change) - database.transaction { + // should now have x2 CONSUMED + x2 UNCONSUMED (one spent + one change) val results = vaultService.queryBy(FungibleAssetQueryCriteria()) assertThat(results.statesMetadata).hasSize(2) assertThat(results.states).hasSize(2) @@ -1175,15 +1110,9 @@ class VaultQueryTests { } database.transaction { services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) - } - val linearStates = - database.transaction { - services.fillWithSomeTestLinearStates(10) - } - database.transaction { + + val linearStates = services.fillWithSomeTestLinearStates(10) services.consumeLinearStates(linearStates.states.toList(), DUMMY_NOTARY) - } - database.transaction { val criteria = VaultQueryCriteria(status = Vault.StateStatus.CONSUMED) val results = vaultService.queryBy(criteria) assertThat(results.states).hasSize(2) @@ -1196,8 +1125,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestLinearStates(10) services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + val results = vaultService.queryBy() assertThat(results.states).hasSize(13) } @@ -1214,8 +1142,7 @@ class VaultQueryTests { services.consumeLinearStates(linearStates.states.toList(), DUMMY_NOTARY) services.consumeDeals(dealStates.states.filter { it.state.data.linearId.externalId == "456" }, DUMMY_NOTARY) services.consumeCash(50.DOLLARS, notary = DUMMY_NOTARY) - } - database.transaction { + val criteria = VaultQueryCriteria(status = Vault.StateStatus.CONSUMED) val results = vaultService.queryBy(criteria) assertThat(results.states).hasSize(3) @@ -1226,11 +1153,9 @@ class VaultQueryTests { @Test fun `unconsumed linear heads for linearId without external Id`() { - val issuedStates = - database.transaction { - services.fillWithSomeTestLinearStates(10) - } database.transaction { + val issuedStates = services.fillWithSomeTestLinearStates(10) + // DOCSTART VaultQueryExample8 val linearIds = issuedStates.states.map { it.state.data.linearId }.toList() val criteria = LinearStateQueryCriteria(linearId = listOf(linearIds.first(), linearIds.last())) @@ -1242,14 +1167,11 @@ class VaultQueryTests { @Test fun `unconsumed linear heads by linearId`() { - val (linearState1, linearState3) = - database.transaction { - val linearState1 = services.fillWithSomeTestLinearStates(1, "ID1") - services.fillWithSomeTestLinearStates(1, "ID2") - val linearState3 = services.fillWithSomeTestLinearStates(1, "ID3") - Pair(linearState1, linearState3) - } database.transaction { + val linearState1 = services.fillWithSomeTestLinearStates(1, "ID1") + services.fillWithSomeTestLinearStates(1, "ID2") + val linearState3 = services.fillWithSomeTestLinearStates(1, "ID3") + val linearIds = listOf(linearState1.states.first().state.data.linearId, linearState3.states.first().state.data.linearId) val criteria = LinearStateQueryCriteria(linearId = linearIds) val results = vaultService.queryBy(criteria) @@ -1259,14 +1181,11 @@ class VaultQueryTests { @Test fun `unconsumed linear heads for linearId by external Id`() { - val (linearState1, linearState3) = - database.transaction { - val linearState1 = services.fillWithSomeTestLinearStates(1, "ID1") - services.fillWithSomeTestLinearStates(1, "ID2") - val linearState3 = services.fillWithSomeTestLinearStates(1, "ID3") - Pair(linearState1, linearState3) - } database.transaction { + val linearState1 = services.fillWithSomeTestLinearStates(1, "ID1") + services.fillWithSomeTestLinearStates(1, "ID2") + val linearState3 = services.fillWithSomeTestLinearStates(1, "ID3") + val externalIds = listOf(linearState1.states.first().state.data.linearId.externalId!!, linearState3.states.first().state.data.linearId.externalId!!) val criteria = LinearStateQueryCriteria(externalId = externalIds) val results = vaultService.queryBy(criteria) @@ -1276,16 +1195,14 @@ class VaultQueryTests { @Test fun `all linear states for a given linear id`() { - val linearId = - database.transaction { - val txns = services.fillWithSomeTestLinearStates(1, "TEST") - val linearState = txns.states.first() - services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference - services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference - services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference - linearState.state.data.linearId - } database.transaction { + val txns = services.fillWithSomeTestLinearStates(1, "TEST") + val linearState = txns.states.first() + services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference + services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference + services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference + val linearId = linearState.state.data.linearId + // should now have 1 UNCONSUMED & 3 CONSUMED state refs for Linear State with "TEST" // DOCSTART VaultQueryExample9 val linearStateCriteria = LinearStateQueryCriteria(linearId = listOf(linearId), status = Vault.StateStatus.ALL) @@ -1298,16 +1215,13 @@ class VaultQueryTests { @Test fun `all linear states for a given id sorted by uuid`() { - val linearStates = - database.transaction { - val txns = services.fillWithSomeTestLinearStates(2, "TEST") - val linearStates = txns.states.toList() - services.evolveLinearStates(linearStates, DUMMY_NOTARY) // consume current and produce new state reference - services.evolveLinearStates(linearStates, DUMMY_NOTARY) // consume current and produce new state reference - services.evolveLinearStates(linearStates, DUMMY_NOTARY) // consume current and produce new state reference - linearStates - } database.transaction { + val txns = services.fillWithSomeTestLinearStates(2, "TEST") + val linearStates = txns.states.toList() + services.evolveLinearStates(linearStates, DUMMY_NOTARY) // consume current and produce new state reference + services.evolveLinearStates(linearStates, DUMMY_NOTARY) // consume current and produce new state reference + services.evolveLinearStates(linearStates, DUMMY_NOTARY) // consume current and produce new state reference + // should now have 1 UNCONSUMED & 3 CONSUMED state refs for Linear State with "TEST" val linearStateCriteria = LinearStateQueryCriteria(uuid = linearStates.map { it.state.data.linearId.id }, status = Vault.StateStatus.ALL) val vaultCriteria = VaultQueryCriteria(status = Vault.StateStatus.ALL) @@ -1325,8 +1239,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, externalId = "111") services.fillWithSomeTestLinearStates(2, externalId = "222") services.fillWithSomeTestLinearStates(3, externalId = "333") - } - database.transaction { + val vaultCriteria = VaultQueryCriteria() val sorting = Sort(setOf(Sort.SortColumn(SortAttribute.Standard(Sort.LinearStateAttribute.EXTERNAL_ID), Sort.Direction.DESC))) @@ -1338,13 +1251,11 @@ class VaultQueryTests { @Test fun `unconsumed deal states sorted`() { - val uid = - database.transaction { - val linearStates = services.fillWithSomeTestLinearStates(10) - services.fillWithSomeTestDeals(listOf("123", "456", "789")) - linearStates.states.first().state.data.linearId.id - } database.transaction { + val linearStates = services.fillWithSomeTestLinearStates(10) + services.fillWithSomeTestDeals(listOf("123", "456", "789")) + val uid = linearStates.states.first().state.data.linearId.id + val linearStateCriteria = LinearStateQueryCriteria(uuid = listOf(uid)) val dealStateCriteria = LinearStateQueryCriteria(externalId = listOf("123", "456", "789")) val compositeCriteria = linearStateCriteria or dealStateCriteria @@ -1363,8 +1274,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, linearString = "111") services.fillWithSomeTestLinearStates(2, linearString = "222") services.fillWithSomeTestLinearStates(3, linearString = "333") - } - database.transaction { + val vaultCriteria = VaultQueryCriteria() val sorting = Sort(setOf(Sort.SortColumn(SortAttribute.Custom(DummyLinearStateSchemaV1.PersistentDummyLinearState::class.java, "linearString"), Sort.Direction.DESC))) @@ -1376,16 +1286,15 @@ class VaultQueryTests { @Test fun `return consumed linear states for a given linear id`() { - val txns = - database.transaction { - val txns = services.fillWithSomeTestLinearStates(1, "TEST") - val linearState = txns.states.first() - val linearState2 = services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference - val linearState3 = services.evolveLinearState(linearState2, DUMMY_NOTARY) // consume current and produce new state reference - services.evolveLinearState(linearState3, DUMMY_NOTARY) // consume current and produce new state reference - txns - } database.transaction { + val txns = services.fillWithSomeTestLinearStates(1, "TEST") + val linearState = txns.states.first() + + val linearState2 =services.evolveLinearState(linearState, DUMMY_NOTARY) // consume current and produce new state reference + val linearState3 = services.evolveLinearState(linearState2, DUMMY_NOTARY) // consume current and produce new state reference + + services.evolveLinearState(linearState3, DUMMY_NOTARY) // consume current and produce new state reference + // should now have 1 UNCONSUMED & 3 CONSUMED state refs for Linear State with "TEST" val linearStateCriteria = LinearStateQueryCriteria(linearId = txns.states.map { it.state.data.linearId }, status = Vault.StateStatus.CONSUMED) val vaultCriteria = VaultQueryCriteria(status = Vault.StateStatus.CONSUMED) @@ -1402,8 +1311,7 @@ class VaultQueryTests { fun `unconsumed deals`() { database.transaction { services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + val results = vaultService.queryBy() assertThat(results.states).hasSize(3) } @@ -1413,8 +1321,7 @@ class VaultQueryTests { fun `unconsumed deals for ref`() { database.transaction { services.fillWithSomeTestDeals(listOf("123", "456", "789")) - } - database.transaction { + // DOCSTART VaultQueryExample10 val criteria = LinearStateQueryCriteria(externalId = listOf("456", "789")) val results = vaultService.queryBy(criteria) @@ -1430,8 +1337,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(2, "TEST") services.fillWithSomeTestDeals(listOf("456")) services.fillWithSomeTestDeals(listOf("123", "789")) - } - database.transaction { + val all = vaultService.queryBy() all.states.forEach { println(it.state) } @@ -1448,8 +1354,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(2, "TEST") services.fillWithSomeTestDeals(listOf("456"), parties) services.fillWithSomeTestDeals(listOf("123", "789")) - } - database.transaction { + // DOCSTART VaultQueryExample11 val criteria = LinearStateQueryCriteria(participants = parties) val results = vaultService.queryBy(criteria) @@ -1470,8 +1375,6 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = BOC.ref(1)) services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = BOC.ref(2)) services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = BOC.ref(3)) - } - database.transaction { val criteria = FungibleAssetQueryCriteria(issuer = listOf(BOC), issuerRef = listOf(BOC.ref(1).reference, BOC.ref(2).reference)) val results = vaultService.queryBy>(criteria) @@ -1493,12 +1396,12 @@ class VaultQueryTests { val chfCashIssuerKey = entropyToKeyPair(BigInteger.valueOf(1003)) val chfCashIssuer = Party(CordaX500Name(organisation = "Swiss Francs Cash Issuer", locality = "Zurich", country = "CH"), chfCashIssuerKey.public).ref(1) val chfCashIssuerServices = MockServices(cordappPackages, chfCashIssuerKey) + database.transaction { services.fillWithSomeTestCash(100.POUNDS, gbpCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = (gbpCashIssuer)) services.fillWithSomeTestCash(100.DOLLARS, usdCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = (usdCashIssuer)) services.fillWithSomeTestCash(100.SWISS_FRANCS, chfCashIssuerServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = (chfCashIssuer)) - } - database.transaction { + val criteria = FungibleAssetQueryCriteria(issuer = listOf(gbpCashIssuer.party, usdCashIssuer.party)) val results = vaultService.queryBy>(criteria) assertThat(results.states).hasSize(2) @@ -1511,8 +1414,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = BOC.ref(1)) services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = MEGA_CORP.ref(0), ownedBy = (MINI_CORP)) - } - database.transaction { + val criteria = FungibleAssetQueryCriteria(owner = listOf(MEGA_CORP)) val results = vaultService.queryBy>(criteria) assertThat(results.states).hasSize(1) // can only be 1 owner of a node (MEGA_CORP in this MockServices setup) @@ -1527,8 +1429,7 @@ class VaultQueryTests { issuedBy = MEGA_CORP.ref(0), ownedBy = (MEGA_CORP)) services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = BOC.ref(0), ownedBy = (MINI_CORP)) // irrelevant to this vault - } - database.transaction { + // DOCSTART VaultQueryExample5.2 val criteria = FungibleAssetQueryCriteria(owner = listOf(MEGA_CORP, BOC)) val results = vaultService.queryBy(criteria) @@ -1546,8 +1447,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) - } - database.transaction { + // DOCSTART VaultQueryExample12 val ccyIndex = builder { CashSchemaV1.PersistentCashState::currency.equal(USD.currencyCode) } val criteria = VaultCustomQueryCriteria(ccyIndex) @@ -1563,8 +1463,7 @@ class VaultQueryTests { database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(200.DOLLARS, notaryServices, DUMMY_NOTARY, 2, 2, Random(0L)) - } - database.transaction { + val sum = builder { CashSchemaV1.PersistentCashState::pennies.sum(groupByColumns = listOf(CashSchemaV1.PersistentCashState::currency)) } val sumCriteria = VaultCustomQueryCriteria(sum) @@ -1588,8 +1487,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(400.POUNDS, notaryServices, DUMMY_NOTARY, 4, 4, Random(0L)) services.fillWithSomeTestCash(500.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 5, 5, Random(0L)) services.fillWithSomeTestCash(600.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 6, 6, Random(0L)) - } - database.transaction { + val ccyIndex = builder { CashSchemaV1.PersistentCashState::pennies.sum(groupByColumns = listOf(CashSchemaV1.PersistentCashState::currency)) } val criteria = VaultCustomQueryCriteria(ccyIndex) val results = vaultService.queryBy>(criteria) @@ -1611,8 +1509,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(25.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(50.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 3, 3, Random(0L)) - } - database.transaction { + // DOCSTART VaultQueryExample13 val fungibleAssetCriteria = FungibleAssetQueryCriteria(quantity = builder { greaterThan(2500L) }) val results = vaultService.queryBy(fungibleAssetCriteria) @@ -1629,8 +1526,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = (DUMMY_CASH_ISSUER)) services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = (BOC.ref(1))) - } - database.transaction { + // DOCSTART VaultQueryExample14 val criteria = FungibleAssetQueryCriteria(issuer = listOf(BOC)) val results = vaultService.queryBy>(criteria) @@ -1647,8 +1543,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(50.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + val ccyIndex = builder { CashSchemaV1.PersistentCashState::currency.equal(GBP.currencyCode) } val customCriteria = VaultCustomQueryCriteria(ccyIndex) val fungibleAssetCriteria = FungibleAssetQueryCriteria(quantity = builder { greaterThan(5000L) }) @@ -1686,8 +1581,7 @@ class VaultQueryTests { notaryServices.addSignature(stx, DUMMY_NOTARY_KEY.public) } services.recordTransactions(commercialPaper2) - } - database.transaction { + val ccyIndex = builder { CommercialPaperSchemaV1.PersistentCommercialPaperState::currency.equal(USD.currencyCode) } val criteria1 = QueryCriteria.VaultCustomQueryCriteria(ccyIndex) @@ -1725,8 +1619,7 @@ class VaultQueryTests { } commercialPaper2.verifyRequiredSignatures() services.recordTransactions(commercialPaper2) - } - database.transaction { + val result = builder { val ccyIndex = CommercialPaperSchemaV1.PersistentCommercialPaperState::currency.equal(USD.currencyCode) @@ -1753,8 +1646,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.SWISS_FRANCS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + // CashSchemaV3 NOT registered with NodeSchemaService val logicalExpression = builder { SampleCashSchemaV3.PersistentCashState::currency.equal(GBP.currencyCode) } val criteria = VaultCustomQueryCriteria(logicalExpression) @@ -1775,8 +1667,7 @@ class VaultQueryTests { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(10.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(1.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) - } - database.transaction { + // DOCSTART VaultQueryExample20 val generalCriteria = VaultQueryCriteria(Vault.StateStatus.ALL) @@ -1808,8 +1699,6 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, "TEST") // 2 unconsumed states with same external ID - } - database.transaction { val recordedBetweenExpression = TimeCondition(TimeInstantType.RECORDED, builder { between(start, end) }) val basicCriteria = VaultQueryCriteria(timeCondition = recordedBetweenExpression) @@ -1825,8 +1714,7 @@ class VaultQueryTests { database.transaction { services.fillWithSomeTestLinearStates(1, "TEST1") services.fillWithSomeTestLinearStates(1, "TEST2") - } - database.transaction { + // 2 unconsumed states with same external ID val externalIdCondition = builder { VaultSchemaV1.VaultLinearStates::externalId.equal("TEST2") } val externalIdCustomCriteria = VaultCustomQueryCriteria(externalIdCondition) @@ -1848,8 +1736,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, "TEST2") sleep(1000) services.fillWithSomeTestLinearStates(1, "TEST3") - } - database.transaction { + // 2 unconsumed states with same external ID val results = builder { @@ -1870,16 +1757,13 @@ class VaultQueryTests { // specifying Query on Linear state attributes @Test fun `unconsumed linear heads for a given external id or uuid`() { - val uuid = - database.transaction { - services.fillWithSomeTestLinearStates(1, "TEST1") - val aState = services.fillWithSomeTestLinearStates(1, "TEST2").states - services.consumeLinearStates(aState.toList(), DUMMY_NOTARY) - services.fillWithSomeTestLinearStates(1, "TEST1").states.first().state.data.linearId.id - - // 2 unconsumed states with same external ID, 1 consumed with different external ID - } database.transaction { + services.fillWithSomeTestLinearStates(1, "TEST1") + val aState = services.fillWithSomeTestLinearStates(1, "TEST2").states + services.consumeLinearStates(aState.toList(), DUMMY_NOTARY) + val uuid = services.fillWithSomeTestLinearStates(1, "TEST1").states.first().state.data.linearId.id + + // 2 unconsumed states with same external ID, 1 consumed with different external ID val results = builder { val externalIdCondition = VaultSchemaV1.VaultLinearStates::externalId.equal("TEST1") val externalIdCustomCriteria = VaultCustomQueryCriteria(externalIdCondition) @@ -1902,8 +1786,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, "TEST1", listOf(ALICE)) services.fillWithSomeTestLinearStates(1) services.fillWithSomeTestLinearStates(1, "TEST3") - } - database.transaction { + val linearStateCriteria = LinearStateQueryCriteria(participants = listOf(ALICE)) val results = vaultService.queryBy(linearStateCriteria) @@ -1922,8 +1805,7 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, "TEST1", listOf(ALICE, BOB, CHARLIE)) services.fillWithSomeTestLinearStates(1) services.fillWithSomeTestLinearStates(1, "TEST3") - } - database.transaction { + val linearStateCriteria = LinearStateQueryCriteria(participants = listOf(ALICE, BOB, CHARLIE)) val results = vaultService.queryBy(linearStateCriteria) @@ -1940,8 +1822,6 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, "TEST3") // 3 unconsumed states (one without an external ID) - } - database.transaction { val results = builder { val externalIdCondition = VaultSchemaV1.VaultLinearStates::externalId.isNull() val externalIdCustomCriteria = VaultCustomQueryCriteria(externalIdCondition) @@ -1960,8 +1840,6 @@ class VaultQueryTests { services.fillWithSomeTestLinearStates(1, "TEST3") // 3 unconsumed states (two with an external ID) - } - database.transaction { val results = builder { val externalIdCondition = VaultSchemaV1.VaultLinearStates::externalId.notNull() val externalIdCustomCriteria = VaultCustomQueryCriteria(externalIdCondition) @@ -1979,9 +1857,7 @@ class VaultQueryTests { services.fillWithSomeTestCommodity(Amount(100, Commodity.getInstance("FCOJ")!!), notaryServices) services.fillWithSomeTestLinearStates(1, "ABC") services.fillWithSomeTestDeals(listOf("123")) - } - database.transaction { // Base criteria val baseCriteria = VaultQueryCriteria(notary = listOf(DUMMY_NOTARY), status = Vault.StateStatus.CONSUMED)