问题
While going through Corda docs, I came across the below snippet at this link.
The default vault implementation makes the decision based on the following rules:
If the state is an OwnableState, the vault will store the state if the node is the state’s owner Otherwise, the vault will store the state if it is one of the participants
In my flow,
- I am issuing/sending cash from Node A to Node B using a state class that implements OwnableState.
- I made Node B as the owner.
- I populated the participants field with Node A and Node B both.
I am able to see the new state in Node B but not in Node A.
I tried to query the states on terminal (where it only shows unconsumed states) as well as using vault query API by adding criteria as status = vault.StateStatus.ALL
.
Does this mean, I would never be able
- to track from where the cash came in Node B ?
- to track to where the cash in Node A goes ?
Code samples are as follows: State Class :
package com.shailesh
import net.corda.core.contracts.CommandAndState
import net.corda.core.contracts.OwnableState
import net.corda.core.identity.AbstractParty
import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState
import net.corda.core.serialization.CordaSerializable
import net.corda.finance.contracts.asset.Cash
@CordaSerializable
data class MyPersistentState(val amount: Int, val sender : AbstractParty, val receiver : AbstractParty) : OwnableState {
override val owner: AbstractParty
get() = receiver
override val participants: List<AbstractParty> = listOf(sender, receiver)
}
Flow Class:
package com.shailesh
import co.paralleluniverse.fibers.Suspendable
import com.shailesh.PersistenceDemoContract.Companion.id
import net.corda.core.contracts.Contract
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import net.corda.core.node.services.Vault
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.finance.DOLLARS
import net.corda.finance.contracts.asset.CASH
import net.corda.finance.contracts.asset.Cash
@InitiatingFlow
@StartableByRPC
class PersistenceDemoFlow(val amount: Int, val receiver : Party) : FlowLogic<Unit>() {
override val progressTracker: ProgressTracker = ProgressTracker()
@Suspendable
override fun call() {
val notary = serviceHub.networkMapCache.notaryIdentities.first()
val qc = QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.ALL)
// I expect that result should show me the states in Node A when A issues state to B
val result: Vault.Page<MyPersistentState> = serviceHub.vaultService.queryBy(contractStateType = MyPersistentState::class.java, criteria = qc)
val outputState = MyPersistentState(amount, ourIdentity, receiver)
val tx = TransactionBuilder(notary).addOutputState(outputState, id).addCommand(Cash.Commands.Issue(), listOf(ourIdentity.owningKey))
tx.verify(serviceHub)
val signedTx = serviceHub.signInitialTransaction(tx)
subFlow(FinalityFlow(signedTx))
}
}
@CordaSerializable
class PersistenceDemoContract: Contract {
companion object {
val id = "com.shailesh.PersistenceDemoContract"
}
override fun verify(tx: LedgerTransaction) {
}
}
Commands to query and issue states:
// Check states
run vaultQuery contractStateType: com.shailesh.MyPersistentState
// Start the issue flow on Node A
flow start com.shailesh.PersistenceDemoFlow amount: 100, receiver: "O=PartyB,L=New York,C=US"
回答1:
Your flow is issuing a state to a receiver directly, where there's no inputs
and one output
- which is the only unconsumed state that will be recorded on the receiver(owner)'s vault.
The state was created from thin-air and inserted into the receiver's vault. Nothing was consumed to create this state in the first place. Hence, despite running a query for both consumed/unconsumed on the sender the side, it returned nothing.
If you want a trace of where it was issued from, do a self-issue
of the state by making issuer as the initial owner. Then send it over to the receiver by making the state consumed on the input, and the outputs with the unconsumed state with the new owner reassigned.
回答2:
Expanding on Adrian's answer, the original question asks whether, for an OwnableState
:
I would never be able
to track from where the cash came in Node B ?
to track to where the cash in Node A goes ?
Additionally, in the comments, it is asked what is the importance of the participants
field for an OwnableState
.
The importance of the participants
field is that all the participants
will receive and record a copy of the transaction creating the new state as part of FinalityFlow
. It is this transaction, and not the state itself, that allows a chain of cash movements to be established over time.
It is important in Corda to distinguish between who records a transaction (all the participants
) and who records a state (the owner
for an OwnableState
, and otherwise all the participants
).
来源:https://stackoverflow.com/questions/49450545/back-tracking-ownablestate-in-corda