We came to know about the Issue flow of doing transaction in a single node even without notarization. The doc link referring above fact is given below. flows-used-in-the-measurements
Help me to know the implementation of the Issue flow in Corda 4.1 version.
Just use an empty list of flow session in the Finality Flow.
Note that you do not need notarization for issuance since there is nothing to double spend. However, the notary should still be passed in the transaction to identify the correct notary for all future transaction on the state.
Here is how your call method should look like:
public SignedTransaction call() throws FlowException {
Party notary = ..// fetch the notary from serviceHub
// Create an instance of your output state
OutputState os = ...
// Create Transaction Builder and call verify
TransactionBuilder transactionBuilder = ...
transactionBuilder.verify(getServiceHub());
//Sign the trnx.
final SignedTransaction selfSignedTx = getServiceHub().signInitialTransaction(transactionBuilder);
//Just pass an empty list of flow session in the finality flow.
return subFlow(new FinalityFlow(selfSignedTx, new HashSet<FlowSession>(0)));
}
Related
I would like to ask if it is possible to save (to be produced by transaction) more states that are linked to each other.
Let's assume following case (it is simplified to be more readable):
States:
ParentState {
...
}
ChildState {
LinkedPointer<ParentState> parent;
}
Flow:
parent = new ParentState(...)
child = new ChildState(...)
child.setParent(new LinearPointer<>(parent.getLinearId(), RestrictedSecurity.class))
TransactionBuilder txBuilder = new TransactionBuilder(notary)
.addCommand(new ParentContract.Commands.Create(), Arrays.asList(getOurIdentity().getOwningKey()));
txBuilder.addOutputState(parent);
txBuilder.addOutputState(child);
txBuilder.verify(getServiceHub());
SignedTransaction signedTransaction = getServiceHub().signInitialTransaction(transactionBuilder);
List<FlowSession> allSessions = new ArrayList<>();
for (AbstractParty party : participants) {
if (!party.equals(getOurIdentity())) {
allSessions.add(initiateFlow(party));
}
}
subFlow(new FinalityFlow(signedTransaction, allSessions, StatesToRecord.ALL_VISIBLE));
This case allways throws
The LinearState with ID 44afa7dd-10a9-408d-a44f-03a7a3d9dbb8 is unknown to this node or it has been exited from the ledger.
But both states are in same transaction so it should be known (exception is thrown on "master" node that initialized flow). May I ask if someone solved this problem or it is necessary to create states without links?
Thank you in advance, Jan.
I tried save states without links or linked but in separate transactions but it is not intended usecase.
I've been trying to learn Corda and I have a specific use case for a contract which involved multiple participants.
Forgive me if my understanding is incorrect and please correct me if I'm wrong! :)
From what I understand, the contract is where we implement the verification functionality for a a transaction that calls upon said contract.
The state can hold the 'state' of a current transaction along with any data regarding the transaction.
The flow is the the business logic associated with a state/contract.
I have a specific use case that I want to address within a contract, and this involves multiple parties that share the same contract/transaction info.
I want a state to be able to hold multiple participants.
Purely from what I understand, I have coded the following for a state:
#BelongsToContract(MasterContract.class)
public class MasterState implements ContractState {
private final List<Party> employers = emptyList();
private final List<Party> contractors = emptyList();
private final String projectName;
public MasterState(String projectName, List<Party> employers, List<Party> contractors) {
this.projectName = projectName;
this.employers.addAll(employers);
this.contractors.addAll(contractors);
}
public String getProjectName() {
return projectName;
}
public List<Party> getEmployers() {
return employers;
}
public List<Party> getContractors() {
return contractors;
}
#Override
public List<AbstractParty> getParticipants() {
List<AbstractParty> allParts = new ArrayList<>();
allParts.addAll(employers);
allParts.addAll(contractors);
return allParts;
}
}
I want to be able to create (via a Command) a new instance of MasterContract by providing multiple 'employers' or 'contractors'.
I am trying to define: MasterCreationFlow.call() as follows:
#Suspendable
#Override
public Void call() throws FlowException {
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
// Create the transaction components
JCTMasterState outputState = new JCTMasterState(projectName, Arrays.asList(getOurIdentity()), contractors);
//List of required signers:
List<PublicKey> requiredSigners = Arrays.asList(getOurIdentity().getOwningKey());
requiredSigners.addAll(getOwningKeys(contractors));
Command createCommand = new Command<>(new JCTMasterContract.Create(), requiredSigners);
...
However, I'm stuck with the idea of InitiateFlow(). As it seems like you can only do this between 2 parties. I understand that Corda is point-to-point. But I want to understand what exactly FlowSession does? So far, I have read that FlowSessions are just a channel between 2 parties that is then consumed by some SubFlow. Is there any way to extend FlowSession to create a shared session between multiple counter-parties? Or would I have to initiate multiple flows?
Thanks in advance!
You are right that FlowSession is between 2 parties, which is the party calling initiateFlow(someParty) method and someParty.
So, in order for you to create multiple sessions between your flow initiator and your contractors, you can do this:
Set<FlowSession> sessions = contractors.stream().map(it ->
initiateFlow(it)).collect(Collectors.toSet());
Then for instance you can pass the sessions to collect signatures from the contractors:
final SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(partSignedTx,
sessions, CollectSignaturesFlow.Companion.tracker()));
On top of the proposed solution by Adel ( https://stackoverflow.com/a/60438425/7733418 ) adding the Owners Public key into the signer list might be necessary, if not yet done.
I have the following Corda flow, where I pass in a list of Partys and attempt to initiate a flow session with each one:
#InitiatingFlow
#StartableByRPC
class MyFlow(val parties: List<Party>) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
// Flow logic.
val flowSessions = parties.forEach { party ->
initiateFlow(party)
}
// Flow logic.
}
}
However, when I call it, I get the following exception:
java.lang.IllegalStateException: Attempted to initiateFlow() twice in
the same InitiatingFlow com.template.TwoTransactionsFlow#1ba8d137 for
the same party O=PartyB, L=London, C=GB. This isn't supported in this
version of Corda. Alternatively you may initiate a new flow by calling
initiateFlow() in an #InitiatingFlow sub-flow.
What is the cause of this exception?
This exception indicates that you have attempted to initiate a flow session twice with the same party within the same flow context, in this case because the parties list you're passing into the flow contains duplicates. This is not allowed.
You should either:
Re-use existing sessions with a given party (i.e. create a single FlowSession with PartyA and use the same flow session to send PartyA information twice)
Subflow into another #InitiatingFlow and create the FlowSession there (each #InitiatingFlow and its in-lined subflows share the same flow context)
I was performing testing on corda observer node. On IOU issue, put call of flow for observer. same thing on IOU lender transfer flow (Flow for changing lender property to the new Party).
I issue IOU From partyA to PartyB. On observer node stateAndRef gets displayed too.
but when performed transferred IOU, no change gets displayed on observer node. It's still showing old state.
Does observer node keep unconsume states only in vault or consume/unconsumed transaction both?
below code is working for one flow IOU issue only not for other flow:
I am referring IOU example here
Below is the code I called from each Flow:
object BroadcastTransaction {
#InitiatingFlow
class BroadcastTransactionToObservers(private val stx: SignedTransaction, private val observers: List<Party>) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val sessions = observers.map { initiateFlow(it) }
sessions.forEach { subFlow(SendTransactionFlow(it, stx)) }
}
}
#InitiatedBy(BroadcastTransactionToObservers::class)
class RecordTransactionAsObserver(private val otherSession: FlowSession) :FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow( ReceiveTransactionFlow(
otherSideSession = otherSession,
checkSufficientSignatures = true,
statesToRecord = StatesToRecord.ALL_VISIBLE
)
)
}
}
}
I have checked logs for node getting not enough signature even after put call to observer flow just after finalityflow call...plz help in this regard?
Finally found my mistake. In logs i got error "Insufficient signature corda". I had passes signedsignature after finalityflow but not passed finalityflow result to above mention flow.
Currently we are planning to have one "Draft" version of contract which will not be sent to the counterparty and the initiator can make any changes before send it to the network, so this should be as one "unshared fact". As we know Corda and the vault is used for shared facts, so here I am not sure whether we can still use vault to store this type of "unshared fact", my idea as below and I already can make this work in my local based on the tutorial CorDapp, but would like to get some inputs from other Corda team/experts.
The main change is in the initiator flow:
Initiate the create command's only with the initiator's key
Do not invoke the "CollectSignaturesFlow" so this will not be sent to any others
Invoke "FinalityFlow" after the verify(), so this will be committed to the ledger
Below are the codes for above mentioned points.
override fun call(): SignedTransaction {
// We create a transaction builder
val txBuilder = TransactionBuilder()
val notaryIdentity = serviceHub.networkMapCache.getAnyNotary()
txBuilder.notary = notaryIdentity
// We create the transaction's components.
val ourIdentity = serviceHub.myInfo.legalIdentity
val iou = TemplateState(iouValue, ourIdentity, ourIdentity)
val txCommand = Command(TemplateContract.Create(), listOf(ourIdentity.owningKey))
// Adding the item's to the builder.
txBuilder.withItems(iou, txCommand)
// Verifying the transaction.
txBuilder.toWireTransaction().toLedgerTransaction(serviceHub).verify()
// Signing the transaction.
val partSignedTx = serviceHub.signInitialTransaction(txBuilder)
// Finalising the transaction.
return subFlow(FinalityFlow(partSignedTx)).single()
}
You can indeed create an unshared fact in Corda! The key here is in the state's participants list. Just add yourself in the participants list and only your public key to the command. Here's a simple example:
//Contract and State.
class UnsharedFact: Contract {
override val legalContractReference: SecureHash = SecureHash.zeroHash
override fun verify(tx: TransactionForContract) = Unit // Stubbed out.
class Create: CommandData
data class State(val parties: Set<Party>): ContractState {
override val contract: Contract get() = UnsharedFact()
override val participants: List<AbstractParty> get() = parties.toList()
fun addParty(newParty: Party) = copy(parties = parties + newParty)
}
}
// Create flow.
#InitiatingFlow
#StartableByRPC
class CreateUnsharedFact(): FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val me = serviceHub.myInfo.legalIdentity
val notary = serviceHub.networkMapCache.getAnyNotary()
val state = UnsharedFact.State(setOf(me))
val command = Command(UnsharedFact.Create(), listOf(me.owningKey))
val utx = TransactionBuilder(notary = notary).withItems(state, command)
val stx = serviceHub.signInitialTransaction(utx)
return subFlow(FinalityFlow(stx)).single()
}
}
When FinalityFlow is called, you will be the only node that receives the output state.
If you wish to subsequently involve another party then you can create a new version of the state using the addParty method on UnsharedFact.State. Then, create a new transaction, adding the original state as the input and the new version (with the new party) as the output. When this transaction is finalised (notarised) then both parties will have a copy in their respective vaults. Now, I guess the name 'UnsharedFact' is inappropriate :)
You can also remove parties using a similar approach.