Corda responder flow not answering

411 views Asked by At

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!

2

There are 2 answers

4
Adel Rustum On BEST ANSWER
  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.
0
Julian On

Another thing missing was the key of the counterParty. When initialising the command, I added

final Command<ContractToken.Commands.Issue> txCommand = new Command<>(
                    new ContractToken.Commands.Issue(),
                    ImmutableList.of(getOurIdentity().getOwningKey(), counterParty.getOwningKey()));