Corda Flow Participants How To Add & Remove - corda

Can we add/remove participant in the subsequent transaction if the original transaction does not have it.
I have party A which has created one transaction and added a participant Party B. The state created in the transaction is shared with Party B. There are state properties like FirstName, LastName and Status.
Party B changes the status to green and then the transaction is completed and recorded to vault of Party B and Party A.
The same process is followed between Party A and Party C.
The same process is followed between Party A and Party D.
------Party B
/
Party A /-------Party C
\
------Party D
I have a use case wherein Party B, Party C, Party D can change the status in the state to Green. As soon as all the status becomes green, I want to initiate a flow at Party A.
What is the best way to implement this in Corda?

1) Yes you can add or remove by placing the participant inside the participant list you could initailize them as null at the start, just remember to send the flowSession to everyone that is involved in the state/transaction. However by performing this action do take note that the chain of transactions ( walk the chain ) will still apply hence the newly added participant would be able to view the history of the state so if there is a requirement for sensitive information to specific party it would be exposed to all participants for the state.
2) Yes you could do that also, there are two sections for the flow the #InitiatingFlow and the #InitiatedBy ( Responder ) flow you could put a logic here to query your vault for related transactions and do your logic operations

1)One way to do it would be to have your state property to have a List parties.
in your getParticipants() method which you've overridden in the state class return this list.
Now at the time of creating the state you can add as many parties as you want.
Once the state has been persisted. You can update this state now and add as many participants as you want to parties field.
2) Not sure in here but if you are party agnostic you can have a status ENUM in your state and make it go from PINE,PEAR,LIME,GREEN(Order of green color) and have each party update the status accordingly. Once green you can start your flow. Make your state scheduled-able and check if it's green you can start the flow to do whatever you want.
PS:This is a workaround I can think of from top of my head, I'm not sure if this an appropriate way to do it in corda.

Related

How to spend UTXO in corda

I learned how to create output state by corda.
However, I can't find documentation about how to consume those created outputs.
How can I specify outputs I want to consume as inputs in Flow code?
Usually it's like this:
Your state is a LinearState that has some UUID attribute as its linearId.
The flow that wants to consume that state has a constructor that takes as an input parameter that linearId.
Inside the flow you query the vault of the node to get that state by its linearId; the query returns a StateAndRef of your state.
You add that StateAndRef as an input to your transaction.
Let's say you're trying to update that state, so you add to the transaction an output; that output has the same value for linearId; but you can modify any other attribute. So this way you mimic an update, because states in Corda are final; so to update one, you consume it, then you create an output that has the same linearId but different values for the remaining attributes. This allows you to track the history of that state by its linearId.
This example shows the above steps, you'll see that the flow constructor takes the Id of the proposal, queries the vault for that proposal; then updates its amount by creating a new proposal with the same Id but different amount.

Unable to remove participant from further transaction on same asset

Parties in the business. .
Parties A , B , C
Asset : Order
Party A sends first transaction for both parties B and C
Party B sends next transaction to A and C (on same order , we used vault query to get input state)
Now we want Party C should not receive any future transaction on this Order. When we remove C from participant list we get following error. Looks like Corda is taking participant list from input state. Please suggest a solution to the problem.
java.lang.IllegalArgumentException: Flow sessions were not provided for the following transaction participants: [O=C, L=NV, C=US]
This error message comes from the FinalityFlow:
https://github.com/corda/corda/blob/56067acd208b1b58f17cca85c0eb40ad0e9a1ff5/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt#L159-L161
To explain why you got that error, let's go back to the definition of participants:
https://github.com/corda/corda/blob/56067acd208b1b58f17cca85c0eb40ad0e9a1ff5/core/src/main/kotlin/net/corda/core/contracts/ContractState.kt#L19
A participant is any party that should be notified when the state is created or consumed.
Following that statement, when your transaction has one (or more) inputs and one (or more) outputs, then this transaction should be recorded (i.e. finalized) in the union of all participants of all input and output states, because again; following the participants definition, they should be notified when their states are created or consumed.
That's why, finality flow expects a FlowSession for each participant in the transaction, and throws the error that you saw when it finds a missing one.
Now, regarding privacy concerns (the other part of your question); even though FinalityFlow records the finalized transaction in the union of all participants; it doesn't record all outputs states in all vaults, it has a parameter called StatesToRecord which defaults to ONLY_RELEVANT:
https://github.com/corda/corda/blob/56067acd208b1b58f17cca85c0eb40ad0e9a1ff5/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt#L47
Which means, a node will only register the states that it participates in.
So to summarize, the transaction will be recorded in the union of all participants (of all input/output states), but each participant will only register in their vault the relevant output states.
Important: The peer node that calls ReceiveFinalityFlow might override the default value of statesToRecord and choose ALL_VISIBLE which means record all output states of the transaction whether it's a participant or not:
https://github.com/corda/corda/blob/56067acd208b1b58f17cca85c0eb40ad0e9a1ff5/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt#L272-L274
I suggest you read my article on privacy analysis using CDL here; it's more detailed about this topic: https://blog.b9lab.com/how-to-design-a-cordapp-and-analyze-privacy-leaks-using-cdl-views-da825953ff54

