mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Updated samples and demos to use new Vault Query service. (#924)
* Updated all sample code to use new Vault Query service APIs. * Fix broken Unit test. * Added missing transaction boundary. * Fix broken ScheduledFlow test (caused by assertion on non-ordered collection) * Remove redundant negative test (as new Vault Query no longer returns iterators). * Whitespace formatting fixed following PR review from SA. * Force query to specify a PAGE SIZE equivalent to total states to be exited (RP review comment). * Use single (and fail fast) instead of first - when only expecting a single result. * Demonstrate paging and sorting; failfast on single expected result. * Enhancement: added Sorting by CommonStateAttribute (StateRef txnId and index) * Fix: incorrect total states count. * Fixed incorrect total states counting. * Remove redundant filter (UNCONSUMED). * Updated tutorial code and associated documentation (building transactions). * Updated all vaultAndUpdates to vault[Track|Query]By. * Temporary disable failing Vault Query tests (awaiting pagination PR fix). * Rebase from master to pick up pagination changes/fix. * Fixed criteria filter on track. * Cleanup redundant print output. * Refactor to extract common function for Vault Query paging and sorting. * Identified problem in SimmValuation demo failing test caused by query by single participant in participants list (not yet supported in VaultQuery criteria). * Minor fixes following rebase from master. * Minor updates following rebase. * Removed redundant import. * Fixed type casting error. * Minor fixes following rebase from master. * VQ Fix - applied in other PR. * Removed duplication after rebase and minor fix to failing smoke test.
This commit is contained in:
parent
73528d287d
commit
64ba8d3a88
@ -5,15 +5,13 @@ import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.client.rpc.CordaRPCClientConfiguration
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.StateMachineInfo
|
||||
import net.corda.core.messaging.StateMachineTransactionMapping
|
||||
import net.corda.core.messaging.StateMachineUpdate
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.vault.*
|
||||
import net.corda.core.utilities.seconds
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.seconds
|
||||
import rx.Observable
|
||||
import rx.subjects.PublishSubject
|
||||
|
||||
@ -84,9 +82,10 @@ class NodeMonitorModel {
|
||||
val currentStateMachines = stateMachines.map { StateMachineUpdate.Added(it) }
|
||||
stateMachineUpdates.startWith(currentStateMachines).subscribe(stateMachineUpdatesSubject)
|
||||
|
||||
// Vault updates
|
||||
val (vault, vaultUpdates) = proxy.vaultAndUpdates()
|
||||
val initialVaultUpdate = Vault.Update(setOf(), vault.toSet())
|
||||
// Vault snapshot (force single page load with MAX_PAGE_SIZE) + updates
|
||||
val (vaultSnapshot, vaultUpdates) = proxy.vaultTrackBy<ContractState>(QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL),
|
||||
PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE))
|
||||
val initialVaultUpdate = Vault.Update(setOf(), vaultSnapshot.states.toSet())
|
||||
vaultUpdates.startWith(initialVaultUpdate).subscribe(vaultUpdatesSubject)
|
||||
|
||||
// Transactions
|
||||
|
@ -135,33 +135,10 @@ class StandaloneCordaRPClientTest {
|
||||
assertEquals(1, updateCount.get())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test vault`() {
|
||||
val (vault, vaultUpdates) = rpcProxy.vaultAndUpdates()
|
||||
assertEquals(0, vault.size)
|
||||
|
||||
val updateCount = AtomicInteger(0)
|
||||
vaultUpdates.subscribe { update ->
|
||||
log.info("Vault>> FlowId=${update.flowId}")
|
||||
updateCount.incrementAndGet()
|
||||
}
|
||||
|
||||
// Now issue some cash
|
||||
rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNode.legalIdentity, notaryNode.notaryIdentity)
|
||||
.returnValue.getOrThrow(timeout)
|
||||
assertNotEquals(0, updateCount.get())
|
||||
|
||||
// Check that this cash exists in the vault
|
||||
val cashState = rpcProxy.vaultQueryBy<Cash.State>(QueryCriteria.FungibleAssetQueryCriteria()).states.single()
|
||||
log.info("Cash State: $cashState")
|
||||
|
||||
assertEquals(629.POUNDS, cashState.state.data.amount.withoutIssuer())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test vault track by`() {
|
||||
val (vault, vaultUpdates) = rpcProxy.vaultTrackBy<Cash.State>()
|
||||
assertEquals(0, vault.states.size)
|
||||
val (vault, vaultUpdates) = rpcProxy.vaultTrackBy<Cash.State>(paging = PageSpecification(DEFAULT_PAGE_NUM))
|
||||
assertEquals(0, vault.totalStatesAvailable)
|
||||
|
||||
val updateCount = AtomicInteger(0)
|
||||
vaultUpdates.subscribe { update ->
|
||||
|
@ -9,11 +9,11 @@ import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.internal.Emoji
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.node.internal.CordaRPCOpsImpl
|
||||
import net.corda.node.services.startFlowPermission
|
||||
@ -178,14 +178,14 @@ class ContractUpgradeFlowTest {
|
||||
mockNet.runNetwork()
|
||||
val stx = result.getOrThrow().stx
|
||||
val stateAndRef = stx.tx.outRef<Cash.State>(0)
|
||||
val baseState = a.database.transaction { a.services.vaultService.unconsumedStates<ContractState>().single() }
|
||||
val baseState = a.database.transaction { a.services.vaultQueryService.queryBy<ContractState>().states.single() }
|
||||
assertTrue(baseState.state.data is Cash.State, "Contract state is old version.")
|
||||
// Starts contract upgrade flow.
|
||||
val upgradeResult = a.services.startFlow(ContractUpgradeFlow(stateAndRef, CashV2::class.java)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
upgradeResult.getOrThrow()
|
||||
// Get contract state from the vault.
|
||||
val firstState = a.database.transaction { a.services.vaultService.unconsumedStates<ContractState>().single() }
|
||||
val firstState = a.database.transaction { a.services.vaultQueryService.queryBy<ContractState>().states.single() }
|
||||
assertTrue(firstState.state.data is CashV2.State, "Contract state is upgraded to the new version.")
|
||||
assertEquals(Amount(1000000, USD).`issued by`(a.info.legalIdentity.ref(1)), (firstState.state.data as CashV2.State).amount, "Upgraded cash contain the correct amount.")
|
||||
assertEquals<Collection<AbstractParty>>(listOf(a.info.legalIdentity), (firstState.state.data as CashV2.State).owners, "Upgraded cash belongs to the right owner.")
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultTrackBy
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
@ -59,9 +60,8 @@ class IntegrationTestingTutorial {
|
||||
// END 2
|
||||
|
||||
// START 3
|
||||
val criteria = QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.ALL)
|
||||
val (_, bobVaultUpdates) = bobProxy.vaultTrackByCriteria<Cash.State>(Cash.State::class.java, criteria)
|
||||
val (_, aliceVaultUpdates) = aliceProxy.vaultTrackByCriteria<Cash.State>(Cash.State::class.java, criteria)
|
||||
val bobVaultUpdates = bobProxy.vaultTrackBy<Cash.State>().updates
|
||||
val aliceVaultUpdates = aliceProxy.vaultTrackBy<Cash.State>().updates
|
||||
// END 3
|
||||
|
||||
// START 4
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.USD
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -105,10 +106,10 @@ fun main(args: Array<String>) {
|
||||
|
||||
// START 6
|
||||
fun generateTransactions(proxy: CordaRPCOps) {
|
||||
val (vault, vaultUpdates) = proxy.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
val vault = proxy.vaultQueryBy<Cash.State>().states
|
||||
|
||||
var ownedQuantity = vault.fold(0L) { sum, state ->
|
||||
sum + (state.state.data as Cash.State).amount.quantity
|
||||
sum + state.state.data.amount.quantity
|
||||
}
|
||||
val issueRef = OpaqueBytes.of(0)
|
||||
val (parties, partyUpdates) = proxy.networkMapFeed()
|
||||
|
@ -10,13 +10,14 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.core.node.services.vault.builder
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.schemas.CashSchemaV1
|
||||
import java.util.*
|
||||
|
||||
@CordaSerializable
|
||||
@ -36,18 +37,18 @@ private data class FxResponse(val inputs: List<StateAndRef<Cash.State>>,
|
||||
private fun gatherOurInputs(serviceHub: ServiceHub,
|
||||
amountRequired: Amount<Issued<Currency>>,
|
||||
notary: Party?): Pair<List<StateAndRef<Cash.State>>, Long> {
|
||||
// Collect cash type inputs
|
||||
val queryCriteria = QueryCriteria.VaultQueryCriteria(Vault.StateStatus.UNCONSUMED, setOf(Cash.State::class.java))
|
||||
val cashStates = serviceHub.vaultQueryService.queryBy<Cash.State>(queryCriteria).states
|
||||
// extract our identity for convenience
|
||||
val ourKeys = serviceHub.keyManagementService.keys
|
||||
// Filter down to our own cash states with right currency and issuer
|
||||
val suitableCashStates = cashStates.filter {
|
||||
val state = it.state.data
|
||||
// TODO: We may want to have the list of our states pre-cached somewhere for performance
|
||||
(state.owner.owningKey in ourKeys) && (state.amount.token == amountRequired.token)
|
||||
}
|
||||
val ourParties = ourKeys.map { serviceHub.identityService.partyFromKey(it) ?: throw IllegalStateException("Unable to resolve party from key") }
|
||||
val fungibleCriteria = QueryCriteria.FungibleAssetQueryCriteria(owner = ourParties)
|
||||
|
||||
val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.equal(amountRequired.token.product.currencyCode) }
|
||||
val cashCriteria = QueryCriteria.VaultCustomQueryCriteria(logicalExpression)
|
||||
|
||||
// Collect cash type inputs
|
||||
val suitableCashStates = serviceHub.vaultQueryService.queryBy<Cash.State>(fungibleCriteria.and(cashCriteria)).states
|
||||
require(!suitableCashStates.isEmpty()) { "Insufficient funds" }
|
||||
|
||||
var remaining = amountRequired.quantity
|
||||
// We will need all of the inputs to be on the same notary.
|
||||
// For simplicity we just filter on the first notary encountered
|
||||
|
@ -12,7 +12,9 @@ import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.linearHeadsOfType
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -21,15 +23,6 @@ import net.corda.core.utilities.seconds
|
||||
import net.corda.core.utilities.unwrap
|
||||
import java.security.PublicKey
|
||||
|
||||
// DOCSTART 1
|
||||
// Helper method to locate the latest Vault version of a LinearState from a possibly out of date StateRef
|
||||
inline fun <reified T : LinearState> ServiceHub.latest(ref: StateRef): StateAndRef<T> {
|
||||
val linearHeads = vaultService.linearHeadsOfType<T>()
|
||||
val original = toStateAndRef<T>(ref)
|
||||
return linearHeads[original.state.data.linearId]!!
|
||||
}
|
||||
// DOCEND 1
|
||||
|
||||
// Minimal state model of a manual approval process
|
||||
@CordaSerializable
|
||||
enum class WorkflowState {
|
||||
@ -150,8 +143,11 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow
|
||||
|
||||
@Suspendable
|
||||
override fun call(): StateAndRef<TradeApprovalContract.State> {
|
||||
// Pull in the latest Vault version of the StateRef as a full StateAndRef
|
||||
val latestRecord = serviceHub.latest<TradeApprovalContract.State>(ref)
|
||||
// DOCSTART 1
|
||||
val criteria = VaultQueryCriteria(stateRefs = listOf(ref))
|
||||
val latestRecord = serviceHub.vaultQueryService.queryBy<TradeApprovalContract.State>(criteria).states.single()
|
||||
// DOCEND 1
|
||||
|
||||
// Check the protocol hasn't already been run
|
||||
require(latestRecord.ref == ref) {
|
||||
"Input trade $ref is not latest version $latestRecord"
|
||||
|
@ -38,7 +38,6 @@ class FxTransactionBuildTutorialTest {
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
println("Close DB")
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
|
||||
|
@ -26,10 +26,9 @@ class WorkflowTransactionBuildTutorialTest {
|
||||
lateinit var nodeA: MockNetwork.MockNode
|
||||
lateinit var nodeB: MockNetwork.MockNode
|
||||
|
||||
// Helper method to locate the latest Vault version of a LinearState from a possibly out of date StateRef
|
||||
// Helper method to locate the latest Vault version of a LinearState
|
||||
private inline fun <reified T : LinearState> ServiceHub.latest(ref: UniqueIdentifier): StateAndRef<T> {
|
||||
val linearHeads = vaultQueryService.queryBy<T>(QueryCriteria.LinearStateQueryCriteria(linearId = listOf(ref))
|
||||
.and(QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.UNCONSUMED)))
|
||||
val linearHeads = vaultQueryService.queryBy<T>(QueryCriteria.LinearStateQueryCriteria(linearId = listOf(ref)))
|
||||
return linearHeads.states.single()
|
||||
}
|
||||
|
||||
@ -48,7 +47,6 @@ class WorkflowTransactionBuildTutorialTest {
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
println("Close DB")
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ One of the first steps to forming a transaction is gathering the set of
|
||||
input references. This process will clearly vary according to the nature
|
||||
of the business process being captured by the smart contract and the
|
||||
parameterised details of the request. However, it will generally involve
|
||||
searching the Vault via the ``VaultService`` interface on the
|
||||
searching the Vault via the ``VaultQueryService`` interface on the
|
||||
``ServiceHub`` to locate the input states.
|
||||
|
||||
To give a few more specific details consider two simplified real world
|
||||
@ -111,16 +111,16 @@ part of a simulated in-memory network of nodes.
|
||||
to the VM options, and set Working directory to ``$PROJECT_DIR$``
|
||||
so that the ``Quasar`` instrumentation is correctly configured.
|
||||
|
||||
For the Cash transaction let’s assume the cash resources are using the
|
||||
standard ``CashState`` in the ``:financial`` Gradle module. The Cash
|
||||
contract uses ``FungibleAsset`` states to model holdings of
|
||||
interchangeable assets and allow the split/merge and summing of
|
||||
states to meet a contractual obligation. We would normally use the
|
||||
``generateSpend`` method on the ``VaultService`` to gather the required
|
||||
amount of cash into a ``TransactionBuilder``, set the outputs and move
|
||||
command. However, to elucidate more clearly example flow code is shown
|
||||
here that will manually carry out the inputs queries using the lower
|
||||
level ``VaultService``.
|
||||
For the Cash transaction let’s assume the cash resources are using the
|
||||
standard ``CashState`` in the ``:financial`` Gradle module. The Cash
|
||||
contract uses ``FungibleAsset`` states to model holdings of
|
||||
interchangeable assets and allow the split/merge and summing of
|
||||
states to meet a contractual obligation. We would normally use the
|
||||
``generateSpend`` method on the ``VaultService`` to gather the required
|
||||
amount of cash into a ``TransactionBuilder``, set the outputs and move
|
||||
command. However, to elucidate more clearly example flow code is shown
|
||||
here that will manually carry out the inputs queries by specifying relevant
|
||||
query criteria filters to the ``queryBy`` method of the ``VaultQueryService``.
|
||||
|
||||
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt
|
||||
:language: kotlin
|
||||
@ -159,21 +159,14 @@ workflows will query the Vault for states of the right contract type and
|
||||
in the right workflow state over the RPC interface. The RPC will then
|
||||
initiate the relevant flow using ``StateRef``, or ``linearId`` values as
|
||||
parameters to the flow to identify the states being operated upon. Thus
|
||||
code to gather the latest input state would be:
|
||||
code to gather the latest input state for a given ``StateRef`` would use
|
||||
the ``VaultQueryService`` as follows:
|
||||
|
||||
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt
|
||||
:language: kotlin
|
||||
:start-after: DOCSTART 1
|
||||
:end-before: DOCEND 1
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
// Pull in the latest Vault version of the StateRef as a full StateAndRef
|
||||
val latestRecord = serviceHub.latest<TradeApprovalContract.State>(ref)
|
||||
|
||||
|
||||
Generating Commands
|
||||
-------------------
|
||||
|
||||
|
@ -15,9 +15,7 @@ import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.TokenizableAssetInfo
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.node.services.VaultService
|
||||
import net.corda.core.node.services.linearHeadsOfType
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import java.math.BigDecimal
|
||||
|
@ -7,8 +7,12 @@ import net.corda.core.contracts.InsufficientBalanceException
|
||||
import net.corda.core.contracts.issuedBy
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.DEFAULT_PAGE_NUM
|
||||
import net.corda.core.node.services.vault.PageSpecification
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import java.util.*
|
||||
|
||||
@ -47,13 +51,9 @@ class CashExitFlow(val amount: Amount<Currency>, val issueRef: OpaqueBytes, prog
|
||||
throw CashException("Exiting more cash than exists", e)
|
||||
}
|
||||
|
||||
// Work out who the owners of the burnt states were
|
||||
val inputStatesNullable = serviceHub.vaultService.statesForRefs(builder.inputStates())
|
||||
val inputStates = inputStatesNullable.values.filterNotNull().map { it.data }
|
||||
if (inputStatesNullable.size != inputStates.size) {
|
||||
val unresolvedStateRefs = inputStatesNullable.filter { it.value == null }.map { it.key }
|
||||
throw IllegalStateException("Failed to resolve input StateRefs: $unresolvedStateRefs")
|
||||
}
|
||||
// Work out who the owners of the burnt states were (specify page size so we don't silently drop any if > DEFAULT_PAGE_SIZE)
|
||||
val inputStates = serviceHub.vaultQueryService.queryBy<Cash.State>(VaultQueryCriteria(stateRefs = builder.inputStates()),
|
||||
PageSpecification(pageNumber = DEFAULT_PAGE_NUM, pageSize = builder.inputStates().size)).states
|
||||
|
||||
// TODO: Is it safe to drop participants we don't know how to contact? Does not knowing how to contact them
|
||||
// count as a reason to fail?
|
||||
|
@ -6,12 +6,16 @@ import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.VaultQueryService
|
||||
import net.corda.core.node.services.VaultService
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.node.services.database.HibernateConfiguration
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.node.services.vault.HibernateVaultQueryImpl
|
||||
import net.corda.node.services.vault.NodeVaultService
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
@ -54,6 +58,7 @@ class CashTests : TestDependencyInjectionBase() {
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties())
|
||||
database.transaction {
|
||||
val hibernateConfig = HibernateConfiguration(NodeSchemaService(), makeTestDatabaseProperties())
|
||||
miniCorpServices = object : MockServices(MINI_CORP_KEY) {
|
||||
override val keyManagementService: MockKeyManagementService = MockKeyManagementService(identityService, MINI_CORP_KEY, MEGA_CORP_KEY, OUR_KEY)
|
||||
override val vaultService: VaultService = makeVaultService(dataSourceProps)
|
||||
@ -65,6 +70,7 @@ class CashTests : TestDependencyInjectionBase() {
|
||||
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
|
||||
vaultService.notifyAll(txs.map { it.tx })
|
||||
}
|
||||
override val vaultQueryService : VaultQueryService = HibernateVaultQueryImpl(hibernateConfig, vaultService.updatesPublisher)
|
||||
}
|
||||
|
||||
miniCorpServices.fillWithSomeTestCash(howMuch = 100.DOLLARS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
@ -76,7 +82,7 @@ class CashTests : TestDependencyInjectionBase() {
|
||||
miniCorpServices.fillWithSomeTestCash(howMuch = 80.SWISS_FRANCS, atLeastThisManyStates = 1, atMostThisManyStates = 1,
|
||||
issuedBy = MINI_CORP.ref(1), issuerKey = MINI_CORP_KEY, ownedBy = OUR_IDENTITY_1)
|
||||
|
||||
vaultStatesUnconsumed = miniCorpServices.vaultService.unconsumedStates<Cash.State>().toList()
|
||||
vaultStatesUnconsumed = miniCorpServices.vaultQueryService.queryBy<Cash.State>().states
|
||||
}
|
||||
resetTestSerialization()
|
||||
}
|
||||
|
@ -176,21 +176,21 @@ class HibernateQueryCriteriaParser(val contractType: Class<out ContractState>,
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
column as Path<Long?>?
|
||||
val aggregateExpression =
|
||||
when (columnPredicate.type) {
|
||||
AggregateFunctionType.SUM -> criteriaBuilder.sum(column)
|
||||
AggregateFunctionType.AVG -> criteriaBuilder.avg(column)
|
||||
AggregateFunctionType.COUNT -> criteriaBuilder.count(column)
|
||||
AggregateFunctionType.MAX -> criteriaBuilder.max(column)
|
||||
AggregateFunctionType.MIN -> criteriaBuilder.min(column)
|
||||
}
|
||||
when (columnPredicate.type) {
|
||||
AggregateFunctionType.SUM -> criteriaBuilder.sum(column)
|
||||
AggregateFunctionType.AVG -> criteriaBuilder.avg(column)
|
||||
AggregateFunctionType.COUNT -> criteriaBuilder.count(column)
|
||||
AggregateFunctionType.MAX -> criteriaBuilder.max(column)
|
||||
AggregateFunctionType.MIN -> criteriaBuilder.min(column)
|
||||
}
|
||||
aggregateExpressions.add(aggregateExpression)
|
||||
// optionally order by this aggregate function
|
||||
expression.orderBy?.let {
|
||||
val orderCriteria =
|
||||
when (expression.orderBy!!) {
|
||||
Sort.Direction.ASC -> criteriaBuilder.asc(aggregateExpression)
|
||||
Sort.Direction.DESC -> criteriaBuilder.desc(aggregateExpression)
|
||||
}
|
||||
when (expression.orderBy!!) {
|
||||
Sort.Direction.ASC -> criteriaBuilder.asc(aggregateExpression)
|
||||
Sort.Direction.DESC -> criteriaBuilder.desc(aggregateExpression)
|
||||
}
|
||||
criteriaQuery.orderBy(orderCriteria)
|
||||
}
|
||||
// add optional group by clauses
|
||||
@ -374,10 +374,10 @@ class HibernateQueryCriteriaParser(val contractType: Class<out ContractState>,
|
||||
}
|
||||
|
||||
val selections =
|
||||
if (aggregateExpressions.isEmpty())
|
||||
listOf(vaultStates).plus(rootEntities.map { it.value })
|
||||
else
|
||||
aggregateExpressions
|
||||
if (aggregateExpressions.isEmpty())
|
||||
listOf(vaultStates).plus(rootEntities.map { it.value })
|
||||
else
|
||||
aggregateExpressions
|
||||
criteriaQuery.multiselect(selections)
|
||||
val combinedPredicates = joinPredicates.plus(predicateSet)
|
||||
criteriaQuery.where(*combinedPredicates.toTypedArray())
|
||||
@ -439,21 +439,21 @@ class HibernateQueryCriteriaParser(val contractType: Class<out ContractState>,
|
||||
|
||||
private fun parse(sortAttribute: Sort.Attribute): Triple<Class<out PersistentState>, String, String?> {
|
||||
val entityClassAndColumnName : Triple<Class<out PersistentState>, String, String?> =
|
||||
when(sortAttribute) {
|
||||
is Sort.CommonStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultStates::class.java, sortAttribute.attributeParent, sortAttribute.attributeChild)
|
||||
when(sortAttribute) {
|
||||
is Sort.CommonStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultStates::class.java, sortAttribute.attributeParent, sortAttribute.attributeChild)
|
||||
}
|
||||
is Sort.VaultStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultStates::class.java, sortAttribute.attributeName, null)
|
||||
}
|
||||
is Sort.LinearStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultLinearStates::class.java, sortAttribute.attributeName, null)
|
||||
}
|
||||
is Sort.FungibleStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultFungibleStates::class.java, sortAttribute.attributeName, null)
|
||||
}
|
||||
else -> throw VaultQueryException("Invalid sort attribute: $sortAttribute")
|
||||
}
|
||||
is Sort.VaultStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultStates::class.java, sortAttribute.attributeName, null)
|
||||
}
|
||||
is Sort.LinearStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultLinearStates::class.java, sortAttribute.attributeName, null)
|
||||
}
|
||||
is Sort.FungibleStateAttribute -> {
|
||||
Triple(VaultSchemaV1.VaultFungibleStates::class.java, sortAttribute.attributeName, null)
|
||||
}
|
||||
else -> throw VaultQueryException("Invalid sort attribute: $sortAttribute")
|
||||
}
|
||||
return entityClassAndColumnName
|
||||
}
|
||||
}
|
@ -102,6 +102,7 @@ class HibernateVaultQueryImpl(hibernateConfig: HibernateConfiguration,
|
||||
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())
|
||||
}
|
||||
|
@ -11,9 +11,9 @@ import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.internal.CordaRPCOpsImpl
|
||||
@ -88,7 +88,7 @@ class CordaRPCOpsImplTest {
|
||||
|
||||
// Check the monitoring service wallet is empty
|
||||
aliceNode.database.transaction {
|
||||
assertFalse(aliceNode.services.vaultService.unconsumedStates<ContractState>().iterator().hasNext())
|
||||
assertFalse(aliceNode.services.vaultQueryService.queryBy<ContractState>().totalStatesAvailable > 0)
|
||||
}
|
||||
|
||||
// Tell the monitoring service node to issue some cash
|
||||
|
@ -7,12 +7,18 @@ import net.corda.core.flows.*
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.linearHeadsOfType
|
||||
import net.corda.core.node.services.VaultQueryService
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.DEFAULT_PAGE_NUM
|
||||
import net.corda.core.node.services.vault.PageSpecification
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
|
||||
import net.corda.core.node.services.vault.Sort
|
||||
import net.corda.core.node.services.vault.SortAttribute
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.node.services.network.NetworkMapService
|
||||
import net.corda.node.services.statemachine.StateMachineManager
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import org.junit.After
|
||||
@ -114,10 +120,10 @@ class ScheduledFlowTests {
|
||||
nodeA.services.startFlow(InsertInitialStateFlow(nodeB.info.legalIdentity))
|
||||
mockNet.waitQuiescent()
|
||||
val stateFromA = nodeA.database.transaction {
|
||||
nodeA.services.vaultService.linearHeadsOfType<ScheduledState>().values.first()
|
||||
nodeA.services.vaultQueryService.queryBy<ScheduledState>().states.single()
|
||||
}
|
||||
val stateFromB = nodeB.database.transaction {
|
||||
nodeB.services.vaultService.linearHeadsOfType<ScheduledState>().values.first()
|
||||
nodeB.services.vaultQueryService.queryBy<ScheduledState>().states.single()
|
||||
}
|
||||
assertEquals(1, countScheduledFlows)
|
||||
assertEquals(stateFromA, stateFromB, "Must be same copy on both nodes")
|
||||
@ -132,14 +138,31 @@ class ScheduledFlowTests {
|
||||
nodeB.services.startFlow(InsertInitialStateFlow(nodeA.info.legalIdentity))
|
||||
}
|
||||
mockNet.waitQuiescent()
|
||||
|
||||
val statesFromA = nodeA.database.transaction {
|
||||
nodeA.services.vaultService.linearHeadsOfType<ScheduledState>()
|
||||
queryStatesWithPaging(nodeA.services.vaultQueryService)
|
||||
}
|
||||
val statesFromB = nodeB.database.transaction {
|
||||
nodeB.services.vaultService.linearHeadsOfType<ScheduledState>()
|
||||
queryStatesWithPaging(nodeB.services.vaultQueryService)
|
||||
}
|
||||
assertEquals(2 * N, statesFromA.count(), "Expect all states to be present")
|
||||
assertEquals(statesFromA, statesFromB, "Expect identical data on both nodes")
|
||||
assertTrue("Expect all states have run the scheduled task", statesFromB.values.all { it.state.data.processed })
|
||||
assertTrue("Expect all states have run the scheduled task", statesFromB.all { it.state.data.processed })
|
||||
}
|
||||
|
||||
// Demonstrate Vault Query paging and sorting
|
||||
val PAGE_SIZE = 20
|
||||
val sorting = Sort(listOf(Sort.SortColumn(SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_TXN_ID), Sort.Direction.DESC)))
|
||||
|
||||
private fun queryStatesWithPaging(vaultQueryService: VaultQueryService): List<StateAndRef<ScheduledState>> {
|
||||
var pageNumber = DEFAULT_PAGE_NUM
|
||||
val states = mutableListOf<StateAndRef<ScheduledState>>()
|
||||
do {
|
||||
val pageSpec = PageSpecification(pageSize = PAGE_SIZE, pageNumber = pageNumber)
|
||||
val results = vaultQueryService.queryBy<ScheduledState>(VaultQueryCriteria(), pageSpec, sorting)
|
||||
states.addAll(results.states)
|
||||
pageNumber++
|
||||
} while ((pageSpec.pageSize * (pageNumber)) <= results.totalStatesAvailable)
|
||||
return states.toList()
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.node.services.NotifyTransactionHandler
|
||||
@ -56,12 +56,12 @@ class DataVendingServiceTests {
|
||||
// Complete the cash transaction, and then manually relay it
|
||||
val tx = registerNode.services.signInitialTransaction(ptx)
|
||||
vaultServiceNode.database.transaction {
|
||||
assertThat(vaultServiceNode.services.vaultService.unconsumedStates<Cash.State>()).isEmpty()
|
||||
assertThat(vaultServiceNode.services.vaultQueryService.queryBy<Cash.State>().states.isEmpty())
|
||||
|
||||
registerNode.sendNotifyTx(tx, vaultServiceNode)
|
||||
|
||||
// Check the transaction is in the receiving node
|
||||
val actual = vaultServiceNode.services.vaultService.unconsumedStates<Cash.State>().singleOrNull()
|
||||
val actual = vaultServiceNode.services.vaultQueryService.queryBy<Cash.State>().states.singleOrNull()
|
||||
val expected = tx.tx.outRef<Cash.State>(0)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
@ -86,12 +86,12 @@ class DataVendingServiceTests {
|
||||
// The transaction tries issuing MEGA_CORP cash, but we aren't the issuer, so it's invalid
|
||||
val tx = registerNode.services.signInitialTransaction(ptx)
|
||||
vaultServiceNode.database.transaction {
|
||||
assertThat(vaultServiceNode.services.vaultService.unconsumedStates<Cash.State>()).isEmpty()
|
||||
assertThat(vaultServiceNode.services.vaultQueryService.queryBy<Cash.State>().states.isEmpty())
|
||||
|
||||
registerNode.sendNotifyTx(tx, vaultServiceNode)
|
||||
|
||||
// Check the transaction is not in the receiving node
|
||||
assertThat(vaultServiceNode.services.vaultService.unconsumedStates<Cash.State>()).isEmpty()
|
||||
assertThat(vaultServiceNode.services.vaultQueryService.queryBy<Cash.State>().states.isEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,9 @@ package net.corda.node.services.statemachine
|
||||
import co.paralleluniverse.fibers.Fiber
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.random63BitValue
|
||||
import net.corda.core.flatMap
|
||||
@ -19,7 +17,6 @@ import net.corda.core.messaging.MessageRecipients
|
||||
import net.corda.core.node.services.PartyInfo
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.toFuture
|
||||
@ -597,13 +594,6 @@ class FlowFrameworkTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `lazy db iterator left on stack during checkpointing`() {
|
||||
val result = node2.services.startFlow(VaultAccessFlow()).resultFuture
|
||||
mockNet.runNetwork()
|
||||
assertThatThrownBy { result.getOrThrow() }.hasMessageContaining("Vault").hasMessageContaining("private method")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `verify vault query service is tokenizable by force checkpointing within a flow`() {
|
||||
val ptx = TransactionBuilder(notary = notary1.info.notaryIdentity)
|
||||
@ -917,14 +907,6 @@ class FlowFrameworkTests {
|
||||
}
|
||||
}
|
||||
|
||||
private class VaultAccessFlow : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
serviceHub.vaultService.unconsumedStates<Cash.State>().filter { true }
|
||||
waitForLedgerCommit(SecureHash.zeroHash)
|
||||
}
|
||||
}
|
||||
|
||||
@InitiatingFlow
|
||||
private class VaultQueryFlow(val stx: SignedTransaction, val otherParty: Party) : FlowLogic<List<StateAndRef<ContractState>>>() {
|
||||
@Suspendable
|
||||
|
@ -7,7 +7,12 @@ import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.node.services.StatesNotAvailableException
|
||||
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.VaultQueryCriteria
|
||||
import net.corda.core.transactions.NotaryChangeWireTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
@ -18,13 +23,11 @@ import net.corda.node.services.database.HibernateConfiguration
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.schemas.CommercialPaperSchemaV1
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.contracts.fillWithSomeTestCash
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestDataSourceProperties
|
||||
import net.corda.testing.node.makeTestDatabaseProperties
|
||||
import net.corda.testing.schemas.DummyLinearStateSchemaV1
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.After
|
||||
@ -41,6 +44,7 @@ import kotlin.test.assertTrue
|
||||
class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
lateinit var services: MockServices
|
||||
val vaultSvc: VaultService get() = services.vaultService
|
||||
val vaultQuery: VaultQueryService get() = services.vaultQueryService
|
||||
lateinit var database: CordaPersistence
|
||||
|
||||
@Before
|
||||
@ -49,8 +53,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties())
|
||||
database.transaction {
|
||||
val customSchemas = setOf(CommercialPaperSchemaV1, DummyLinearStateSchemaV1)
|
||||
val hibernateConfig = HibernateConfiguration(NodeSchemaService(customSchemas), makeTestDatabaseProperties())
|
||||
val hibernateConfig = HibernateConfiguration(NodeSchemaService(), makeTestDatabaseProperties())
|
||||
services = object : MockServices() {
|
||||
override val vaultService: VaultService = makeVaultService(dataSourceProps, hibernateConfig)
|
||||
|
||||
@ -61,8 +64,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
|
||||
vaultService.notifyAll(txs.map { it.tx })
|
||||
}
|
||||
|
||||
override val vaultQueryService: VaultQueryService = HibernateVaultQueryImpl(hibernateConfig, vaultService.updatesPublisher)
|
||||
override val vaultQueryService : VaultQueryService = HibernateVaultQueryImpl(hibernateConfig, vaultService.updatesPublisher)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,10 +81,11 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L))
|
||||
|
||||
val w1 = vaultSvc.unconsumedStates<Cash.State>()
|
||||
val w1 = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(w1).hasSize(3)
|
||||
|
||||
val originalVault = vaultSvc
|
||||
val originalVaultQuery = vaultQuery
|
||||
val services2 = object : MockServices() {
|
||||
override val vaultService: VaultService get() = originalVault
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
@ -91,9 +94,10 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
vaultService.notify(stx.tx)
|
||||
}
|
||||
}
|
||||
override val vaultQueryService : VaultQueryService get() = originalVaultQuery
|
||||
}
|
||||
|
||||
val w2 = services2.vaultService.unconsumedStates<Cash.State>()
|
||||
val w2 = services2.vaultQueryService.queryBy<Cash.State>().states
|
||||
assertThat(w2).hasSize(3)
|
||||
}
|
||||
}
|
||||
@ -104,11 +108,10 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L))
|
||||
|
||||
val w1 = vaultSvc.unconsumedStates<Cash.State>().toList()
|
||||
val w1 = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(w1).hasSize(3)
|
||||
|
||||
val stateRefs = listOf(w1[1].ref, w1[2].ref)
|
||||
val states = vaultSvc.statesForRefs(stateRefs)
|
||||
val states = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(stateRefs = listOf(w1[1].ref, w1[2].ref))).states
|
||||
assertThat(states).hasSize(2)
|
||||
}
|
||||
}
|
||||
@ -119,7 +122,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L))
|
||||
|
||||
val unconsumedStates = vaultSvc.unconsumedStates<Cash.State>().toList()
|
||||
val unconsumedStates = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(unconsumedStates).hasSize(3)
|
||||
|
||||
val stateRefsToSoftLock = NonEmptySet.of(unconsumedStates[1].ref, unconsumedStates[2].ref)
|
||||
@ -134,17 +137,17 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
assertThat(vaultSvc.softLockedStates<Cash.State>(softLockId)).hasSize(2)
|
||||
|
||||
// excluding softlocked states
|
||||
val unlockedStates1 = vaultSvc.unconsumedStates<Cash.State>(includeSoftLockedStates = false).toList()
|
||||
val unlockedStates1 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(includeSoftlockedStates = false)).states
|
||||
assertThat(unlockedStates1).hasSize(1)
|
||||
|
||||
// soft lock release one of the states explicitly
|
||||
vaultSvc.softLockRelease(softLockId, NonEmptySet.of(unconsumedStates[1].ref))
|
||||
val unlockedStates2 = vaultSvc.unconsumedStates<Cash.State>(includeSoftLockedStates = false).toList()
|
||||
val unlockedStates2 = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(includeSoftlockedStates = false)).states
|
||||
assertThat(unlockedStates2).hasSize(2)
|
||||
|
||||
// soft lock release the rest by id
|
||||
vaultSvc.softLockRelease(softLockId)
|
||||
val unlockedStates = vaultSvc.unconsumedStates<Cash.State>(includeSoftLockedStates = false).toList()
|
||||
val unlockedStates = vaultQuery.queryBy<Cash.State>(VaultQueryCriteria(includeSoftlockedStates = false)).states
|
||||
assertThat(unlockedStates).hasSize(3)
|
||||
|
||||
// should be back to original states
|
||||
@ -297,7 +300,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 1, 1, Random(0L))
|
||||
|
||||
val unconsumedStates = vaultSvc.unconsumedStates<Cash.State>().toList()
|
||||
val unconsumedStates = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(unconsumedStates).hasSize(1)
|
||||
|
||||
val spendableStatesUSD = (vaultSvc as NodeVaultService).unconsumedStatesForSpending<Cash.State>(100.DOLLARS, lockId = UUID.randomUUID())
|
||||
@ -333,7 +336,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = (BOC.ref(2)), issuerKey = BOC_KEY, ref = OpaqueBytes.of(2))
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 1, 1, Random(0L), issuedBy = (BOC.ref(3)), issuerKey = BOC_KEY, ref = OpaqueBytes.of(3))
|
||||
|
||||
val unconsumedStates = vaultSvc.unconsumedStates<Cash.State>().toList()
|
||||
val unconsumedStates = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(unconsumedStates).hasSize(4)
|
||||
|
||||
val spendableStatesUSD = vaultSvc.unconsumedStatesForSpending<Cash.State>(200.DOLLARS, lockId = UUID.randomUUID(),
|
||||
@ -351,7 +354,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 1, 1, Random(0L))
|
||||
|
||||
val unconsumedStates = vaultSvc.unconsumedStates<Cash.State>().toList()
|
||||
val unconsumedStates = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(unconsumedStates).hasSize(1)
|
||||
|
||||
val spendableStatesUSD = (vaultSvc as NodeVaultService).unconsumedStatesForSpending<Cash.State>(110.DOLLARS, lockId = UUID.randomUUID())
|
||||
@ -367,7 +370,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 2, 2, Random(0L))
|
||||
|
||||
val unconsumedStates = vaultSvc.unconsumedStates<Cash.State>().toList()
|
||||
val unconsumedStates = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(unconsumedStates).hasSize(2)
|
||||
|
||||
val spendableStatesUSD = (vaultSvc as NodeVaultService).unconsumedStatesForSpending<Cash.State>(1.DOLLARS, lockId = UUID.randomUUID())
|
||||
@ -386,7 +389,7 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
|
||||
services.fillWithSomeTestCash(100.POUNDS, DUMMY_NOTARY, 10, 10, Random(0L))
|
||||
services.fillWithSomeTestCash(100.SWISS_FRANCS, DUMMY_NOTARY, 10, 10, Random(0L))
|
||||
|
||||
val allStates = vaultSvc.unconsumedStates<Cash.State>()
|
||||
val allStates = vaultQuery.queryBy<Cash.State>().states
|
||||
assertThat(allStates).hasSize(30)
|
||||
|
||||
for (i in 1..5) {
|
||||
|
@ -1,8 +1,6 @@
|
||||
package net.corda.node.services.vault
|
||||
|
||||
import net.corda.contracts.CommercialPaper
|
||||
import net.corda.contracts.Commodity
|
||||
import net.corda.contracts.DealState
|
||||
import net.corda.contracts.*
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||
import net.corda.core.contracts.*
|
||||
@ -1254,7 +1252,7 @@ class VaultQueryTests : TestDependencyInjectionBase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unconsumed deal states paged and sorted`() {
|
||||
fun `unconsumed deal states sorted`() {
|
||||
database.transaction {
|
||||
|
||||
val linearStates = services.fillWithSomeTestLinearStates(10)
|
||||
@ -1385,6 +1383,28 @@ class VaultQueryTests : TestDependencyInjectionBase() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `DEPRECATED DealState dealsWith helper method`() {
|
||||
database.transaction {
|
||||
|
||||
// specify a different participant to the node owner (MEGA_CORP)
|
||||
val parties = listOf(MINI_CORP)
|
||||
|
||||
services.fillWithSomeTestLinearStates(2, "TEST")
|
||||
services.fillWithSomeTestDeals(listOf("456"), parties)
|
||||
services.fillWithSomeTestDeals(listOf("123", "789"))
|
||||
|
||||
// DOCSTART VaultQueryExample11
|
||||
val criteria = LinearStateQueryCriteria(participants = parties)
|
||||
val results = vaultQuerySvc.queryBy<DealState>(criteria)
|
||||
// DOCEND
|
||||
assertThat(results.states).hasSize(1)
|
||||
|
||||
val states = vaultSvc.dealsWith<DummyDealContract.State>(MINI_CORP)
|
||||
assertThat(states).hasSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deal Contract state to be removed as is duplicate of LinearState
|
||||
*/
|
||||
@ -1834,7 +1854,8 @@ class VaultQueryTests : TestDependencyInjectionBase() {
|
||||
database.transaction {
|
||||
|
||||
services.fillWithSomeTestLinearStates(1, "TEST1")
|
||||
services.fillWithSomeTestLinearStates(1, "TEST2")
|
||||
val aState = services.fillWithSomeTestLinearStates(1, "TEST2").states
|
||||
services.consumeLinearStates(aState.toList())
|
||||
val uuid = services.fillWithSomeTestLinearStates(1, "TEST3").states.first().state.data.linearId.id
|
||||
|
||||
// 2 unconsumed states with same external ID, 1 with different external ID
|
||||
|
@ -5,23 +5,22 @@ import net.corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||
import net.corda.contracts.getCashBalance
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
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.consumedStates
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.node.services.database.HibernateConfiguration
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.schemas.CommercialPaperSchemaV1
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.contracts.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestDataSourceProperties
|
||||
import net.corda.testing.node.makeTestDatabaseProperties
|
||||
import net.corda.testing.schemas.DummyLinearStateSchemaV1
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.After
|
||||
@ -37,6 +36,7 @@ import kotlin.test.assertEquals
|
||||
class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
lateinit var services: MockServices
|
||||
val vault: VaultService get() = services.vaultService
|
||||
val vaultQuery: VaultQueryService get() = services.vaultQueryService
|
||||
lateinit var database: CordaPersistence
|
||||
val notaryServices = MockServices(DUMMY_NOTARY_KEY)
|
||||
|
||||
@ -46,8 +46,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties())
|
||||
database.transaction {
|
||||
val customSchemas = setOf(CommercialPaperSchemaV1, DummyLinearStateSchemaV1)
|
||||
val hibernateConfig = HibernateConfiguration(NodeSchemaService(customSchemas), makeTestDatabaseProperties())
|
||||
val hibernateConfig = HibernateConfiguration(NodeSchemaService(), makeTestDatabaseProperties())
|
||||
services = object : MockServices() {
|
||||
override val vaultService: VaultService = makeVaultService(dataSourceProps, hibernateConfig)
|
||||
|
||||
@ -58,8 +57,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
|
||||
vaultService.notifyAll(txs.map { it.tx })
|
||||
}
|
||||
|
||||
override val vaultQueryService: VaultQueryService = HibernateVaultQueryImpl(hibernateConfig, vaultService.updatesPublisher)
|
||||
override val vaultQueryService : VaultQueryService = HibernateVaultQueryImpl(hibernateConfig, vaultService.updatesPublisher)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,7 +74,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
// Fix the PRNG so that we get the same splits every time.
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L))
|
||||
|
||||
val w = vault.unconsumedStates<Cash.State>().toList()
|
||||
val w = vaultQuery.queryBy<Cash.State>().states
|
||||
assertEquals(3, w.size)
|
||||
|
||||
val state = w[0].state.data
|
||||
@ -139,7 +137,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
ownedBy = AnonymousParty(freshKey))
|
||||
println("Cash balance: ${services.getCashBalance(USD)}")
|
||||
|
||||
assertThat(vault.unconsumedStates<Cash.State>()).hasSize(10)
|
||||
assertThat(vaultQuery.queryBy<Cash.State>().states).hasSize(10)
|
||||
assertThat(vault.softLockedStates<Cash.State>()).hasSize(0)
|
||||
}
|
||||
|
||||
@ -154,16 +152,20 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
val ptxn1 = notaryServices.signInitialTransaction(txn1Builder)
|
||||
val txn1 = services.addSignature(ptxn1, freshKey)
|
||||
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))
|
||||
println("""txn1 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
CONSUMED: ${vault.consumedStates<Cash.State>().count()} : ${vault.consumedStates<Cash.State>()},
|
||||
UNCONSUMED: ${unconsumedStates1.totalStatesAvailable} : $unconsumedStates1,
|
||||
CONSUMED: ${consumedStates1.totalStatesAvailable} : $consumedStates1,
|
||||
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
|
||||
""")
|
||||
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))
|
||||
println("""txn1 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
CONSUMED: ${vault.consumedStates<Cash.State>().count()} : ${vault.consumedStates<Cash.State>()},
|
||||
UNCONSUMED: ${unconsumedStates2.totalStatesAvailable} : $unconsumedStates2,
|
||||
CONSUMED: ${consumedStates2.totalStatesAvailable} : $consumedStates2,
|
||||
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
|
||||
""")
|
||||
txn1
|
||||
@ -184,16 +186,20 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
val ptxn2 = notaryServices.signInitialTransaction(txn2Builder)
|
||||
val txn2 = services.addSignature(ptxn2, freshKey)
|
||||
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))
|
||||
println("""txn2 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
CONSUMED: ${vault.consumedStates<Cash.State>().count()} : ${vault.consumedStates<Cash.State>()},
|
||||
UNCONSUMED: ${unconsumedStates1.totalStatesAvailable} : $unconsumedStates1,
|
||||
CONSUMED: ${consumedStates1.totalStatesAvailable} : $consumedStates1,
|
||||
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
|
||||
""")
|
||||
services.recordTransactions(txn2)
|
||||
println("txn2: Cash balance: ${services.getCashBalance(USD)}")
|
||||
val unconsumedStates2 = vaultQuery.queryBy<Cash.State>()
|
||||
val consumedStates2 = vaultQuery.queryBy<Cash.State>()
|
||||
println("""txn2 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
CONSUMED: ${vault.consumedStates<Cash.State>().count()} : ${vault.consumedStates<Cash.State>()},
|
||||
UNCONSUMED: ${unconsumedStates2.totalStatesAvailable} : $unconsumedStates2,
|
||||
CONSUMED: ${consumedStates2.totalStatesAvailable} : $consumedStates2,
|
||||
LOCKED: ${vault.softLockedStates<Cash.State>().count()} : ${vault.softLockedStates<Cash.State>()}
|
||||
""")
|
||||
txn2
|
||||
@ -250,7 +256,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
|
||||
services.recordTransactions(dummyIssue)
|
||||
assertThat(vault.unconsumedStates<DummyLinearContract.State>()).hasSize(1)
|
||||
assertThat(vaultQuery.queryBy<DummyLinearContract.State>().states).hasSize(1)
|
||||
|
||||
// Move the same state
|
||||
val dummyMoveBuilder = TransactionBuilder(notary = DUMMY_NOTARY).apply {
|
||||
@ -263,7 +269,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
|
||||
services.recordTransactions(dummyMove)
|
||||
assertThat(vault.unconsumedStates<DummyLinearContract.State>()).hasSize(1)
|
||||
assertThat(vaultQuery.queryBy<DummyLinearContract.State>().states).hasSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,11 +281,11 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L), ownedBy = AnonymousParty(freshKey))
|
||||
services.fillWithSomeTestCash(100.SWISS_FRANCS, DUMMY_NOTARY, 2, 2, Random(0L))
|
||||
services.fillWithSomeTestCash(100.POUNDS, DUMMY_NOTARY, 1, 1, Random(0L))
|
||||
val cash = vault.unconsumedStates<Cash.State>()
|
||||
val cash = vaultQuery.queryBy<Cash.State>().states
|
||||
cash.forEach { println(it.state.data.amount) }
|
||||
|
||||
services.fillWithSomeTestDeals(listOf("123", "456", "789"))
|
||||
val deals = vault.unconsumedStates<DummyDealContract.State>()
|
||||
val deals = vaultQuery.queryBy<DummyDealContract.State>().states
|
||||
deals.forEach { println(it.state.data.ref) }
|
||||
}
|
||||
|
||||
@ -291,10 +297,10 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
val spendTX = services.addSignature(spendPTX, freshKey)
|
||||
services.recordTransactions(spendTX)
|
||||
|
||||
val consumedStates = vault.consumedStates<ContractState>()
|
||||
val consumedStates = vaultQuery.queryBy<ContractState>(VaultQueryCriteria(status = Vault.StateStatus.CONSUMED)).states
|
||||
assertEquals(3, consumedStates.count())
|
||||
|
||||
val unconsumedStates = vault.unconsumedStates<ContractState>()
|
||||
val unconsumedStates = vaultQuery.queryBy<ContractState>().states
|
||||
assertEquals(7, unconsumedStates.count())
|
||||
}
|
||||
}
|
||||
@ -307,11 +313,11 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
database.transaction {
|
||||
|
||||
services.fillWithSomeTestDeals(listOf("123", "456", "789"))
|
||||
val deals = vault.unconsumedStates<DummyDealContract.State>().toList()
|
||||
val deals = vaultQuery.queryBy<DummyDealContract.State>().states
|
||||
deals.forEach { println(it.state.data.ref) }
|
||||
|
||||
services.fillWithSomeTestLinearStates(3)
|
||||
val linearStates = vault.unconsumedStates<DummyLinearContract.State>().toList()
|
||||
val linearStates = vaultQuery.queryBy<DummyLinearContract.State>().states
|
||||
linearStates.forEach { println(it.state.data.linearId) }
|
||||
|
||||
// Create a txn consuming different contract types
|
||||
@ -327,10 +333,10 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
|
||||
dummyMove.toLedgerTransaction(services).verify()
|
||||
services.recordTransactions(dummyMove)
|
||||
|
||||
val consumedStates = vault.consumedStates<ContractState>()
|
||||
val consumedStates = vaultQuery.queryBy<ContractState>(VaultQueryCriteria(status = Vault.StateStatus.CONSUMED)).states
|
||||
assertEquals(2, consumedStates.count())
|
||||
|
||||
val unconsumedStates = vault.unconsumedStates<ContractState>()
|
||||
val unconsumedStates = vaultQuery.queryBy<ContractState>().states
|
||||
assertEquals(6, unconsumedStates.count())
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultTrackBy
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
@ -37,10 +38,10 @@ class BankOfCordaRPCClientTest {
|
||||
|
||||
// Register for Bank of Corda Vault updates
|
||||
val criteria = QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.ALL)
|
||||
val (_, vaultUpdatesBoc) = bocProxy.vaultTrackByCriteria<Cash.State>(Cash.State::class.java, criteria)
|
||||
val vaultUpdatesBoc = bocProxy.vaultTrackByCriteria<Cash.State>(Cash.State::class.java, criteria).updates
|
||||
|
||||
// Register for Big Corporation Vault updates
|
||||
val (_, vaultUpdatesBigCorp) = bigCorpProxy.vaultTrackByCriteria<Cash.State>(Cash.State::class.java, criteria)
|
||||
val vaultUpdatesBigCorp = bigCorpProxy.vaultTrackByCriteria<Cash.State>(Cash.State::class.java, criteria).updates
|
||||
|
||||
// Kick-off actual Issuer Flow
|
||||
val anonymous = true
|
||||
|
@ -3,6 +3,7 @@ package net.corda.irs
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.vaultTrackBy
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
@ -81,7 +82,7 @@ class IRSDemoTest : IntegrationTestCategory {
|
||||
fun getFixingDateObservable(config: FullNodeConfiguration): Observable<LocalDate?> {
|
||||
val client = CordaRPCClient(config.rpcAddress!!, initialiseSerialization = false)
|
||||
val proxy = client.start("user", "password").proxy
|
||||
val vaultUpdates = proxy.vaultAndUpdates().updates
|
||||
val vaultUpdates = proxy.vaultTrackBy<InterestRateSwap.State>().updates
|
||||
|
||||
return vaultUpdates.map { update ->
|
||||
val irsStates = update.produced.map { it.state.data }.filterIsInstance<InterestRateSwap.State>()
|
||||
|
@ -5,6 +5,8 @@ import net.corda.core.contracts.filterStatesOfType
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.irs.contract.InterestRateSwap
|
||||
import net.corda.irs.flows.AutoOfferFlow
|
||||
@ -36,8 +38,7 @@ class InterestRateSwapAPI(val rpc: CordaRPCOps) {
|
||||
private fun generateDealLink(deal: InterestRateSwap.State) = "/api/irs/deals/" + deal.common.tradeID
|
||||
|
||||
private fun getDealByRef(ref: String): InterestRateSwap.State? {
|
||||
val (vault, vaultUpdates) = rpc.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
val vault = rpc.vaultQueryBy<InterestRateSwap.State>().states
|
||||
val states = vault.filterStatesOfType<InterestRateSwap.State>().filter { it.state.data.ref == ref }
|
||||
return if (states.isEmpty()) null else {
|
||||
val deals = states.map { it.state.data }
|
||||
@ -46,8 +47,7 @@ class InterestRateSwapAPI(val rpc: CordaRPCOps) {
|
||||
}
|
||||
|
||||
private fun getAllDeals(): Array<InterestRateSwap.State> {
|
||||
val (vault, vaultUpdates) = rpc.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
val vault = rpc.vaultQueryBy<InterestRateSwap.State>().states
|
||||
val states = vault.filterStatesOfType<InterestRateSwap.State>()
|
||||
val swaps = states.map { it.state.data }.toTypedArray()
|
||||
return swaps
|
||||
|
@ -4,17 +4,18 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.google.common.util.concurrent.*
|
||||
import net.corda.core.*
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.UniqueIdentifier
|
||||
import net.corda.core.flatMap
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.linearHeadsOfType
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.map
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.thenMatch
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.testing.DUMMY_CA
|
||||
import net.corda.flows.TwoPartyDealFlow.Acceptor
|
||||
import net.corda.flows.TwoPartyDealFlow.AutoOffer
|
||||
import net.corda.flows.TwoPartyDealFlow.Instigator
|
||||
@ -22,6 +23,7 @@ import net.corda.irs.contract.InterestRateSwap
|
||||
import net.corda.irs.flows.FixingFlow
|
||||
import net.corda.jackson.JacksonSupport
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.testing.DUMMY_CA
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||
import rx.Observable
|
||||
import java.security.PublicKey
|
||||
@ -76,19 +78,16 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
||||
return future
|
||||
}
|
||||
|
||||
private fun loadLinearHeads(node: SimulatedNode): Map<UniqueIdentifier, StateAndRef<InterestRateSwap.State>> {
|
||||
return node.database.transaction {
|
||||
node.services.vaultService.linearHeadsOfType<InterestRateSwap.State>()
|
||||
}
|
||||
}
|
||||
|
||||
private fun doNextFixing(i: Int, j: Int): ListenableFuture<Unit>? {
|
||||
println("Doing a fixing between $i and $j")
|
||||
val node1: SimulatedNode = banks[i]
|
||||
val node2: SimulatedNode = banks[j]
|
||||
|
||||
val swaps: Map<UniqueIdentifier, StateAndRef<InterestRateSwap.State>> = loadLinearHeads(node1)
|
||||
val theDealRef: StateAndRef<InterestRateSwap.State> = swaps.values.single()
|
||||
val swaps =
|
||||
node1.database.transaction {
|
||||
node1.services.vaultQueryService.queryBy<InterestRateSwap.State>().states
|
||||
}
|
||||
val theDealRef: StateAndRef<InterestRateSwap.State> = swaps.single()
|
||||
|
||||
// Do we have any more days left in this deal's lifetime? If not, return.
|
||||
val nextFixingDate = theDealRef.state.data.calculation.nextFixingDate() ?: return null
|
||||
|
@ -4,7 +4,6 @@ import com.opengamma.strata.basics.currency.MultiCurrencyAmount
|
||||
import net.corda.client.rpc.notUsed
|
||||
import net.corda.contracts.DealState
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.filterStatesOfType
|
||||
import net.corda.core.crypto.parsePublicKeyBase58
|
||||
import net.corda.core.crypto.toBase58String
|
||||
import net.corda.core.getOrThrow
|
||||
@ -12,6 +11,7 @@ import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.vega.analytics.InitialMarginTriple
|
||||
import net.corda.vega.contracts.IRSState
|
||||
@ -38,9 +38,10 @@ class PortfolioApi(val rpc: CordaRPCOps) {
|
||||
private val portfolioUtils = PortfolioApiUtils(ownParty)
|
||||
|
||||
private inline fun <reified T : DealState> dealsWith(party: AbstractParty): List<StateAndRef<T>> {
|
||||
val (vault, vaultUpdates) = rpc.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
return vault.filterStatesOfType<T>().filter { it.state.data.participants.any { it == party } }
|
||||
val linearStates = rpc.vaultQueryBy<T>().states
|
||||
// TODO: enhancement to Vault Query to check for any participant in participants attribute
|
||||
// QueryCriteria.LinearStateQueryCriteria(participants = anyOf(party))
|
||||
return linearStates.filter { it.state.data.participants.any { it == party } }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,8 @@ import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.unwrap
|
||||
@ -26,7 +28,6 @@ import net.corda.vega.analytics.*
|
||||
import net.corda.vega.contracts.*
|
||||
import net.corda.vega.portfolio.Portfolio
|
||||
import net.corda.vega.portfolio.toPortfolio
|
||||
import net.corda.vega.portfolio.toStateAndRef
|
||||
import java.time.LocalDate
|
||||
|
||||
/**
|
||||
@ -68,6 +69,7 @@ object SimmFlow {
|
||||
myIdentity = serviceHub.myInfo.legalIdentity
|
||||
|
||||
val trades = serviceHub.vaultService.dealsWith<IRSState>(otherParty)
|
||||
|
||||
val portfolio = Portfolio(trades, valuationDate)
|
||||
if (existing == null) {
|
||||
agreePortfolio(portfolio)
|
||||
@ -75,6 +77,7 @@ object SimmFlow {
|
||||
updatePortfolio(portfolio, existing)
|
||||
}
|
||||
val portfolioStateRef = serviceHub.vaultService.dealsWith<PortfolioState>(otherParty).first()
|
||||
|
||||
val state = updateValuation(portfolioStateRef)
|
||||
logger.info("SimmFlow done")
|
||||
return state
|
||||
@ -104,7 +107,8 @@ object SimmFlow {
|
||||
private fun updateValuation(stateRef: StateAndRef<PortfolioState>): RevisionedState<PortfolioState.Update> {
|
||||
logger.info("Agreeing valuations")
|
||||
val state = stateRef.state.data
|
||||
val portfolio = state.portfolio.toStateAndRef<IRSState>(serviceHub).toPortfolio()
|
||||
val portfolio = serviceHub.vaultQueryService.queryBy<IRSState>(VaultQueryCriteria(stateRefs = state.portfolio)).states.toPortfolio()
|
||||
|
||||
val valuer = serviceHub.identityService.partyFromAnonymous(state.valuer)
|
||||
require(valuer != null) { "Valuer party must be known to this node" }
|
||||
val valuation = agreeValuation(portfolio, valuationDate, valuer!!)
|
||||
@ -308,7 +312,7 @@ object SimmFlow {
|
||||
|
||||
@Suspendable
|
||||
private fun updateValuation(stateRef: StateAndRef<PortfolioState>) {
|
||||
val portfolio = stateRef.state.data.portfolio.toStateAndRef<IRSState>(serviceHub).toPortfolio()
|
||||
val portfolio = serviceHub.vaultQueryService.queryBy<IRSState>(VaultQueryCriteria(stateRefs = stateRef.state.data.portfolio)).states.toPortfolio()
|
||||
val valuer = serviceHub.identityService.partyFromAnonymous(stateRef.state.data.valuer) ?: throw IllegalStateException("Unknown valuer party ${stateRef.state.data.valuer}")
|
||||
val valuation = agreeValuation(portfolio, offer.valuationDate, valuer)
|
||||
subFlow(object : StateRevisionFlow.Receiver<PortfolioState.Update>(replyToParty) {
|
||||
|
@ -5,7 +5,8 @@ import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.SchedulableFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.node.services.linearHeadsOfType
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
|
||||
import net.corda.vega.contracts.PortfolioState
|
||||
import java.time.LocalDate
|
||||
|
||||
@ -19,7 +20,7 @@ object SimmRevaluation {
|
||||
class Initiator(val curStateRef: StateRef, val valuationDate: LocalDate) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call(): Unit {
|
||||
val stateAndRef = serviceHub.vaultService.linearHeadsOfType<PortfolioState>().values.first { it.ref == curStateRef }
|
||||
val stateAndRef = serviceHub.vaultQueryService.queryBy<PortfolioState>(VaultQueryCriteria(stateRefs = listOf(curStateRef))).states.single()
|
||||
val curState = stateAndRef.state.data
|
||||
val myIdentity = serviceHub.myInfo.legalIdentity
|
||||
if (myIdentity == curState.participants[0]) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.corda.vega.portfolio
|
||||
|
||||
import net.corda.client.rpc.notUsed
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.sum
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.vega.contracts.IRSState
|
||||
import net.corda.vega.contracts.SwapData
|
||||
import java.math.BigDecimal
|
||||
@ -35,16 +35,5 @@ fun List<StateAndRef<IRSState>>.toPortfolio(): Portfolio {
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> List<StateRef>.toStateAndRef(rpc: CordaRPCOps): List<StateAndRef<T>> {
|
||||
val (vault, vaultUpdates) = rpc.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
val stateRefs = vault.associateBy { it.ref }
|
||||
return mapNotNull { stateRefs[it] }.filterStatesOfType<T>()
|
||||
}
|
||||
|
||||
// TODO: This should probably have its generics fixed and moved into the core platform API.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : ContractState> List<StateRef>.toStateAndRef(services: ServiceHub): List<StateAndRef<T>> {
|
||||
return services.vaultService.statesForRefs(this).map {
|
||||
StateAndRef(it.value as TransactionState<T>, it.key)
|
||||
}
|
||||
return rpc.vaultQueryBy<T>(QueryCriteria.VaultQueryCriteria(stateRefs = this)).states
|
||||
}
|
||||
|
@ -1,21 +1,23 @@
|
||||
package net.corda.traderdemo
|
||||
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.client.rpc.notUsed
|
||||
import net.corda.contracts.CommercialPaper
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.contracts.getCashBalance
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.contracts.USD
|
||||
import net.corda.core.contracts.filterStatesOfType
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.internal.Emoji
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.core.node.services.vault.builder
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.services.vault.VaultSchemaV1
|
||||
import net.corda.testing.BOC
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.contracts.calculateRandomlySizedAmounts
|
||||
@ -31,18 +33,18 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
|
||||
val logger = loggerFor<TraderDemoClientApi>()
|
||||
}
|
||||
|
||||
val cashCount: Int get() {
|
||||
val (vault, vaultUpdates) = rpc.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
return vault.filterStatesOfType<Cash.State>().size
|
||||
val cashCount: Long get() {
|
||||
val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() }
|
||||
val countCriteria = QueryCriteria.VaultCustomQueryCriteria(count)
|
||||
return rpc.vaultQueryBy<Cash.State>(countCriteria).otherResults.single() as Long
|
||||
}
|
||||
|
||||
val dollarCashBalance: Amount<Currency> get() = rpc.getCashBalance(USD)
|
||||
|
||||
val commercialPaperCount: Int get() {
|
||||
val (vault, vaultUpdates) = rpc.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
return vault.filterStatesOfType<CommercialPaper.State>().size
|
||||
val commercialPaperCount: Long get() {
|
||||
val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() }
|
||||
val countCriteria = QueryCriteria.VaultCustomQueryCriteria(count)
|
||||
return rpc.vaultQueryBy<CommercialPaper.State>(countCriteria).otherResults.single() as Long
|
||||
}
|
||||
|
||||
fun runBuyer(amount: Amount<Currency> = 30000.DOLLARS, anonymous: Boolean = true) {
|
||||
|
@ -8,6 +8,7 @@ import net.corda.core.contracts.Issued
|
||||
import net.corda.core.contracts.PartyAndReference
|
||||
import net.corda.core.contracts.USD
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.core.thenMatch
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.flows.CashFlowCommand
|
||||
@ -218,14 +219,11 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
||||
val currentNodeVaults = HashMap<AbstractParty, HashMap<AbstractParty, Long>>()
|
||||
simpleNodes.forEach {
|
||||
val quantities = HashMap<AbstractParty, Long>()
|
||||
val (vault, vaultUpdates) = it.proxy.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
val vault = it.proxy.vaultQueryBy<Cash.State>().states
|
||||
vault.forEach {
|
||||
val state = it.state.data
|
||||
if (state is Cash.State) {
|
||||
val issuer = state.amount.token.issuer.party
|
||||
quantities.put(issuer, (quantities[issuer] ?: 0L) + state.amount.quantity)
|
||||
}
|
||||
val issuer = state.amount.token.issuer.party
|
||||
quantities.put(issuer, (quantities[issuer] ?: 0L) + state.amount.quantity)
|
||||
}
|
||||
currentNodeVaults.put(it.info.legalIdentity, quantities)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import net.corda.core.contracts.USD
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.flows.CashFlowCommand
|
||||
import net.corda.loadtest.LoadTest
|
||||
import net.corda.loadtest.NodeConnection
|
||||
@ -71,15 +72,12 @@ val selfIssueTest = LoadTest<SelfIssueCommand, SelfIssueState>(
|
||||
gatherRemoteState = { previousState ->
|
||||
val selfIssueVaults = HashMap<AbstractParty, Long>()
|
||||
simpleNodes.forEach { connection ->
|
||||
val (vault, vaultUpdates) = connection.proxy.vaultAndUpdates()
|
||||
vaultUpdates.notUsed()
|
||||
val vault = connection.proxy.vaultQueryBy<Cash.State>().states
|
||||
vault.forEach {
|
||||
val state = it.state.data
|
||||
if (state is Cash.State) {
|
||||
val issuer = state.amount.token.issuer.party
|
||||
if (issuer == connection.info.legalIdentity as AbstractParty) {
|
||||
selfIssueVaults.put(issuer, (selfIssueVaults[issuer] ?: 0L) + state.amount.quantity)
|
||||
}
|
||||
val issuer = state.amount.token.issuer.party
|
||||
if (issuer == connection.info.legalIdentity as AbstractParty) {
|
||||
selfIssueVaults.put(issuer, (selfIssueVaults[issuer] ?: 0L) + state.amount.quantity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user