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.
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.
We are using the code below in an application to execute a write to the database. However, multiple clients may be writing at the same time so we used a Transaction as this is supposed to run again if the data is modified by another Transaction during execution.
Something seemed to go wrong though: When seperate clients (two different mobile devices) are running the code below ± simultaneously, only one of them seems to update the value in the database.
What could be the cause of this and how can we prevent this in the future?
static Future< bool > voteOnUser(GroupData groupData, String voteeID) async {
await Firestore.instance.runTransaction((Transaction transaction) async {
DocumentReference groupRef = Firestore.instance
.collection("groups")
.document( groupData.getGroupCode() );
DocumentSnapshot ds = await transaction.get( groupRef );
/// Initialize lists
Map<dynamic, dynamic> dbData = ds.data['newVotes'];
Map<String, int> convertedData = new Map<String, int>();
/// Loop the database Map and add the values to the data Map
/// All data is assumed to exist and definitely be of the desired types
dbData.forEach( (key, value) {
convertedData[key.toString()] = value;
} );
if (convertedData.containsKey( voteeID ))
convertedData[voteeID] += 1;
else convertedData[voteeID] = 1;
Map<String, dynamic> incremented = new Map<String, dynamic>();
incremented['newVotes'] = convertedData;
await transaction.update(groupRef, incremented);
});
return true;
}
Edit: The purpose of this code is to vote on a user that is located in a map within a document. Several clients may vote at the same time and each vote should increment the value of one element in the map by one.
When two clients vote at the same time on for example the user with ID 'joe' who had no votes before, the expected result is that joe would have two votes. However, when testing simultaneous voting, we observed that only one vote was added to the database instead of the desired two votes.
Edit 2: At first, the document exists and contains an empty map newVotes. We were testing with two different mobile devices and casted a vote at ± the same point in time. Almost instantly, the document was updated and a user ID was added to the previously empty map with one vote while we expected two votes to be mapped to that key.
Edit 3: First, a document is created with the following fields: newVotes (map) to map a number of votes to a unique user id, totalVotes (map) to keep track of the total votes and members (List) which is a list of all user id's in that group. newVotes And totalVotes are empty at this point and members contains a few IDs (in this case, two unique Google IDs)
Once this document exists, clients can vote with the given code. In my case we both voted on the same google user ID (say: "ID1") and expected the map newVotes to contain one element: {"ID1": 2}. However, we both voted at the same time (no errors were thrown) and the newVotes field contained {"ID1":1}.
Transactions does not guarantee protection from modification of the same entity concurently - unless SERIALIZED (or "Read for update locking"). It guarantees that every operations in transaction will be applied at once upon commit or discarded if tx is rolled back
To guarantee that there are no conflicts either:
Synchronize access to entity - lock upon reading
Synchrionize method execution
Serialize transaction
Use version controll mechanism
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 have read enter link description here.
As per this post, OwnableState participant's node will persist transactin copy but not state copy.
As per corda documentation OwnableState is a contract state that can have a single owner. OwnableState have participant properties. I have added Buyer and Seller as participant in OwnableState but state is only stored in Owners vault only not participant. However in LinearState state is persisted on both participants vault.
I need to understand diffrence between LinearState participant and OwnableState participant in corda.
Here is the logic a node's vault uses to decide whether the node should store the state:
internal fun isRelevant(state: ContractState, myKeys: Set<PublicKey>): Boolean {
val keysToCheck = when (state) {
is OwnableState -> listOf(state.owner.owningKey)
else -> state.participants.map { it.owningKey }
}
return keysToCheck.any { it in myKeys }
}
In words:
For an OwnableState, the node will store the state if OwnableState.owner corresponds to one of the node's keys
For ContractState and any other ContractState subclass, the node will store the state if ContractState.participants contains one of the node's keys
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).