我们可以在发展corda状态的同时修改参与者列表吗



我做了一个Corda项目,其中我有一个策略状态,有一个发送方和两个接收方。我有三个节点卖方,保险公司和LSP。我从卖方节点上的一个帐户创建了一个新的PolicyState,并使用PolicyCreationFlow将其发送到保险公司和LSP上的帐户。这个流程运行良好。但是,当我试图从保险公司的终端更新此状态的字段时,它不起作用,并生成了一个异常。这意味着当我创建保单状态时,发送方是卖方节点,而当我更新保单状态时则发送方是保险公司,接收方是这两个节点中的其余节点。

策略状态的代码如下:

@BelongsToContract(PolicyContract.class)
public class PolicyState implements LinearState  {
//private variables
private final UniqueIdentifier linearID;
private final String sellerID;
private final String policyID ;
private final String insurerID;
private final int policyNo;
private final double faceValue;
private final double deathBenefits;
private final double annualPremium;
private final double cashSurrenderValue;
private final String policyStartDate;
private final boolean isVerfied;
private List<AnonymousParty> receivingparties;
private final AnonymousParty policyOwner;
@Nullable
private final boolean isValid;
//    private final AnonymousParty inuranceCompany;
public PolicyState(UniqueIdentifier linearID, String policyID, String sellerID, String insurerID, int policyNo, double faceValue, double deathBenefits, double annualPremium,
double cashSurrenderValue, String policyStartDate, AnonymousParty policyOwner, boolean isVerfied, List<AnonymousParty> receivingparties, boolean isValid) {
this.linearID = linearID;
this.policyID = policyID;
this.sellerID = sellerID;
this.insurerID = insurerID;
this.policyNo = policyNo;
this.faceValue = faceValue;
this.deathBenefits = deathBenefits;
this.annualPremium = annualPremium;
this.cashSurrenderValue = cashSurrenderValue;
this.policyStartDate = policyStartDate;
this.policyOwner = policyOwner;
this.isVerfied = isVerfied;
this.receivingparties = receivingparties;
this.isValid = isValid;
//        this.inuranceCompany = receivingparties.get(0);
}
/////Getters for the Fields
public String getPolicyID() {
return policyID;
}
public String getSellerID() {
return sellerID;
}
public String getInsurerID() {
return insurerID;
}
public int getPolicyNo() {
return policyNo;
}
public double getFaceValue() {
return faceValue;
}
public double getDeathBenefits() {
return deathBenefits;
}
public double getAnnualPremium() {
return annualPremium;
}
public double getCashSurrenderValue() {
return cashSurrenderValue;
}
public String getPolicyStartDate() {
return policyStartDate;
}
public boolean isVerfied() {
return isVerfied;
}
public AnonymousParty getPolicyOwner() {
return policyOwner;
}
public boolean isValid() {
return isValid;
}
public List<AnonymousParty> getReceivingparties() {
return receivingparties;
}
public PolicyState withNewPolicyOwner(AnonymousParty newOwner){
return new PolicyState(linearID, policyID,sellerID, insurerID, policyNo, faceValue, deathBenefits, annualPremium, cashSurrenderValue, policyStartDate, newOwner, isVerfied, receivingparties, isValid);
}
public PolicyState deletePolicy(AnonymousParty policyOwner){
return new PolicyState(linearID, policyID,sellerID, insurerID, policyNo, faceValue, deathBenefits, annualPremium, cashSurrenderValue, policyStartDate, policyOwner, isVerfied,receivingparties, false);
}
@NotNull
@Override
public UniqueIdentifier getLinearId() {
return linearID;
}
@NotNull
@Override
public List<AbstractParty> getParticipants() {
//        return Arrays.asList(policyOwner,inuranceCompany);
List<AbstractParty> allParts = new ArrayList<>();
allParts.addAll(receivingparties);
allParts.add(policyOwner);
return allParts;
}
}

策略创建流程的代码如下:

@InitiatingFlow
@StartableByRPC
public static class PolicyCreation extends FlowLogic<SignedTransaction> {
private final ProgressTracker.Step GENERATING_TRANSACTION = new ProgressTracker.Step("Generating transaction.");
private final ProgressTracker.Step ADDING_POLICY = new ProgressTracker.Step("Adding the Policy State to Transaction.");
private final ProgressTracker.Step VERIFYING_TRANSACTION = new ProgressTracker.Step("Verifying contract constraints.");
private final ProgressTracker.Step SIGNING_TRANSACTION = new ProgressTracker.Step("Signing transaction with our private key.");
private final ProgressTracker.Step GATHERING_SIGS = new ProgressTracker.Step("Gathering the counterparty's signature.") {
@Override
public ProgressTracker childProgressTracker() {
return CollectSignaturesFlow.Companion.tracker();
}
};
private final ProgressTracker.Step FINALISING_TRANSACTION = new ProgressTracker.Step("Obtaining notary signature and recording transaction.") {
@Override
public ProgressTracker childProgressTracker() {
return FinalityFlow.Companion.tracker();
}
};
private final ProgressTracker progressTracker = new ProgressTracker(
GENERATING_TRANSACTION,
ADDING_POLICY,
VERIFYING_TRANSACTION,
SIGNING_TRANSACTION,
GATHERING_SIGS,
FINALISING_TRANSACTION
);

@Override
public ProgressTracker getProgressTracker() {
return progressTracker;
}
//PolicyState Fields
private final String policyID;
private final String sellerID;
private final String insurerID;
private final int policyNo;
private final double faceValue;
private final double deathBenefits;
private final double annualPremium;
private final double cashSurrenderValue;
private final String policyStartDate;
private final String policyOwner;
private final String insuranceCompany;
private final String lsp;
//Constructor for PolicyCreation
public PolicyCreation(String policyID, String sellerID, String insurerID, int policyNo, double faceValue, double deathBenefits, double annualPremium,
double cashSurrenderValue, String policyStartDate, String policyOwner, String insuranceCompany, String lsp) {
this.policyID = policyID;
this.sellerID = sellerID;
this.insurerID = insurerID;
this.policyNo = policyNo;
this.faceValue = faceValue;
this.deathBenefits = deathBenefits;
this.annualPremium = annualPremium;
this.cashSurrenderValue = cashSurrenderValue;
this.policyStartDate = policyStartDate;
this.policyOwner = policyOwner;
this.insuranceCompany = insuranceCompany;
this.lsp = lsp;
}
@Suspendable
@Override
public SignedTransaction call() throws FlowException {
AccountService accountService = getServiceHub().cordaService(KeyManagementBackedAccountService.class);
//Owner Account
AccountInfo policyOwnerAccountInfo = accountService.accountInfo(policyOwner).get(0).getState().getData();
PublicKey policyOwnerKey = subFlow(new NewKeyForAccount(policyOwnerAccountInfo.getIdentifier().getId())).getOwningKey();
//Insurance Company Account
AccountInfo insurerAccountInfo = accountService.accountInfo(insuranceCompany).get(0).getState().getData();
AnonymousParty insuranceCompanyAccount = subFlow(new RequestKeyForAccount(insurerAccountInfo));
//LSP account
AccountInfo lspAccountInfo = accountService.accountInfo(lsp).get(0).getState().getData();
AnonymousParty lspAccount = subFlow(new RequestKeyForAccount(lspAccountInfo));
List<AccountInfo> parties = new ArrayList<>();
parties.add(insurerAccountInfo);
parties.add(lspAccountInfo);

// Step 1. Get a reference to the notary service on our network and our key pair.
// Note: ongoing work to support multiple notary identities is still in progress.
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
//            UniqueIdentifier policyLinearId = new UniqueIdentifier(policyID);
final PolicyState output = new PolicyState(new UniqueIdentifier(policyID), policyID, sellerID, insurerID, policyNo, faceValue, deathBenefits, annualPremium, cashSurrenderValue, policyStartDate,new AnonymousParty(policyOwnerKey), false, Arrays.asList(insuranceCompanyAccount,lspAccount), true);
progressTracker.setCurrentStep(GENERATING_TRANSACTION);
final TransactionBuilder builder = new TransactionBuilder(notary);
//Adding outputState to the transaction
progressTracker.setCurrentStep(ADDING_POLICY);
builder.addOutputState(output, PolicyContract.ID);
builder.addCommand(new PolicyContract.Commands.Create(), Arrays.asList(policyOwnerKey,insuranceCompanyAccount.getOwningKey(),lspAccount.getOwningKey()));
//          self sign Transaction
progressTracker.setCurrentStep(SIGNING_TRANSACTION);
builder.verify(getServiceHub());
SignedTransaction locallySignedTx = getServiceHub().signInitialTransaction(builder, Arrays.asList(getOurIdentity().getOwningKey(),policyOwnerKey));

progressTracker.setCurrentStep(GATHERING_SIGS);
FlowSession session = initiateFlow(insurerAccountInfo.getHost());
List<TransactionSignature> accountToMoveToSignature = (List<TransactionSignature>) subFlow(new CollectSignatureFlow(locallySignedTx,
session,insuranceCompanyAccount.getOwningKey()));
SignedTransaction signedByCounterParty = locallySignedTx.withAdditionalSignatures(accountToMoveToSignature);
FlowSession session1 = initiateFlow(lspAccountInfo.getHost());
List<TransactionSignature> accountToMoveToSignature1 = (List<TransactionSignature>) subFlow(new CollectSignatureFlow(signedByCounterParty,
session1,lspAccount.getOwningKey()));
signedByCounterParty = signedByCounterParty.withAdditionalSignatures(accountToMoveToSignature1);
progressTracker.setCurrentStep(FINALISING_TRANSACTION);
return subFlow(new FinalityFlow(signedByCounterParty, session,session1));
//            return subFlow(new FinalityFlow(signedByCounterParty,
//                    Arrays.asList(session).stream().filter(it -> it.getCounterparty() != getOurIdentity()).collect(Collectors.toList())));
}
}
@InitiatedBy(PolicyCreation.class)
public static class PolicyCreationResponder extends FlowLogic<String> {
//private variable
private FlowSession counterpartySession;
//Constructor
public PolicyCreationResponder(FlowSession counterpartySession) {
this.counterpartySession = counterpartySession;
}
@Override
@Suspendable
public String call() throws FlowException {
AtomicReference accountMovedTo = new AtomicReference< AccountInfo>();
SignedTransaction signedTransaction =  subFlow(new SignTransactionFlow(counterpartySession) {
@Suspendable
@Override
protected void checkTransaction(SignedTransaction stx) throws FlowException {
// Custom Logic to validate transaction.
}
});
subFlow(new ReceiveFinalityFlow(counterpartySession));
return "Policy Sent";
}
}