Corda is it possible to issue and consume state in same flow

I am trying to do simple fund transfer from one account to another account using simple state. 2 Flows have been created one for issue of transfer request with cash transfer and flow created to just consumed that transaction. My question is, is it possible to transfer and consume state in one flow ?
As per my opinion transaction must be consumed after transfer but also want to show it on UI.
Corda RPCQuery allowed to bring information of unconsumed states only, if I consume above transaction, is there way to show consumed transactions last state?
CordaRPCOps allows you to query for unconsumed states, consumed states, or both. Here's a simple way of querying for all states:
val criteria = QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL)
val results = proxy.vaultQueryBy<ContractState>(criteria)
To show the last consumed state, you could retrieve all the consumed states in descending order of consumption and grab the first one, as follows:
val criteria = QueryCriteria.VaultQueryCriteria(Vault.StateStatus.UNCONSUMED)
val sortColumn = Sort.SortColumn(SortAttribute.Standard(Sort.VaultStateAttribute.CONSUMED_TIME), Sort.Direction.DESC)
val sorting = Sort(listOf(sortColumn))
val results = proxy.vaultQueryBy<Obligation>(criteria, sorting = sorting)
val lastConsumedState = results.states[0]
From any flow, you need to call FinalityFlow, in order to notarize
and record the transaction in individual parties' vault. So I think
after the issuance (or transfer), you need to call FinalityFlow
first. Only then you can use the issued state as input for the new
transaction.
The notary is responsible for avoiding the double spend
of the input state in any transaction. So you can not use any newly
issued state (as input to new transaction), until the notary is aware
of it.
Thus I think in your case, you will need to call FinalityFlow twice, once after each transaction (i.e. issuance & consumption).

how to add a participant to an existing Corda State, and ensure they receive updates?

Here's an example scenario:
Party A receives data from Party B before Party B has a Corda node and identity. Party A temporarily manages their shared state, using a temporary string identifier for Party B. When Party B launches a node, Party A needs to update the shared state with B's identity (replace the temp id in the State with a Party reference).
At this point, B should become aware of this State, and receive updates if there are any changes. What's the right way to ensure this last part?
You would create a transaction that:
Takes an input the shared state where B is identified using the temporary string
Has as output the same shared state, but with B identified using a Party object and added to the participants
As a participant, B will then receive the transaction as part of the FinalityFlow.
You'd need to think about how to handle the fact that a field in the state could either be an identifier string or a Party object. Some options:
Have two subclasses of the overall state, that differ by this field
Have nullable fields in the same
Define some type that wraps either an identifier or a Party object

Corda IsRelevant() work around?

