mirror of
https://github.com/corda/corda.git
synced 2025-06-13 04:38:19 +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:
@ -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()
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user