Improvements to Vault Query Service soft locked state querying (#1174)

* Improvements to Vault Query Service soft locked state querying (removed old mechanism from VaultService).

* Fixed rst document formatting.

* Added additional soft locking criteria mode: all unlocked plus those locked as specified by lockId(s).

* Addressed comments from PR feedback.
This commit is contained in:
josecoll 2017-08-04 17:23:31 +01:00 committed by GitHub
parent 67361188e5
commit bef8630fe0
10 changed files with 131 additions and 71 deletions

View File

@ -274,12 +274,6 @@ interface VaultService {
*/
fun softLockRelease(lockId: UUID, stateRefs: NonEmptySet<StateRef>? = null)
/**
* Retrieve softLockStates for a given [UUID] or return all softLockStates in vault for a given
* [ContractState] type
*/
fun <T : ContractState> softLockedStates(lockId: UUID? = null): List<StateAndRef<T>>
// DOCEND SoftLockAPI
/**

View File

@ -26,6 +26,19 @@ sealed class QueryCriteria {
@CordaSerializable
data class TimeCondition(val type: TimeInstantType, val predicate: ColumnPredicate<Instant>)
// DOCSTART VaultQuerySoftLockingCriteria
@CordaSerializable
data class SoftLockingCondition(val type: SoftLockingType, val lockIds: List<UUID> = emptyList())
@CordaSerializable
enum class SoftLockingType {
UNLOCKED_ONLY, // only unlocked states
LOCKED_ONLY, // only soft locked states
SPECIFIED, // only those soft locked states specified by lock id(s)
UNLOCKED_AND_SPECIFIED // all unlocked states plus those soft locked states specified by lock id(s)
}
// DOCEND VaultQuerySoftLockingCriteria
abstract class CommonQueryCriteria : QueryCriteria() {
abstract val status: Vault.StateStatus
override fun visit(parser: IQueryCriteriaParser): Collection<Predicate> {
@ -40,7 +53,7 @@ sealed class QueryCriteria {
val contractStateTypes: Set<Class<out ContractState>>? = null,
val stateRefs: List<StateRef>? = null,
val notaryName: List<X500Name>? = null,
val includeSoftlockedStates: Boolean = true,
val softLockingCondition: SoftLockingCondition? = null,
val timeCondition: TimeCondition? = null) : CommonQueryCriteria() {
override fun visit(parser: IQueryCriteriaParser): Collection<Predicate> {
return parser.parseCriteria(this as CommonQueryCriteria).plus(parser.parseCriteria(this))

View File

@ -56,7 +56,7 @@ There are four implementations of this interface which can be chained together t
1. ``VaultQueryCriteria`` provides filterable criteria on attributes within the Vault states table: status (UNCONSUMED, CONSUMED), state reference(s), contract state type(s), notaries, soft locked states, timestamps (RECORDED, CONSUMED).
.. note:: Sensible defaults are defined for frequently used attributes (status = UNCONSUMED, includeSoftlockedStates = true).
.. note:: Sensible defaults are defined for frequently used attributes (status = UNCONSUMED, always include soft locked states).
2. ``FungibleAssetQueryCriteria`` provides filterable criteria on attributes defined in the Corda Core ``FungibleAsset`` contract state interface, used to represent assets that are fungible, countable and issued by a specific party (eg. ``Cash.State`` and ``CommodityContract.State`` in the Corda finance module). Filterable attributes include: participants(s), owner(s), quantity, issuer party(s) and issuer reference(s).

View File

@ -81,6 +81,12 @@ UNRELEASED
dealing with ``StateAndRef``s.
* Vault query soft locking enhancements and deprecations
* removed original ``VaultService`` ``softLockedStates` query mechanism.
* introduced improved ``SoftLockingCondition`` filterable attribute in ``VaultQueryCriteria`` to enable specification
of different soft locking retrieval behaviours (exclusive of soft locked states, soft locked states only, specified
by set of lock ids)
Milestone 13
------------

View File

@ -22,13 +22,15 @@ query soft locks associated with states as required by their CorDapp application
:start-after: DOCSTART SoftLockAPI
:end-before: DOCEND SoftLockAPI
You can also control whether soft locked states are retrieved in general vault queries by setting an optional boolean
`includeSoftLockedStates` flag (which is set to *true* by default)
Query
-----
By default vault queries will always include locked states in its result sets.
Custom filterable criteria can be specified using the ``SoftLockingCondition`` attribute of ``VaultQueryCriteria``:
.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/node/services/VaultService.kt
:language: kotlin
:start-after: DOCSTART VaultStatesQuery
:end-before: DOCEND VaultStatesQuery
.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/node/services/vault/QueryCriteria.kt
:language: kotlin
:start-after: DOCSTART VaultQuerySoftLockingCriteria
:end-before: DOCEND VaultQuerySoftLockingCriteria
Explicit Usage
--------------

View File

@ -48,8 +48,25 @@ class HibernateQueryCriteriaParser(val contractType: Class<out ContractState>,
predicateSet.add(criteriaBuilder.and(vaultStates.get<String>("contractStateClassName").`in`(contractTypes)))
// soft locking
if (!criteria.includeSoftlockedStates)
predicateSet.add(criteriaBuilder.and(vaultStates.get<String>("lockId").isNull))
criteria.softLockingCondition?.let {
val softLocking = criteria.softLockingCondition
val type = softLocking!!.type
when(type) {
QueryCriteria.SoftLockingType.UNLOCKED_ONLY ->
predicateSet.add(criteriaBuilder.and(vaultStates.get<String>("lockId").isNull))
QueryCriteria.SoftLockingType.LOCKED_ONLY ->
predicateSet.add(criteriaBuilder.and(vaultStates.get<String>("lockId").isNotNull))
QueryCriteria.SoftLockingType.UNLOCKED_AND_SPECIFIED -> {
require(softLocking.lockIds.isNotEmpty()) { "Must specify one or more lockIds" }
predicateSet.add(criteriaBuilder.or(vaultStates.get<String>("lockId").isNull,
vaultStates.get<String>("lockId").`in`(softLocking.lockIds.map { it.toString() })))
}
QueryCriteria.SoftLockingType.SPECIFIED -> {
require(softLocking.lockIds.isNotEmpty()) { "Must specify one or more lockIds" }
predicateSet.add(criteriaBuilder.and(vaultStates.get<String>("lockId").`in`(softLocking.lockIds.map { it.toString() })))
}
}
}
// notary names
criteria.notaryName?.let {

View File

@ -430,26 +430,6 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P
return stateAndRefs
}
override fun <T : ContractState> softLockedStates(lockId: UUID?): List<StateAndRef<T>> {
val stateAndRefs =
session.withTransaction(transactionIsolationLevel) {
val query = select(VaultSchema.VaultStates::class)
.where(VaultSchema.VaultStates::stateStatus eq Vault.StateStatus.UNCONSUMED)
.and(VaultSchema.VaultStates::contractStateClassName eq Cash.State::class.java.name)
if (lockId != null)
query.and(VaultSchema.VaultStates::lockId eq lockId)
else
query.and(VaultSchema.VaultStates::lockId.notNull())
query.get()
.map { it ->
val stateRef = StateRef(SecureHash.parse(it.txId), it.index)
val state = it.contractState.deserialize<TransactionState<T>>(context = STORAGE_CONTEXT)
StateAndRef(state, stateRef)
}.toList()
}
return stateAndRefs
}
/**
* Generate a transaction that moves an amount of currency to the given pubkey.
*

View File

@ -12,6 +12,7 @@ import net.corda.core.node.services.Vault
import net.corda.core.node.services.VaultQueryService
import net.corda.core.node.services.VaultService
import net.corda.core.node.services.queryBy
import net.corda.core.node.services.vault.QueryCriteria.*
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
import net.corda.core.transactions.NotaryChangeWireTransaction
import net.corda.core.transactions.SignedTransaction
@ -132,22 +133,24 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
vaultSvc.softLockReserve(softLockId, stateRefsToSoftLock)
// all softlocked states
assertThat(vaultSvc.softLockedStates<Cash.State>()).hasSize(2)
val criteriaLocked = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.LOCKED_ONLY))
assertThat(vaultQuery.queryBy<Cash.State>(criteriaLocked).states).hasSize(2)
// my softlocked states
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId)).hasSize(2)
val criteriaByLockId = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(softLockId)))
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId).states).hasSize(2)
// excluding softlocked states
val unlockedStates1 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(includeSoftlockedStates = false)).states
val unlockedStates1 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_ONLY))).states
assertThat(unlockedStates1).hasSize(1)
// soft lock release one of the states explicitly
vaultSvc.softLockRelease(softLockId, NonEmptySet.of(unconsumedStates[1].ref))
val unlockedStates2 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(includeSoftlockedStates = false)).states
val unlockedStates2 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_ONLY))).states
assertThat(unlockedStates2).hasSize(2)
// soft lock release the rest by id
vaultSvc.softLockRelease(softLockId)
val unlockedStates = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(includeSoftlockedStates = false)).states
val unlockedStates = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_ONLY))).states
assertThat(unlockedStates).hasSize(3)
// should be back to original states
@ -157,13 +160,15 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
@Test
fun `soft locking attempt concurrent reserve`() {
val backgroundExecutor = Executors.newFixedThreadPool(2)
val countDown = CountDownLatch(2)
val softLockId1 = UUID.randomUUID()
val softLockId2 = UUID.randomUUID()
val criteriaByLockId1 = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(softLockId1)))
val criteriaByLockId2 = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(softLockId2)))
val vaultStates =
database.transaction {
assertEquals(0.DOLLARS, services.getCashBalance(USD))
@ -177,7 +182,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
try {
database.transaction {
vaultSvc.softLockReserve(softLockId1, stateRefsToSoftLock)
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId1)).hasSize(3)
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId1).states).hasSize(3)
}
println("SOFT LOCK STATES #1 succeeded")
} catch(e: Throwable) {
@ -193,7 +198,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
Thread.sleep(100) // let 1st thread soft lock them 1st
database.transaction {
vaultSvc.softLockReserve(softLockId2, stateRefsToSoftLock)
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId2)).hasSize(3)
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId2).states).hasSize(3)
}
println("SOFT LOCK STATES #2 succeeded")
} catch(e: Throwable) {
@ -205,10 +210,10 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
countDown.await()
database.transaction {
val lockStatesId1 = vaultSvc.softLockedStates<Cash.State>(softLockId1)
val lockStatesId1 = vaultQuery.queryBy<Cash.State>(criteriaByLockId1).states
println("SOFT LOCK #1 final states: $lockStatesId1")
assertThat(lockStatesId1.size).isIn(0, 3)
val lockStatesId2 = vaultSvc.softLockedStates<Cash.State>(softLockId2)
val lockStatesId2 = vaultQuery.queryBy<Cash.State>(criteriaByLockId2).states
println("SOFT LOCK #2 final states: $lockStatesId2")
assertThat(lockStatesId2.size).isIn(0, 3)
}
@ -216,7 +221,6 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
@Test
fun `soft locking partial reserve states fails`() {
val softLockId1 = UUID.randomUUID()
val softLockId2 = UUID.randomUUID()
@ -231,7 +235,8 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
// lock 1st state with LockId1
database.transaction {
vaultSvc.softLockReserve(softLockId1, NonEmptySet.of(stateRefsToSoftLock.first()))
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId1)).hasSize(1)
val criteriaByLockId1 = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(softLockId1)))
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId1).states).hasSize(1)
}
// attempt to lock all 3 states with LockId2
@ -244,8 +249,8 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
@Test
fun `attempt to lock states already soft locked by me`() {
val softLockId1 = UUID.randomUUID()
val criteriaByLockId1 = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(softLockId1)))
val vaultStates =
database.transaction {
@ -258,13 +263,13 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
// lock states with LockId1
database.transaction {
vaultSvc.softLockReserve(softLockId1, stateRefsToSoftLock)
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId1)).hasSize(3)
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId1).states).hasSize(3)
}
// attempt to relock same states with LockId1
database.transaction {
vaultSvc.softLockReserve(softLockId1, stateRefsToSoftLock)
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId1)).hasSize(3)
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId1).states).hasSize(3)
}
}
@ -272,6 +277,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
fun `lock additional states to some already soft locked by me`() {
val softLockId1 = UUID.randomUUID()
val criteriaByLockId1 = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(softLockId1)))
val vaultStates =
database.transaction {
@ -284,13 +290,13 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
// lock states with LockId1
database.transaction {
vaultSvc.softLockReserve(softLockId1, NonEmptySet.of(stateRefsToSoftLock.first()))
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId1)).hasSize(1)
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId1).states).hasSize(1)
}
// attempt to lock all states with LockId1 (including previously already locked one)
database.transaction {
vaultSvc.softLockReserve(softLockId1, stateRefsToSoftLock.toNonEmptySet())
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId1)).hasSize(3)
assertThat(vaultQuery.queryBy<Cash.State>(criteriaByLockId1).states).hasSize(3)
}
}
@ -307,7 +313,8 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
spendableStatesUSD.forEach(::println)
assertThat(spendableStatesUSD).hasSize(1)
assertThat(spendableStatesUSD[0].state.data.amount.quantity).isEqualTo(100L * 100)
assertThat(vaultSvc.softLockedStates<Cash.State>()).hasSize(1)
val criteriaLocked = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.LOCKED_ONLY))
assertThat(vaultQuery.queryBy<Cash.State>(criteriaLocked).states).hasSize(1)
}
}
@ -360,7 +367,8 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
val spendableStatesUSD = (vaultSvc as NodeVaultService).unconsumedStatesForSpending<Cash.State>(110.DOLLARS, lockId = UUID.randomUUID())
spendableStatesUSD.forEach(::println)
assertThat(spendableStatesUSD).hasSize(1)
assertThat(vaultSvc.softLockedStates<Cash.State>()).hasSize(0)
val criteriaLocked = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.LOCKED_ONLY))
assertThat(vaultQuery.queryBy<Cash.State>(criteriaLocked).states).hasSize(0)
}
}
@ -377,7 +385,8 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
spendableStatesUSD.forEach(::println)
assertThat(spendableStatesUSD).hasSize(1)
assertThat(spendableStatesUSD[0].state.data.amount.quantity).isGreaterThanOrEqualTo(100L)
assertThat(vaultSvc.softLockedStates<Cash.State>()).hasSize(1)
val criteriaLocked = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.LOCKED_ONLY))
assertThat(vaultQuery.queryBy<Cash.State>(criteriaLocked).states).hasSize(1)
}
}
@ -397,7 +406,8 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
spendableStatesUSD.forEach(::println)
}
// note only 3 spend attempts succeed with a total of 8 states
assertThat(vaultSvc.softLockedStates<Cash.State>()).hasSize(8)
val criteriaLocked = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.LOCKED_ONLY))
assertThat(vaultQuery.queryBy<Cash.State>(criteriaLocked).states).hasSize(8)
}
}

View File

@ -127,6 +127,9 @@ class VaultQueryTests : TestDependencyInjectionBase() {
return props
}
@get:Rule
val expectedEx = ExpectedException.none()!!
/**
* Query API tests
*/
@ -460,15 +463,46 @@ class VaultQueryTests : TestDependencyInjectionBase() {
}
@Test
fun `unconsumed states excluding soft locks`() {
fun `unconsumed states with soft locking`() {
database.transaction {
val issuedStates = services.fillWithSomeTestCash(100.DOLLARS, CASH_NOTARY, 3, 3, Random(0L))
vaultSvc.softLockReserve(UUID.randomUUID(), NonEmptySet.of(issuedStates.states.first().ref, issuedStates.states.last().ref))
val issuedStates = services.fillWithSomeTestCash(100.DOLLARS, CASH_NOTARY, 10, 10, Random(0L)).states.toList()
vaultSvc.softLockReserve(UUID.randomUUID(), NonEmptySet.of(issuedStates[1].ref, issuedStates[2].ref, issuedStates[3].ref))
val lockId1 = UUID.randomUUID()
vaultSvc.softLockReserve(lockId1, NonEmptySet.of(issuedStates[4].ref, issuedStates[5].ref))
val lockId2 = UUID.randomUUID()
vaultSvc.softLockReserve(lockId2, NonEmptySet.of(issuedStates[6].ref))
val criteria = VaultQueryCriteria(includeSoftlockedStates = false)
val results = vaultQuerySvc.queryBy<ContractState>(criteria)
assertThat(results.states).hasSize(1)
// excluding soft locked states
val criteriaExclusive = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_ONLY))
val resultsExclusive = vaultQuerySvc.queryBy<ContractState>(criteriaExclusive)
assertThat(resultsExclusive.states).hasSize(4)
// only soft locked states
val criteriaLockedOnly = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.LOCKED_ONLY))
val resultsLockedOnly = vaultQuerySvc.queryBy<ContractState>(criteriaLockedOnly)
assertThat(resultsLockedOnly.states).hasSize(6)
// soft locked states by single lock id
val criteriaByLockId = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(lockId1)))
val resultsByLockId = vaultQuerySvc.queryBy<ContractState>(criteriaByLockId)
assertThat(resultsByLockId.states).hasSize(2)
// soft locked states by multiple lock ids
val criteriaByLockIds = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.SPECIFIED, listOf(lockId1, lockId2)))
val resultsByLockIds = vaultQuerySvc.queryBy<ContractState>(criteriaByLockIds)
assertThat(resultsByLockIds.states).hasSize(3)
// unlocked and locked by `lockId2`
val criteriaUnlockedAndByLockId = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_AND_SPECIFIED, listOf(lockId2)))
val resultsUnlockedAndByLockIds = vaultQuerySvc.queryBy<ContractState>(criteriaUnlockedAndByLockId)
assertThat(resultsUnlockedAndByLockIds.states).hasSize(5)
// missing lockId
expectedEx.expect(IllegalArgumentException::class.java)
expectedEx.expectMessage("Must specify one or more lockIds")
val criteriaMissingLockId = VaultQueryCriteria(softLockingCondition = SoftLockingCondition(SoftLockingType.UNLOCKED_AND_SPECIFIED))
vaultQuerySvc.queryBy<ContractState>(criteriaMissingLockId)
}
}
@ -980,9 +1014,6 @@ class VaultQueryTests : TestDependencyInjectionBase() {
}
}
@get:Rule
val expectedEx = ExpectedException.none()!!
// pagination: invalid page number
@Test
fun `invalid page number`() {

View File

@ -9,6 +9,7 @@ import net.corda.core.node.services.Vault
import net.corda.core.node.services.VaultQueryService
import net.corda.core.node.services.VaultService
import net.corda.core.node.services.queryBy
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
@ -128,6 +129,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
@Test
fun `issue and attempt double spend`() {
val freshKey = services.keyManagementService.freshKey()
val criteriaLocked = VaultQueryCriteria(softLockingCondition = QueryCriteria.SoftLockingCondition(QueryCriteria.SoftLockingType.LOCKED_ONLY))
database.transaction {
// A tx that sends us money.
@ -138,11 +140,12 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
println("Cash balance: ${services.getCashBalance(USD)}")
assertThat(vaultQuery.queryBy<Cash.State>().states).hasSize(10)
assertThat(vault.softLockedStates<Cash.State>()).hasSize(0)
assertThat(vaultQuery.queryBy<Cash.State>(criteriaLocked).states).hasSize(0)
}
val backgroundExecutor = Executors.newFixedThreadPool(2)
val countDown = CountDownLatch(2)
// 1st tx that spends our money.
backgroundExecutor.submit {
database.transaction {
@ -154,19 +157,21 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
println("txn1: ${txn1.id} spent ${((txn1.tx.outputs[0].data) as Cash.State).amount}")
val unconsumedStates1 = vaultQuery.queryBy<Cash.State>()
val consumedStates1 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(status = Vault.StateStatus.CONSUMED))
val lockedStates1 = vaultQuery.queryBy<Cash.State>(criteriaLocked).states
println("""txn1 states:
UNCONSUMED: ${unconsumedStates1.totalStatesAvailable} : $unconsumedStates1,
CONSUMED: ${consumedStates1.totalStatesAvailable} : $consumedStates1,
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
LOCKED: ${lockedStates1.count()} : $lockedStates1
""")
services.recordTransactions(txn1)
println("txn1: Cash balance: ${services.getCashBalance(USD)}")
val unconsumedStates2 = vaultQuery.queryBy<Cash.State>()
val consumedStates2 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(status = Vault.StateStatus.CONSUMED))
val lockedStates2 = vaultQuery.queryBy<Cash.State>(criteriaLocked).states
println("""txn1 states:
UNCONSUMED: ${unconsumedStates2.totalStatesAvailable} : $unconsumedStates2,
CONSUMED: ${consumedStates2.totalStatesAvailable} : $consumedStates2,
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
LOCKED: ${lockedStates2.count()} : $lockedStates2
""")
txn1
} catch(e: Exception) {
@ -188,19 +193,21 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
println("txn2: ${txn2.id} spent ${((txn2.tx.outputs[0].data) as Cash.State).amount}")
val unconsumedStates1 = vaultQuery.queryBy<Cash.State>()
val consumedStates1 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(status = Vault.StateStatus.CONSUMED))
val lockedStates1 = vaultQuery.queryBy<Cash.State>(criteriaLocked).states
println("""txn2 states:
UNCONSUMED: ${unconsumedStates1.totalStatesAvailable} : $unconsumedStates1,
CONSUMED: ${consumedStates1.totalStatesAvailable} : $consumedStates1,
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
LOCKED: ${lockedStates1.count()} : $lockedStates1
""")
services.recordTransactions(txn2)
println("txn2: Cash balance: ${services.getCashBalance(USD)}")
val unconsumedStates2 = vaultQuery.queryBy<Cash.State>()
val consumedStates2 = vaultQuery.queryBy<Cash.State>()
val lockedStates2 = vaultQuery.queryBy<Cash.State>(criteriaLocked).states
println("""txn2 states:
UNCONSUMED: ${unconsumedStates2.totalStatesAvailable} : $unconsumedStates2,
CONSUMED: ${consumedStates2.totalStatesAvailable} : $consumedStates2,
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
LOCKED: ${lockedStates2.count()} : $lockedStates2
""")
txn2
} catch(e: Exception) {