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"
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.
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).
Related
I have a simple flow that creates a state between a buyer and seller and obviously each side can see everything on the state.
However, I now have a requirement that the buyer wants to store the user that processed the transaction for auditing and reporting purposes.
The user in this case is not a node or an account but a user that has logged in to the application and been authorised via Active Directory.
I could just add the user name to the state as a String but that would expose private data to the seller.
An alternative would be to obfuscate the name in some way but I would rather store the information in a separate table outside the state and only in the buyers vault.
How do I do this and is there a sample that demonstrates it?
You can create a second output state, which is used in the same transaction, but has only the token issuer as participant. Then of course, it is up to you to make the link between the "issued state" and the "recorder state", it depends on what you will store inside the latter.
Let's make an example of a fungible token issuance from Node1 to Node2. You could create a "issuance recorder state" that aims at recording something on Node1's vault only, like so (note the list of participants):
// the "recorder" state visible only in Node1's vault
#BelongsToContract(IssuanceRecordContract::class)
class IssuanceRecord(
val holder: AbstractParty,
val amount: Amount<IssuedTokenType>
) : ContractState {
override val participants: List<AbstractParty>
get() = listOf(amount.token.issuer)
}
and then you could pass it to the same TransactionBuilder that you are using to issue the fungible token (which instead has both parties in the list of participants), like so:
// This is from the Issuanflow launched from Node1
#Suspendable
override fun call(): String {
...
...
// Create the FungibleToken (issuedToken is an IssuedTokenType created before)
val tokenCoin = FungibleToken(Amount(volume.toLong(), issuedToken), holderAnonymousParty)
// create the "recorder" output state visible only to Node1
val issuanceRecord = IssuanceRecord(holderAnonymousParty, tokenCoin.amount)
// create the Transaction Builder passing the "recorder" output state
val transactionBuilder = TransactionBuilder(notary).apply {
addOutputState(issuanceRecord, IssuanceRecordContract.ID)
addCommand(Command(IssuanceRecordContract.Commands.Issue(), ourIdentity.owningKey))
}
// Issue the token passing the transactionBuilder and the fungible token
addIssueTokens(transactionBuilder, tokenCoin)
// collect signatures
// verify transaction
// FinalityFlow (fundamental to make this work in Node1)
}
This way, I think, the recorder states will be atomically stored in Node1's vault. If something happens, the transaction will be not successful for both output states.
Basically i have two parties in my state and i want to transfer an asset say a house or a car from one party to another or issue the same asset to a party so how can i manage that?
I tried searching the docs but couldn't find anything substantial
If your modeling or defining your own states then you decide. Some attribute of your state is set to the owning party. Transfer of the asset is a transaction that changes the party on this attribute, presumably initiated by only the owner or a party delegated that power.
Let's use the example of your House State
Your house state might look something like this:
#BelongsToContract(HouseContract::class)
data class HouseState (
val address: String,
val appraisal: Amount<USD>,
val owner: Party,
val participants: List<Party>,
override val linearId: UniqueIdentifier = UniqueIdentifier()
): ContractState, LinearState {
fun withNewOwner(party: Party): HouseState {
return this.copy(owner = party)
}
override val participants: List<AbstractParty> get() = players
}
}
In Corda, states are immutable. You would change the owner of a House by marking the input state as consumed and issuing a new houseState onto the ledger with the owner field updated.
Some states even have convenience methods (see the HouseState above) That return a copy of the input state with a field updated (in this case the owner) to be included in the transaction as the output state.
I am looking for the correct contract upgrade process. Consider the following example:
SimpleContract : Contract {
data class State(override val owner: AbstractParty, val relevantParticipant: AbstractParty) : OwnableState {
override val participants: List<AbstractParty> = listOf(owner, relevantParticipant)
override fun withNewOwner(newOwner: AbstractParty): CommandAndState
= CommandAndState(Commands.Move(), copy(owner = newOwner))
}
}
As I understand, this state is only stored in the owner's vault, but the relevantParticipant also has (in it's transaction storage) the transaction where the SimpleContract.State is one of the outputs. If the owner were to (authorize and) initiate the upgrade, the flow fails as the relevantParticipant does not have the authorized contract upgrade for it. What is the right approach here?
One solution is for the owner to send the StateRef to the relevantParticipant. The relevantParticipant can then retrieve the StateAndRef using ServiceHub.loadState, and choose to authorise the contract upgrade using ContractUpgradeFlow.Authorise.
This is better than sending the StateAndRef directly, since the relevantParticipant can then verify that the state being sent hasn't been tampered with (since they retrieve the actual state from their storage, not the counterparty's).
Do you have any example how to execute multiple transactions between participants A, B, C. I can do it ease between 2 parties A and B. Have fount the same discussion on the official Corda forum without result
Sharing transaction among multiple nodes
Is it possible? Do you have any example?
If you are issuing a new state, you can simply alter the participants of this state to ensure all parties receive the new state. Here is an example I have created with KYC data. This is example is updating a state (not issuing a new state), but the same principle applies - simply alter the participants list to control who will see that state. The KYC State is as follows:
#CordaSerializable
data class State(val firstName: String, val lastName: String, val accountNum: String, val owner: AbstractParty,
override val linearId: UniqueIdentifier = UniqueIdentifier(), val banksInvolved: List<AbstractParty> = emptyList()) : QueryableState, ContractState, LinearState {
//Each time a TD is issued with this KYC data, the bank it is issued to is added to this banks involved list, meaning the data is now stored in that banks vault
override val participants: List<AbstractParty> get() = banksInvolved.plus(owner)
This participants variable is the list of all nodes that will store this state in their vault (i.e will be notified about the states creation, update, etc). This is where you would add new nodes too for them to be able to view the state in their vault.
Then within a flow, to notify a new bank that they have received KYC data, we simply add the state as output with a new bank added to the banksInvolved list. This will make this new bank a participant with this state:
builder.addOutputState(KYCData.first().state.copy(data = KYCData.first().state.data.copy(
banksInvolved = KYCData.first().state.data.banksInvolved.plus(issuingInstitue)))) //Same state but with a new bank involved - i.e able to view this KYC data
check your state, there you can mention the List of participants for transaction.
Consider the following case:
node A builds and signs a TX which is sent to B for signing.
class FlowA(val otherParty: Party) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.getNotary()
val builder = TransactionBuilder(notary)
// ... add some commands and states
val stx = serviceHub.signInitialTransaction(builder)
val session = initiateFlow(otherParty)
subFlow(SendTransactionFlow(session, stx))
return session.sendAndReceive<SignedTransaction>(stx).unwrap {
it.id == stx.id // is it enough?
it
}
}
}
class FlowB(val session: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow(ReceiveTransactionFlow(session, false))
val stx = session.receive<SignedTransaction>().unwrap {
val ledgerTx = it.toLedgerTransaction(serviceHub, false)
ledgerTx.commandsOfType<SomeContract.Commands.SomeCommand>().single()
ledgerTx.verify() // is it enough?
}
}
}
Is it secure to check only the id of the transaction from the sender side once we received the full signed transaction?
I've read in the doc that id is the root Merkle tree built by using transaction's components, so if the otherParty change something the id would be different, correct?
From the receiver side, is it secure to check which commands are present in the transaction so we are sure that the contract relative to that command is run by means of verify?
On receiving a transaction, you will be able to interrogate all the inputs, outputs and commands.
Typically, the interrogation would happen inside the contracts verify method.
Yes, if anything were to change the root ID would indeed change. Note that it's not possible to change anything within a transaction once it has been signed.
Other things you could look for is the presence of the transaction being notarised.
It depends on what your contract needs to do, but yes, you would check which commands are present within a transaction e.g. in the issuance of a security, you might check that only one issue command is present.
You can also check the commands have received the required counterparty signatures.
If you would like to discuss in person, feel free to join one of office hour sessions - https://www.corda.net/support/technical-office-hours/