VerifyPolicyFlow(更新流(的代码如下:

@InitiatingFlow
@StartableByRPC
public static class VerifyPolicy extends FlowLogic<SignedTransaction> {
private final UniqueIdentifier linearID;
private final String sender;
//        private final ArrayList<String> receivers;
private final String receiver1;
private final String receiver2;
private final boolean isVerified;

public VerifyPolicy(UniqueIdentifier linearID, String sender, String receiver1, String receiver2, boolean isVerified) {
this.linearID = linearID;
this.sender = sender;
this.receiver1 = receiver1;
this.receiver2 = receiver2;
this.isVerified = isVerified;
}
//        private ArrayList<AccountInfo> receiversAccountInfo = new ArrayList<>();
@Suspendable
@Override
public SignedTransaction call() throws FlowException {
AccountService accountService = getServiceHub().cordaService(KeyManagementBackedAccountService.class);
//Owner Account
AccountInfo senderAccountInfo = accountService.accountInfo(sender).get(0).getState().getData();
PublicKey senderKey = subFlow(new NewKeyForAccount(senderAccountInfo.getIdentifier().getId())).getOwningKey();
AccountInfo receiver1AccountInfo = accountService.accountInfo(receiver1).get(0).getState().getData();
AnonymousParty receiver1Account = subFlow(new RequestKeyForAccount(receiver1AccountInfo));
//LSP account
AccountInfo receiver2AccountInfo = accountService.accountInfo(receiver2).get(0).getState().getData();
AnonymousParty receiver2Account = subFlow(new RequestKeyForAccount(receiver2AccountInfo));
List<UUID> listOfLinearIds = new ArrayList<>();
listOfLinearIds.add(linearID.getId());
QueryCriteria queryCriteria = new QueryCriteria.LinearStateQueryCriteria(null, listOfLinearIds);
// 2. Get a reference to the inputState data that we are going to settle.
Vault.Page results = getServiceHub().getVaultService().queryBy(PolicyState.class, queryCriteria);
StateAndRef inputStateAndRefToTransfer = (StateAndRef) results.getStates().get(0);
PolicyState inputStateToTransfer = (PolicyState) inputStateAndRefToTransfer.getState().getData();
// Step 1. Get a reference to the notary service on our network and our key pair.
// Note: ongoing work to support multiple notary identities is still in progress.
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
//            UniqueIdentifier policyLinearId = new UniqueIdentifier(policyID);
final PolicyState output = new PolicyState(inputStateToTransfer.getLinearId(), inputStateToTransfer.getPolicyID(),
inputStateToTransfer.getSellerID(), inputStateToTransfer.getInsurerID(), inputStateToTransfer.getPolicyNo(),
inputStateToTransfer.getFaceValue(),inputStateToTransfer.getDeathBenefits(), inputStateToTransfer.getAnnualPremium(),
inputStateToTransfer.getCashSurrenderValue(), inputStateToTransfer.getPolicyStartDate(),
new AnonymousParty(senderKey), isVerified, Arrays.asList(receiver1Account,receiver2Account), true);
final TransactionBuilder builder = new TransactionBuilder(notary);
//Adding outputState to the transaction
builder.addInputState(inputStateAndRefToTransfer);
builder.addOutputState(output, PolicyContract.ID);
builder.addCommand(new PolicyContract.Commands.Update(), Arrays.asList(senderKey,receiver1Account.getOwningKey(),receiver2Account.getOwningKey()));
builder.verify(getServiceHub());
SignedTransaction locallySignedTx = getServiceHub().signInitialTransaction(builder, Arrays.asList(getOurIdentity().getOwningKey(),senderKey));
FlowSession session = initiateFlow(receiver1AccountInfo.getHost());
List<TransactionSignature> accountToMoveToSignature = (List<TransactionSignature>) subFlow(new CollectSignatureFlow(locallySignedTx,
session,receiver1Account.getOwningKey()));
SignedTransaction signedByCounterParty = locallySignedTx.withAdditionalSignatures(accountToMoveToSignature);
FlowSession session1 = initiateFlow(receiver2AccountInfo.getHost());
List<TransactionSignature> accountToMoveToSignature1 = (List<TransactionSignature>) subFlow(new CollectSignatureFlow(signedByCounterParty,
session1,receiver2Account.getOwningKey()));
signedByCounterParty = signedByCounterParty.withAdditionalSignatures(accountToMoveToSignature1);
return subFlow(new FinalityFlow(signedByCounterParty, session,session1));
//            return null;
}
}
@InitiatedBy(VerifyPolicy.class)
public static class VerifyPolicyResponder extends FlowLogic<String> {
//private variable
private FlowSession counterpartySession;
//Constructor
public VerifyPolicyResponder(FlowSession counterpartySession) {
this.counterpartySession = counterpartySession;
}
@Override
@Suspendable
public String call() throws FlowException {
AtomicReference accountMovedTo = new AtomicReference< AccountInfo>();
SignedTransaction signedTransaction =  subFlow(new SignTransactionFlow(counterpartySession) {
@Suspendable
@Override
protected void checkTransaction(SignedTransaction stx) throws FlowException {
// Custom Logic to validate transaction.
}
});
subFlow(new ReceiveFinalityFlow(counterpartySession));
return "Policy Sent";
}
}

保险公司节点的日志显示:

java.lang.IllegalArgumentException: Could not find Party for Anonymous(DLCtNGZXmvmEJCHLNA1GCCwYv39gGJxsgf7MTfytmKgtT4)
at net.corda.core.identity.IdentityUtils.groupAbstractPartyByWellKnownParty(IdentityUtils.kt:47) ~[corda-core-4.5.jar:?]
at net.corda.core.identity.IdentityUtils.groupAbstractPartyByWellKnownParty(IdentityUtils.kt:63) ~[corda-core-4.5.jar:?]
at net.corda.core.flows.FinalityFlow.extractExternalParticipants(FinalityFlow.kt:252) ~[corda-core-4.5.jar:?]
at net.corda.core.flows.FinalityFlow.call(FinalityFlow.kt:162) ~[corda-core-4.5.jar:?]
at net.corda.core.flows.FinalityFlow.call(FinalityFlow.kt:43) ~[corda-core-4.5.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.subFlow(FlowStateMachineImpl.kt:362) ~[corda-node-4.5.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:397) ~[corda-core-4.5.jar:?]
at com.BLife.flows.VerifyPolicyFlow$VerifyPolicy.call(VerifyPolicyFlow.java:107) ~[?:?]
at com.BLife.flows.VerifyPolicyFlow$VerifyPolicy.call(VerifyPolicyFlow.java:30) ~[?:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:299) ~[corda-node-4.5.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:66) ~[corda-node-4.5.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_265]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_265]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[?:1.8.0_265]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[?:1.8.0_265]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_265]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_265]
at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:63) ~[corda-node-4.5.jar:?]

