Corda:一次创建并使用相同状态吗?

时间:2018-10-05 09:29:20

标签: corda

是否可以在一个流中创建和使用相同的Corda状态,或者在不同的子流中创建和使用它? 我收到以下错误: Caused by: net.corda.core.flows.NotaryException: Unable to notarise transactionBEDE8C3F8F2D7A646A9F7D1948DAF77CDAFC37F3B086E09FC766F0D412F02690: One or more input states have been used in another transaction

2 个答案:

答案 0 :(得分:1)

是的,您可以在单个流程中创建和使用相同的Corda状态。

您需要执行两个步骤:

  1. 创建第一个发布新状态的交易
  2. 创建第二个使用新状态的交易

请注意,如果您创建第二笔交易,并导致交易对手在完成第一笔交易之前调用ResolveTransactionFlow,这将导致TransactionResolutionException,因为您在第一笔交易中没有您的存储空间尚未分发。例如,在运行CollectSignaturesFlow时会发生这种情况。

以下是在同一流程中构建两个事务的示例:

@InitiatingFlow
@StartableByRPC
class TwoTransactionsFlow(val otherParty: Party) : FlowLogic<Unit>() {
    @Suspendable
    override fun call() {
        val otherPartySessions = listOf(initiateFlow(otherParty))

        val transactionBuilderOne = TransactionBuilder()
        // TODO: Add notary and transaction components.
        val partSignedTransactionOne = serviceHub.signInitialTransaction(transactionBuilderOne)
        val fullySignedTransactionOne = subFlow(CollectSignaturesFlow(partSignedTransactionOne, otherPartySessions))
        val notarisedTransactionOne = subFlow(FinalityFlow(fullySignedTransactionOne))

        val transactionOneFirstOutputRef = StateRef(notarisedTransactionOne.id, 0)
        val transactionOneFirstOutput = serviceHub.toStateAndRef<ContractState>(transactionOneFirstOutputRef)

        val transactionBuilderTwo = TransactionBuilder()
                .addInputState(transactionOneFirstOutput)
        // TODO: Add notary and other transaction components.
        val partSignedTransactionTwo = serviceHub.signInitialTransaction(transactionBuilderTwo)
        val fullySignedTransactionTwo = subFlow(CollectSignaturesFlow(partSignedTransactionTwo, otherPartySessions))
        subFlow(FinalityFlow(fullySignedTransactionTwo))
    }
}

答案 1 :(得分:1)

还有更多要考虑的地方

  • 在Corda 4中,当在一个流中创建和使用状态时,相应的响应者流应调用ReceiveFinalityFlow 2次(在签名者的情况下,也应调用SignTransactionFlow),否则将引发错误:-java.util.concurrent.ExecutionException :net.corda.core.flows.UnexpectedFlowEndException:尝试使用空缓冲区访问已结束的会话SessionId(toLong = 1984916257986245538)。

Java中启动程序流的代码段

...

        // Signing the transaction.
        SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);

        // Creating a session with the other party.
        FlowSession otherPartySession = initiateFlow(otherParty);

        // Obtaining the counterparty's signature.
        SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(
                signedTx, Arrays.asList(otherPartySession), CollectSignaturesFlow.Companion.tracker()));

        //notarized transaction
        SignedTransaction notraizedtransaction = subFlow(new FinalityFlow(fullySignedTx, otherPartySession));

        //------------------------------------------------------------------------------------------------------------
        // STEP-2:
        //  SINCE NOW WE HAVE A NEW UNCONSUMED RECORD-ANCHOR SO WE MUST MAKE IT CONSUMED ( BY USING THE PREVIOUS OUTPUT AS AN INPUT)
        //
        //------------------------------------------------------------------------------------------------------------

        StateAndRef oldStateref =  getServiceHub().toStateAndRef(new StateRef(notraizedtransaction.getId(),0));

        Command storeCommand = new Command<>(new AnchorStateContract.Commands.ApproveRecAnchorCmd(), requiredSigners);

        TransactionBuilder txBuilder2 = new TransactionBuilder(notary)
                .addInputState(oldStateref)
                .addCommand(storeCommand);

        txBuilder2.verify(getServiceHub());

        // signing
        SignedTransaction signedTx2 = getServiceHub().signInitialTransaction(txBuilder2);

        // Finalising the transaction.
        SignedTransaction fullySignedTx2 = subFlow(new CollectSignaturesFlow(
                signedTx2, Arrays.asList(otherPartySession), CollectSignaturesFlow.Companion.tracker()));


        //notarized transaction
        return subFlow(new FinalityFlow(fullySignedTx2, otherPartySession));
}

Java ResponderFlow的代码段

@InitiatedBy(Initiator.class)
public class Responder extends FlowLogic<SignedTransaction> {
    private FlowSession otherPartySession;

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

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

        //this class is used inside call function for the verification purposes before signed by this party
        class SignTxFlow1 extends SignTransactionFlow
        {
            private SignTxFlow1(FlowSession otherPartySession) {
                super(otherPartySession);
            }

            @Override
            protected void checkTransaction(SignedTransaction stx) {
                requireThat(require -> {
                    // Validation Logic
                    return null;
                });
            }
        }

        //this class is used inside call function for the verification purposes before signed by this party
        class SignTxFlow2 extends SignTransactionFlow
        {
            private SignTxFlow2(FlowSession otherPartySession) {
                super(otherPartySession);
            }

            @Override
            protected void checkTransaction(SignedTransaction stx) {
                requireThat(require -> {
                    // Validation Logic
                    return null;
                });
            }
        }
        //Validation, signing and storing of first transaction data
        SecureHash expectedTxId1 = subFlow(new SignTxFlow1(otherPartySession)).getId();
        subFlow(new ReceiveFinalityFlow(otherPartySession, expectedTxId1));

        //Validation, signing and storing of second transaction data
        SecureHash expectedTxId2 = subFlow(new SignTxFlow2(otherPartySession)).getId();
        return subFlow(new ReceiveFinalityFlow(otherPartySession, expectedTxId2));

    }
}