Obligation Cordapp中的唯一标识符

时间:2018-03-29 13:43:20

标签: corda

我已经复制了Obligation Cordapp Transfer功能,我对Unique Identifier的linearId感到震惊。我已经成功地运行了问题Cordapp并且为了转移义务,我已经提供了带有生成的Obligation的linearId的flow命令。我通过linearId传递的参数被解释为外部ID [UniqueIdentifier中的参数]而不是 id ,因此无法找到要传输的义务。

以下是问题的参考。

创建的Obligation的生成ID是

** linearId:externalId:null

id:“4799c549-8c2b-401f-90dd-1dc115fbcfba”

Thu Mar 29 18:41:02 IST 2018>>> flow start TransferObligation$Initiator newLender: "O=PartyC,L=Paris,C=FR",anonymous: false,linearId: "4799c549-8c2b-401f-90dd-1dc115fbcfba

传递的参数,linearId必须作为id [在UniqueIdentifier中的参数并且如果外部id不等于null则随机生成]根据Obligation Cordapp并且必须执行所需的传输功能。相反,它将linearId作为externalId [UniqueIdentifier中的参数]传递,因此total linearId变为 externalId_id

>Linear Id parameter is:4799c549-8c2b-401f-90dd-1dc115fbcfba_ace60f85-b360-4cf7b198-4d3d471f9d63
>Obtaining IOU from vault.
>States Size:0

观察ace60f85-b360-4cf7b198-4d3d471f9d63作为id附加,该id是随机生成的,无法找到生成的Obligation。

corda将如何解释通过linearId? as externalId / Id默认? 在Obligation Cordapp中,它在样本中显示为Id并且完成了所需的工作。但是我正在执行的cordapp将传递的参数作为externalId。

或者必须在代码级别进行任何更改才能将linearId参数作为id?

编辑1: 我们正在开发java中的代码转移义务供参考。虽然它只是一个复制品。请看看它

  package com.example.flow;

import co.paralleluniverse.fibers.Suspendable;
import com.example.contract.ActivityContract;
import com.example.state.Activity;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import net.corda.confidential.IdentitySyncFlow;
import net.corda.confidential.SwapIdentitiesFlow;
import net.corda.core.contracts.Command;
import net.corda.core.contracts.StateAndRef;
import net.corda.core.contracts.UniqueIdentifier;
import net.corda.core.flows.*;
import net.corda.core.identity.AbstractParty;
import net.corda.core.identity.AnonymousParty;
import net.corda.core.identity.Party;
import net.corda.core.transactions.SignedTransaction;
import net.corda.core.transactions.TransactionBuilder;
import net.corda.core.utilities.ProgressTracker;
import net.corda.core.utilities.ProgressTracker.Step;


import java.security.PublicKey;
import java.util.*;

import static com.example.contract.ActivityContract.Activity_Contract_ID;

public class ActivityTransferFlow {

    @StartableByRPC
    @InitiatingFlow
    public static class Initiator extends ActivityBaseFlow{


    public final UniqueIdentifier linearId;
    public final Party newLender;
    public final Boolean anonymous;

    private final Step INITIATION = new Step("Obtaining IOU from vault.");
    private final Step BUILDING = new Step("Building and Verifying Transaction");
    private final Step SIGNING = new Step("Signing gathered transaction");
    private final Step SYNCING = new Step("Syncing gathered identities "){

        @Override
        public ProgressTracker childProgressTracker() {
            return IdentitySyncFlow.Send.Companion.tracker();
        }
    };

    private final Step GATHERING = new Step("Gathering counterparty signatures"){

        @Override
        public ProgressTracker childProgressTracker() {
            return CollectSignaturesFlow.Companion.tracker();
        }
    };

    private final Step FINALISING = new Step("Finalising transaction"){

        @Override
        public ProgressTracker childProgressTracker() {
            return FinalityFlow.Companion.tracker();
        }
    };

       private final ProgressTracker progressTracker = new ProgressTracker(
               INITIATION,
               BUILDING,
               SIGNING,
               SYNCING,
               GATHERING,
               FINALISING
       );

        public Initiator(UniqueIdentifier linearId, Party newLender, Boolean anonymous) {

            this.linearId = linearId;
            this.newLender = newLender;
            this.anonymous = anonymous;
        }

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

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

            // step1:Retrieve Activity specified by linear id from the vault
            progressTracker.setCurrentStep(INITIATION);

            final StateAndRef<Activity> activityToTransfer= getObligationByLinearId(linearId);
            }



            final Activity inputActivity=activityToTransfer.getState().getData();

            //step2:This flow can only be initiated by current recipient
            final AbstractParty lenderIdentity =getLenderIdentity(inputActivity);

            //step3:Abort if the borrower started this flow
            if(!getOurIdentity().equals(lenderIdentity))
            {
             throw new IllegalStateException("Activity transfer can only be initiated by the lender.");
            }

            //step4:Creating the new obligation state reflecting a new lender
             progressTracker.setCurrentStep(BUILDING);
             final Activity transferredActivity =createOutputActivity(inputActivity);

