Search code examples
cordacorda-flow

In R3 Corda, how to trigger another node to run specific flow inside on a flow?


I have this code, i want to trigger another node to run specific flow inside on a flow. When Requester Node run the IssuanceFlow, I want some code in that flow when it will trigger the Approver Node to run ApproverIssuanceFlow. And I want to use the output of ApproverIssuanceFlow as an input in the next step in IssuanceFlow.

public class IssuanceFlow {

@InitiatingFlow
@StartableByRPC
public static class IssuanceInitiator extends FlowLogic<SignedTransaction> {
    private Amount<Currency> amount;

    public IssuanceInitiator(Amount<Currency> amount) {
        this.amount = amount;
    }

    //STEP GENERATOR
    private final ProgressTracker.Step GENERATE_TRX = new ProgressTracker.Step("Generating trx.");
    private final ProgressTracker.Step VERIFY_TRX = new ProgressTracker.Step("Verify trx.");
    private final ProgressTracker.Step SIGN_TRX = new ProgressTracker.Step("Sign trx.");
    private final ProgressTracker.Step GATHER_SIGN = new ProgressTracker.Step("Collecting other sign.") {
        @Override
        public ProgressTracker childProgressTracker() {
            return CollectSignaturesFlow.Companion.tracker();
        }
    };
    private final ProgressTracker.Step FINALIZE_TRX = new ProgressTracker.Step("Notarize and record.") {
        @Override
        public ProgressTracker childProgressTracker() {
            return FinalityFlow.Companion.tracker();
        }
    };

    public ProgressTracker progressTracker = new ProgressTracker(
            GENERATE_TRX,
            VERIFY_TRX,
            SIGN_TRX,
            GATHER_SIGN,
            FINALIZE_TRX
    );

    @Override
    public ProgressTracker getProgressTracker() {
        return progressTracker;
    }

    @Suspendable
    @Override
    public SignedTransaction call() throws FlowException {
        //obtain notary
        final Party notary =getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);

        progressTracker.setCurrentStep(GENERATE_TRX);
        UniqueIdentifier linearID = new UniqueIdentifier();
        Date issuanceDate = new Date();
        Party approver = getServiceHub().getNetworkMapCache().getPeerByLegalName(CordaX500Name.parse("O=Approver,L=Jakarta,C=ID")); //always choose Central Bank as approver

        **// I want to trigger another node to run another flow, and use the output in this flow**

        //build output
        IssuanceState newIssuance = new IssuanceState(linearID, this.amount, this.getOurIdentity(), approver, issuanceDate);

        //build transaction
        TransactionBuilder transactionBuilder = new TransactionBuilder(notary)
                .addOutputState(newIssuance)
                .addCommand(new IssuanceContract.Commands.Issue(), Arrays.asList(getOurIdentity().getOwningKey(), approver.getOwningKey()));

        progressTracker.setCurrentStep(VERIFY_TRX);
        //verify transaction
        transactionBuilder.verify(getServiceHub());

        progressTracker.setCurrentStep(SIGN_TRX);
        //sign transaction
        final SignedTransaction partiallySign = getServiceHub().signInitialTransaction(transactionBuilder);

        progressTracker.setCurrentStep(GATHER_SIGN);
        //send to counterparty, back with signature
        FlowSession otherPartySession = initiateFlow(approver);
        final SignedTransaction fullySign = subFlow(new CollectSignaturesFlow(partiallySign,Arrays.asList(otherPartySession)));

        progressTracker.setCurrentStep(FINALIZE_TRX);
        //notarize, record transaction
        final SignedTransaction finalityFlow = subFlow(new FinalityFlow(fullySign, Arrays.asList(otherPartySession)));

        return finalityFlow;
    }
}

@InitiatedBy(IssuanceInitiator.class)
public static class IssuanceResponder extends FlowLogic<Void> {
    private FlowSession otherPartySession;

    public IssuanceResponder(FlowSession otherPartySession) {
        this.otherPartySession = otherPartySession;
    }

    @Override
    @Suspendable
    public Void call() throws FlowException {
        SignedTransaction signedTransaction = subFlow(new SignTransactionFlow(otherPartySession) {
            @Override
            @Suspendable
            protected void checkTransaction(@NotNull SignedTransaction stx) throws FlowException {

            }
        });

        //stored to db
        subFlow(new ReceiveFinalityFlow(otherPartySession,signedTransaction.getId()));
        return null;
    }
}

Solution

  • You cannot trigger anything in other nodes, it would be a big breach of security if a party could trigger unexpected behaviors in other parties' nodes. Remember that other nodes are expected to be other companies, competitors, legal entities in general.

    What you want to do could be achieved with a simple p2p communication between parties using send or sendAndReceive (documentation is here). They allow the initiator flow to send a message to the receiver and the receiver could send back another message. That response could be the input for whatever you need to do next. Still all this needs to be done anyway inside a session in a Flow, so in a transaction between PartyA - the initiator - and PartyB - the receiver.