我已经复制了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);
}
答案 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;
}