             //step4:Create transfer command
             final List<PublicKey> signerKeys = new ImmutableList.Builder<PublicKey>()
                     .addAll(inputActivity.getParticipantKeys())
                     .add(transferredActivity.getLender().getOwningKey()).build();

            final Command transferCommand = new Command<>(new ActivityContract.Commands.ActivityTransfer(), signerKeys);

            //step5:Create a transaction builder and then add states and commands.
            final TransactionBuilder builder = new TransactionBuilder(getNotary())
                    .addInputState(activityToTransfer)
                    .addOutputState(transferredActivity, Activity_Contract_ID)
                    .addCommand(transferCommand);

            //step6:Verify and sign the transaction
            progressTracker.setCurrentStep(SIGNING);
            builder.verify(getServiceHub());
            final SignedTransaction ptx=getServiceHub().signInitialTransaction(builder, inputActivity.getLender().getOwningKey());

            //step7:Getting party object from the borrower
            progressTracker.setCurrentStep(SYNCING);
            final Party borrower=getBorrowerIdentity(inputActivity);

            //step8:Send any keys or certificates so the signers can verify each other identity
            Set<FlowSession> sessions=new HashSet<>();
            Set<Party> parties= ImmutableSet.of(borrower,newLender);
            for (Party party:parties) {

                  sessions.add(initiateFlow(party));

            }
            subFlow(new IdentitySyncFlow.Send(sessions,ptx.getTx(),SYNCING.childProgressTracker()));

            //step9:Gathering signatures from the borrower and the new lender
             progressTracker.setCurrentStep(GATHERING);
             final SignedTransaction stx=subFlow(new CollectSignaturesFlow(
                     ptx,
                     sessions,
                     ImmutableList.of(inputActivity.getLender().getOwningKey()),
                     GATHERING.childProgressTracker()
             ));

            //Step10:Notarise and record the transaction into vault and broadcast the transaction

            progressTracker.setCurrentStep(FINALISING);
            return subFlow(new FinalityFlow(stx,ImmutableSet.of(getOurIdentity())));
        }

        @Suspendable
        private AbstractParty getLenderIdentity(Activity inputObligation) {
            if (inputObligation.getLender() instanceof AnonymousParty) {
                return resolveIdentity(inputObligation.getLender());
            } else {
                return inputObligation.getLender();
            }
        }

        @Suspendable
        private Activity createOutputActivity(Activity inputActivity) throws FlowException {
            if (anonymous) {
                final HashMap<Party, AnonymousParty> txKeys = subFlow(new SwapIdentitiesFlow(newLender));
                if (!txKeys.containsKey(newLender)) {
                    throw new FlowException("Couldn't get lender's conf. identity.");
                }
                final AnonymousParty anonymousLender = txKeys.get(newLender);
                return inputActivity.withNewLender(anonymousLender);
            } else {
                return inputActivity.withNewLender(newLender);
            }
        }

        @Suspendable
        private Party getBorrowerIdentity(Activity inputActivity) {
            if (inputActivity.getBorrower() instanceof AnonymousParty) {
                return resolveIdentity(inputActivity.getBorrower());
            } else {
                return (Party) inputActivity.getBorrower();
            }
        }
    }



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

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

        @Suspendable
        @Override
        public SignedTransaction call() throws FlowException {
            subFlow(new IdentitySyncFlow.Receive(otherFlow));
            SignedTransaction stx = subFlow(new ActivityBaseFlow.SignTxFlowNoChecking(otherFlow, SignTransactionFlow.Companion.tracker()));
            return waitForLedgerCommit(stx.getId());
        }
    }

}

编辑2: ActivityBaseFlow中的getObligationByLinearId方法 我们使用的命令是

  

flow start ActivityTransferFlow $ Initiator linearId:d21827b7-e4be-4874-9383-e9f339d7c9ea,newLender:“O = PartyC,L = Paris,C = FR”,匿名:false

StateAndRef<Activity> getObligationByLinearId(UniqueIdentifier linearId) throws FlowException {
    System.out.println("Linear Id parameter is:"+linearId);
    QueryCriteria queryCriteria = new QueryCriteria.LinearStateQueryCriteria(
            null,
            ImmutableList.of(linearId),
            Vault.StateStatus.UNCONSUMED,
            null);
    List<StateAndRef<Activity>> obligations = getServiceHub().getVaultService().queryBy(Activity.class, queryCriteria).getStates();
    if (obligations.size() != 1) {
        System.out.println("Linear Id 1:"+linearId);
        throw new FlowException(String.format("Obligation with id %s not found.", linearId));
    }
    //System.out.println("Linear Id 2:"+linearId);
    return obligations.get(0);
}

1 个答案:

答案 0 :(得分:1)

UniqueIdentifier构造函数将flow start的字符串输入作为externalId

更改您的流程以接受字符串,然后使用UniqueIdentifier.fromString(inputString)手动解析它。即

public Initiator(String inputString, Party newLender, Boolean anonymous) {

            this.linearId = UniqueIdentifier.fromString(inputString);
            this.newLender = newLender;
            this.anonymous = anonymous;
        }