tokencordacorda-flow

Corda responder flow not answering


I created a very easy flow test with IntelliJ.

@Test
    public void dummyTest() throws InterruptedException, ExecutionException {

        Party Alice = aliceNode.getServices().getIdentityService().wellKnownPartyFromX500Name(new CordaX500Name("Alice", "London", "GB"));

        FlowInitiatorIssueToken flow = new FlowInitiatorIssueToken(30, alice, network.getDefaultNotaryIdentity());
        SignedTransaction transaction = bobNode.startFlow(flow).get();
        // The error occurs because of this line ....

        State state = (State) transaction.getTx().getOutputStates().get(0);

        assertEquals(state.getParticipants(), alice);

        VaultQueryCriteria criteria = new VaultQueryCriteria(Vault.StateStatus.ALL);

        aliceNode.transaction(() -> {
            Vault.Page<State> result = aliceNode.getServices().getVaultService().queryBy(State.class, criteria);
            assertTrue(result.getStates().size() > 0);

            return null;
        });

    network.runNetwork();        
    }

IntelliJ is not able to fulfil the test and gives me the error

statemachine.FlowMonitor. - Flow with id 3982ab19-3e5b-4737-9adf-e4a6a97d20e6 has been waiting for 117 seconds to receive messages from parties [O=Alice, L=London, C=GB]

This led to the assumption that the responder flow is not doing anything.

// ******************
// * Initiator flow *
// ******************

@InitiatingFlow
@StartableByRPC
public class FlowInitiatorIssueToken extends FlowLogic<SignedTransaction> {
    private final Integer value;
    private final Party counterParty;
    private final Party notary; 

    public FlowInitiatorIssuToken(Integer value, Party counterParty, Party notary) {
        this.value = value;
        this.counterParty = counterParty;
        this.notary = notary; 
    }

    /**
     * The flow logic is encapsulated within the call() method.
     */
    @Suspendable
    @Override
    public SignedTransaction call() throws FlowException {


        /*------------------------------
         * SENDING AND RECEIVING DATA *
        ------------------------------*/

        FlowSession issueTokenSession = initiateFlow((Party) counterParty);


        /*------------------------------------------
         * GATHERING OTHER TRANSACTION COMPONENTS * 
        ------------------------------------------*/

        State outputState = new State(this.value, this.counterParty);
        Command<ContractToken.Commands.Issue> command = new Command<>(new ContractToken.Commands.Issue(), getOurIdentity().getOwningKey());

        /*------------------------
         * TRANSACTION BUILDING *
        ------------------------*/

        TransactionBuilder txBuilder = new TransactionBuilder(notary)
                .addOutputState(outputState, ContractToken.ID)
                .addCommand(command);


        /*-----------------------
         * TRANSACTION SIGNING *
        -----------------------*/

        SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);


        /*------------------------------
         * FINALISING THE TRANSACTION *
        ------------------------------*/

        System.out.println("Hey World!");

        subFlow(new FinalityFlow(signedTx, issueTokenSession));

        return null;
    }

}

// ******************
// * Responder flow *
// ******************
@InitiatedBy(FlowInitiatorIssueToken.class)
public class FlowResponderIssueToken extends FlowLogic<SignedTransaction> {
    private final FlowSession issueTokenSession;

    public FlowResponderIssueToken(FlowSession issueTokenSession) {
        this.issueTokenSession = issueTokenSession;
    }

    @Suspendable
    @Override
    public SignedTransaction call() throws FlowException {


        /*-----------------------------------------
         * RESPONDING TO COLLECT_SIGNATURES_FLOW *
        -----------------------------------------*/


        class SignTxFlow extends SignTransactionFlow {
            private SignTxFlow(FlowSession issueTokenSession) {
                super(issueTokenSession);
            }

            @Override
            protected void checkTransaction(SignedTransaction stx) {

            }
        }

        SecureHash idOfTxWeSigned = subFlow(new SignTxFlow(issueTokenSession, SignTransactionFlow.tracker())).getId();

        /*------------------------------
         * FINALISING THE TRANSACTION *
        ------------------------------*/

        subFlow(new ReceiveFinalityFlow(issueTokenSession, idOfTxWeSigned));
        return null;
    }
}

The initiator flow is executed. I can see that, because the System.out.println("Hey World!") command is showing up in the logs. However, I don't know whether the responder flow is never started by the initiator flow or it is just not reacting. Maybe you can help me with that.

Thanks!


Solution

    1. You didn't call CollectSignaturesFlow in your initiator; that's why you didn't initiate a "conversation" with the responder for them to sign the transaction. See example here.
    2. SignTransactionFlow that you call in your responder is a "reply" to calling CollectSignaturesFlow in the initiator.
    3. Btw, you must verify a transaction before you sign it in your initiator. See example here.