卖方节点的日志(它是更新流的接收器之一(说:

net.corda.core.flows.UnexpectedFlowEndException: Counter-flow errored
at Received unexpected counter-flow exception from peer O=InsuranceCompany, L=New York, C=US.() ~[?:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.fillInLocalStackTrace(FlowStateMachineImpl.kt:204) ~[corda-node-4.5.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.processEventsUntilFlowIsResumed(FlowStateMachineImpl.kt:192) ~[corda-node-4.5.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.suspend(FlowStateMachineImpl.kt:506) ~[corda-node-4.5.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.receive(FlowSessionImpl.kt:67) ~[corda-node-4.5.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.receive(FlowSessionImpl.kt:71) ~[corda-node-4.5.jar:?]
at net.corda.core.flows.ReceiveTransactionFlow.call(ReceiveTransactionFlow.kt:103) ~[corda-core-4.5.jar:?]
at net.corda.core.flows.ReceiveTransactionFlow.call(ReceiveTransactionFlow.kt:31) ~[corda-core-4.5.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.subFlow(FlowStateMachineImpl.kt:362) ~[corda-node-4.5.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:397) ~[corda-core-4.5.jar:?]
at net.corda.core.flows.ReceiveFinalityFlow.call(FinalityFlow.kt:285) ~[corda-core-4.5.jar:?]
at net.corda.core.flows.ReceiveFinalityFlow.call(FinalityFlow.kt:280) ~[corda-core-4.5.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.subFlow(FlowStateMachineImpl.kt:362) ~[corda-node-4.5.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:397) ~[corda-core-4.5.jar:?]
at com.BLife.flows.VerifyPolicyFlow$VerifyPolicyResponder.call(VerifyPolicyFlow.java:133) ~[?:?]
at com.BLife.flows.VerifyPolicyFlow$VerifyPolicyResponder.call(VerifyPolicyFlow.java:113) ~[?:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:299) ~[corda-node-4.5.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:66) ~[corda-node-4.5.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) ~[quasar-core-0.7.12_r3-jdk8.jar:0.7.12_r3]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_265]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_265]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[?:1.8.0_265]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[?:1.8.0_265]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_265]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_265]
at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:63) ~[corda-node-4.5.jar:?]

我该如何纠正,因为根据项目要求,卖方将在区块链上添加保单,保险公司将验证相同的保单?

通常,出现此问题是因为接收方没有发送方的AccountInfo。创建卖家帐户时,还会生成该帐户的公钥,但其他参与者不知道该密钥与卖家节点的X.500名称之间的映射。

您可以将其添加到PolicyCreation流的末尾:

subFlow(ShareStateAndSyncAccounts(state, borrowerAccountInfo.state.data.host))

文件。

作为参考:这里和这里。

最新更新