There were some changes in the API for 1.0 that had removed isRelevant(). What are the best workarounds for this?
Given a use case: If there are 100 parties that want to see this queryable state and all updates pertaining to it (but read-only and doesn't need to sign), do I need to add them all to the Participants list? The "observer" role doesn't exist yet? Is there an alsoInformed or something similar for the use case of just seeing static reference data?
The general function here is a shared linear queryable state where the issuer has the master to change/update which would propagate to all parties that want to "subscribe" to these changes. I believe this might work with a broadcast to a "club", but I don't think clubs exist yet or if they're dynamic groupings of the network map.
I'll go into a bit of background before answering... The concept of relevancy still exists in the platform. As you know, in Corda there are two data persistence stores; the storage service and the vault.
The storage service
The storage service is a key -> value store that persists data such as:
Serialised flow state machines
Attachments
Transactions
The storage service is great for storing large amounts of serialised data that can be indexed and retrieved by hash. However, it is awkward if one wishes to search for data within one of the stored objects. E.g. one cannot easily search for transaction output states of a specific type when using the transaction store. The approach would be to iterate through all transactions, deserialise them one by one, and filter by output type. It's cumbersome and not very efficient. This is why the vault and the concept of relevancy exists!
The vault
The vault exists to store state objects, as opposed to transactions. There is a master states table where the state reference, transaction id (that generated the output state) and some other meta data such as whether the state is consumed (or not), is stored. There's also a table for LinearStates and a table for OwnableStates. Also, if one wishes to add an ORM to their state, a database table is created for each type of state object reflecting the ORM definition. These properties can then be queried to pull out states from the vault that meet specific queries, e.g. "Any obligation states over £1000 with Alice as the lender that have not yet been consumed". That's the power of the vault!
Relevancy
Now, it is the case that not all transactions a node receives produce states that are relevant to that node. An example would be a payment vs payment transaction where Alice sends dollars to Bob and Bob sends pounds to Alice. As Bob now owns the dollars Alice previously owned, those dollars are now not relevant for Alice. As such, Alice shouldn't record the output state representing those dollars as she does not hold the right and obligations to those dollars. What Alice does do is to mark the old dollar state as consumed, thus it will now not count towards her total dollars balance and cannot be used as an input in another transaction (as it has already been spent).
How relevancy works in Corda
So, when a node receives a new transaction, it intersects the public keys defined in the participants property of each output state with all the public keys that the VaultService is aware of. If the resultant set fora particular state is not empty, then the state is relevant for the node. Simple.
What this means is that if a node receives a transaction where their public keys are not listed in an output states' participants field, then they will not store that output state in the vault. However, they will store the transaction in the transaction store, and it can still be queried.
The concept of relevancy for OwnableStates is simple, one either owns it or they don't. The concept for LinearStates that represent multi-lateral agreements is more complex. In versions M14 and below, one could override the functionality of isRelevant in a LinearState, however in V1 this has been removed in favour of an easier approach which just compares the participants keys to the vault keys (as described above).
Implications of the V1 approach to relevancy
As the OP notes, in V1, there will be the concept of transaction observers, where nodes that were not participants of a state can still store the state in their vault and query it as a "third party" state. I.e. it cannot be consumed or contribute to balance totals but it can be queried. In the meantime, we will have to work around the absence of that feature and the options are:
For LinearStates, add all intended observers to the participants list. Then, add an additional property to the state object called something like consumers that just contains the list of participants that can consume this state in a valid transaction, i.e. sign a transaction containing it. The contract for that state will then compare those public keys in the commands to those in the consumers list. This way all the observers will still store the state in their vaults. The FinalityFlow will broadcast this transaction to all participants. You can use randomly generated public keys if you don't want the observers to be known to other participants.
For OwnableStates, like Cash, there can only be one identity in participants, the owner. So the approach would be to use the FinalityFlow to send the transaction to a set of observers, then those observers would have to get the output states directly from the transaction. Cumbersome but temporary as we are working on transaction observers at this moment: https://r3-cev.atlassian.net/browse/CORDA-663.
Just a strawman of what I understood if this were to be in code.
i.e using obligation cordapp example
Obligation State
val consumers: List<AbstractParty> = listOf(lender, borrower)
override val participants: List<AbstractParty> get() = listOf(lender, borrower, extraActor)
Contract code verify
override fun verify(tx: LedgerTransaction){
val command = tx.commands.requireSingleCommand<Commands>()
when (command.value) {
is Obligation.Issue -> requireThat {
"The signers should only be the consumers for the obligation" using
(command.signers.toSet() == obligation.consumers.map { it.owningKey }.toSet())
}
Add Command specifying the signers need only be consumers during TX creation
val utx = TransactionBuilder(notary = notary)
.addOutputState(state, OBLIGATION_CONTRACT_ID)
.addCommand(Obligation.Issue(), state.consumers.map { it.owningKey })
.setTimeWindow(serviceHub.clock.instant(), 30.seconds)
In this way, the first tx allows the extraActor to commit the state into the ledger without signing. In a future tx proposal, the extraActor here can query its state table and propose a change of lifecycle in the state using a different command, whereby this time it may require all participants (if need be) to sign the command. i.e Obligation.DoSomethingExtra command with all participant signing (command.signers.toSet() == obligation.participants.map { it.owningKey }.toSet())

Resources