The output of one of my flows is a LinearState that has been "modified" over time by various flows.
Is there an API to get the previous versions of this state in the order that they were created/modified?
I can query the vault like this:
val linearIdCriteria = QueryCriteria.LinearStateQueryCriteria(linearId = listOf(outputState.linearId), status = ALL)
val states = myNode.services.vaultService.queryBy<MyState>(linearIdCriteria).states
However, the SQL generated by hibernate doesn't have an Order By clause so the order of the states in the list cannot be guaranteed.
The states returned don't have any timestamp on them so I can't see how to order the list.
The time that the state was saved is available as a sorting option (Sort.VaultStateAttribute.RECORDED_TIME) which should guarantee the order of the vault query.
//Get all versions of the State by its LinearId
val linearIdCriteria = QueryCriteria.LinearStateQueryCriteria(linearId = listOf(outputState.linearId), status = ALL)
//Add sorting by recorded date
val sortByRecordedDate = SortColumn(SortAttribute.Standard(Sort.VaultStateAttribute.RECORDED_TIME), Sort.Direction.ASC)
val sorting = Sort(listOf(sortByRecordedDate))
val states = myNode.services.vaultService.queryBy<MyState>(linearIdCriteria, sorting).states
Unconsumed and consumed states can be sorted in ascending/descending alphabetical order using the following code -
Vault.StateStatus status = Vault.StateStatus.CONSUMED;
#SuppressWarnings("unchecked")
Set<Class<LinearState>> contractStateTypes = new HashSet(singletonList(LinearState.class));
QueryCriteria vaultCriteria = new VaultQueryCriteria(status, contractStateTypes);
List<UniqueIdentifier> linearIds = singletonList(ids.getSecond());
QueryCriteria linearCriteriaAll = new LinearStateQueryCriteria(null, linearIds, Vault.StateStatus.UNCONSUMED, null);
QueryCriteria dealCriteriaAll = new LinearStateQueryCriteria(null, null, dealIds);
QueryCriteria compositeCriteria1 = dealCriteriaAll.or(linearCriteriaAll);
QueryCriteria compositeCriteria2 = compositeCriteria1.and(vaultCriteria);
PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
Sort.SortColumn sortByUid = new Sort.SortColumn(new SortAttribute.Standard(Sort.LinearStateAttribute.UUID), Sort.Direction.DESC);
Sort sorting = new Sort(ImmutableSet.of(sortByUid));
Vault.Page<LinearState> results = vaultService.queryBy(LinearState.class, compositeCriteria2, pageSpec, sorting);
OR
val sortAttribute = SortAttribute.Custom(CustomerSchema.CustomerEntity.class,
"changeDate")
val sorter = Sort(setOf(Sort.SortColumn(sortAttribute, Sort.Direction.DESC)))
val constraintResults = vaultService.queryBy<LinearState>(constraintTypeCriteria, sorter)
Following are the URLs for reference:
URL1: https://docs.corda.net/api-vault-query.html
URL2: https://github.com/corda/corda/issues/5060
URL3: https://github.com/manosbatsis/vaultaire
URL4: https://r3-cev.atlassian.net/browse/CORDA-2247
Related
If anyone can help me its lots help.
I need Query Some state that state data must be descending Order
You can add sorting to your query; see below sample code that's taken from here.
Vault.StateStatus status = Vault.StateStatus.CONSUMED;
#SuppressWarnings("unchecked")
Set<Class<LinearState>> contractStateTypes = new HashSet(singletonList(LinearState.class));
QueryCriteria vaultCriteria = new VaultQueryCriteria(status, contractStateTypes);
List<UniqueIdentifier> linearIds = singletonList(ids.getSecond());
QueryCriteria linearCriteriaAll = new LinearStateQueryCriteria(null, linearIds, Vault.StateStatus.UNCONSUMED, null);
QueryCriteria dealCriteriaAll = new LinearStateQueryCriteria(null, null, dealIds);
QueryCriteria compositeCriteria1 = dealCriteriaAll.or(linearCriteriaAll);
QueryCriteria compositeCriteria2 = compositeCriteria1.and(vaultCriteria);
PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
Sort.SortColumn sortByUid = new Sort.SortColumn(new SortAttribute.Standard(Sort.LinearStateAttribute.UUID), Sort.Direction.DESC);
Sort sorting = new Sort(ImmutableSet.of(sortByUid));
Vault.Page<LinearState> results = vaultService.queryBy(LinearState.class, compositeCriteria2, pageSpec, sorting);
We have Name schema contains,
FirstName : Rock
LastName : John
Prefix : Mr
MiddleName : ""
Suffix: "Jr"
We are creating some states, schema with the definition.
But Now Want to field the states with values. We need to filter the values like
(FirstName+LastName).equals("RockJohn").
We are trying to write the custom vault query.
Is there any way to achieve this?
In Java, you'd write something like:
FieldInfo firstNameField = getField("firstName", NameSchemaV1.PersistentName.class);
FieldInfo lastNameField = getField("lastName", NameSchemaV1.PersistentName.class);
CriteriaExpression firstNameIndex = Builder.equal(firstNameField, "Rock");
CriteriaExpression lastNameIndex = Builder.equal(lastNameField, "John");
QueryCriteria firstNameCriteria = new QueryCriteria.VaultCustomQueryCriteria(firstNameIndex);
QueryCriteria lastNameCriteria = new QueryCriteria.VaultCustomQueryCriteria(lastNameIndex);
QueryCriteria criteria = firstNameCriteria.and(lastNameCriteria);
Vault.Page<ContractState> results = getServiceHub().getVaultService().queryBy(NameState.class, criteria);
In Kotlin, you'd write something like:
val results = builder {
val firstNameIndex = NameSchemaV1.PersistentName::firstName.equal("Rock")
val lastNameIndex = NameSchemaV1.PersistentName::lastName.equal("John")
val firstNameCriteria = QueryCriteria.VaultCustomQueryCriteria(firstNameIndex)
val lastNameCriteria = QueryCriteria.VaultCustomQueryCriteria(lastNameIndex)
val criteria = firstNameCriteria.and(lastNameCriteria)
serviceHub.vaultService.queryBy(NameState::class.java, criteria)
}
You can use a Hibernate formula to create a dynamic/calculated property:
#Formula(value = " concat(first_name, last_name) ")
String fullName
Then treat it as a regular property/field in your queries
I try to get transaction history on corda.
I need to get the amount of the transaction for a certain period
My api for this :
#GET
#Path("transactions")
#Produces(MediaType.APPLICATION_JSON)
fun gettransatcions(): List<StateAndRef<ContractState>> {
val TODAY = Instant.now()
val pagingSpec = PageSpecification(DEFAULT_PAGE_NUM, 100)
val start = TODAY.minus(1, ChronoUnit.HOURS)
val end = TODAY.plus(1, ChronoUnit.HOURS)
val recordedBetweenExpression = QueryCriteria.TimeCondition(
QueryCriteria.TimeInstantType.RECORDED,
ColumnPredicate.Between(start, end))
val criteria = QueryCriteria.VaultQueryCriteria(timeCondition = recordedBetweenExpression,status = Vault.StateStatus.ALL)
val results = rpcOps.vaultQueryBy<ContractState>(criteria, paging = pagingSpec)
val size = results.states.count()
return rpcOps.vaultQueryBy<ContractState>().states
}
where:
val rpcOps: CordaRPCOps
I can explicitly specify States for which to receive transactions like:
val criteria = VaultQueryCriteria(contractStateTypes = setOf(Cash.State::class.java, DealState::class.java))
but, I need to get transactions across all states except for a certain.
Have corda got any mechanism for this ?
There is no type of query criteria that specifically excludes certain states. However, you can define a query criteria that specifically includes certain states, then combine that with your existing criteria using an AND composition:
val TODAY = Instant.now()
val pagingSpec = PageSpecification(DEFAULT_PAGE_NUM, 100)
val start = TODAY.minus(1, ChronoUnit.HOURS)
val end = TODAY.plus(1, ChronoUnit.HOURS)
val recordedBetweenExpression = QueryCriteria.TimeCondition(
QueryCriteria.TimeInstantType.RECORDED,
ColumnPredicate.Between(start, end))
val timeCriteria = QueryCriteria.VaultQueryCriteria(timeCondition = recordedBetweenExpression, status = Vault.StateStatus.ALL)
val typeCriteria = QueryCriteria.VaultQueryCriteria(contractStateTypes = setOf(State1::class.java, State2::class.java), status = Vault.StateStatus.ALL)
val combinedCriteria = timeCriteria.and(typeCriteria)
val results = rpcOps.vaultQueryBy<ContractState>(combinedCriteria, paging = pagingSpec)
This will retrieve all the states that meet both your time criteria and your type criteria.
I have the StateRef for a state that was recorded by my node. How can I get a stream of all the states recorded by my node since that StateRef was recorded?
You need to do two things:
Identify when the StateRef you have was recorded
Start streaming updates from after that time
Here's an example RPC client that would do this:
fun main(args: Array<String>) {
// Getting an RPC connection to the node.
require(args.size == 1) { "Usage: ExampleClientRPC <node address>" }
val nodeAddress = NetworkHostAndPort.parse(args[0])
val client = CordaRPCClient(nodeAddress)
val rpcOps = client.start("user1", "test").proxy
// Change this to an actual StateRef.
val dummyStateRef = StateRef(SecureHash.zeroHash, 0)
// Getting the time the state was recorded.
val queryByStateRefCriteria = VaultQueryCriteria(stateRefs = listOf(dummyStateRef))
val queryByStateRefResults = rpcOps.vaultQueryBy<ContractState>(queryByStateRefCriteria)
val queryByStateRefMetadata = queryByStateRefResults.statesMetadata
val dummyStateRefRecordedTime = queryByStateRefMetadata.single().recordedTime
// Getting the states recorded after that time.
val queryAfterTimeExpression = TimeCondition(
RECORDED, BinaryComparison(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL, dummyStateRefRecordedTime))
val queryAfterTimeCriteria = VaultQueryCriteria(
status = ALL,
timeCondition = queryAfterTimeExpression)
val queryAfterTimeResults = rpcOps.vaultTrackBy<ContractState>(queryAfterTimeCriteria)
val afterTimeStates = queryAfterTimeResults.states
}
I am using Corda 3.2. Given a SignedTransaction, how can I establish when it was recorded?
There is no direct API for determining when a transaction was recorded. However, you can achieve this by checking either:
When one of the transaction's inputs was consumed:
val inputStateRef = signedTx.inputs[0]
val queryCriteria = QueryCriteria.VaultQueryCriteria(stateRefs = listOf(inputStateRef))
val results = serviceHub.vaultService.queryBy<ContractState>(queryCriteria)
val consumedTime = results.statesMetadata.single().consumedTime!!
When one of the transaction's outputs was recorded:
val ledgerTx = signedTx.toLedgerTransaction(serviceHub)
val outputStateRef = StateRef(signedTx.id, 0)
val queryCriteria = QueryCriteria.VaultQueryCriteria(stateRefs = listOf(outputStateRef))
val results = serviceHub.vaultService.queryBy<ContractState>(queryCriteria)
val recordedTime = results.statesMetadata.single().recordedTime