在我的cordapp中使用帐户net.corda.core.CordaRuntimeException:java.lang.IllegalArgumentException:我找不到流中的一个错误:找不到匿名方(DLBBYFJYhpPQXEMcTZtuzkg8ixptu92L3dqiN4boD1o2FN) 此错误来自“最终确定流程”行
这是错误日志
java.lang.IllegalArgumentException: Could not find Party for Anonymous(DLKiQpwdw3E7CewLhUatjRpKvCMkHDhEoEYXfAUrp33z7)
at net.corda.core.identity.IdentityUtils.groupAbstractPartyByWellKnownParty(IdentityUtils.kt:47) ~[corda-core-4.3.jar:?]
at net.corda.core.identity.IdentityUtils.groupAbstractPartyByWellKnownParty(IdentityUtils.kt:63) ~[corda-core-4.3.jar:?]
at net.corda.core.flows.FinalityFlow.extractExternalParticipants(FinalityFlow.kt:224) ~[corda-core-4.3.jar:?]
at net.corda.core.flows.FinalityFlow.call(FinalityFlow.kt:134) ~[corda-core-4.3.jar:?]
at net.corda.core.flows.FinalityFlow.call(FinalityFlow.kt:39) ~[corda-core-4.3.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.subFlow(FlowStateMachineImpl.kt:330) ~[corda-node-4.3.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:326) ~[corda-core-4.3.jar:?]
at com.template.flows.LoanTransferFlow.call(LoanTransferFlow.java:129) ~[?:?]
at com.template.flows.LoanTransferFlow.call(LoanTransferFlow.java:29) ~[?:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:270) ~[corda-node-4.3.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:46) ~[corda-node-4.3.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_212]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[?:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[?:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_212]
at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:63) ~[corda-node-4.3.jar:?]
流处于输入状态和3输出状态。
这是流程代码:
@InitiatingFlow
@StartableByRPC
public class LoanTransferFlow extends FlowLogic<SignedTransaction> {
final AccountInfo borrower;
final AccountInfo lender;
UniqueIdentifier loanId = null;
StateAndRef<InfoState> inputBorrowerState = null;
private final static Logger logger = LoggerFactory.getLogger(LoanTransferFlow.class);
public LoanTransferFlow(AccountInfo borrower, AccountInfo lender, UniqueIdentifier loanId, StateAndRef<InfoState> inputBorrowerState) {
this.borrower = borrower;
this.lender = lender;
this.loanId = loanId;
this.inputBorrowerState = inputBorrowerState;
}
@Suspendable
@Override
public SignedTransaction call() throws FlowException {
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
List<StateAndRef<InfoState>> matchingLenderStates = null;
StateAndRef<InfoState> inputInfoLenderState = null;
StateAndRef<LoanState> inputLoanState = null;
//
// PublicKey myKey = subFlow(new RequestKeyForAccount(lender.getHost(), lender.getIdentifier().getId())).getOwningKey();
// PublicKey borrowerKey = subFlow(new RequestKeyForAccount(borrower.getHost(), borrower.getIdentifier().getId())).getOwningKey();
try {
Vault.Page<InfoState> lenderStateresults = (Vault.Page<InfoState>) subFlow(new CheckAccountInfoFlow(lender.getName()));
matchingLenderStates = lenderStateresults.getStates();
} catch (Exception e) {
throw new FlowException(e);
}
if ((matchingLenderStates == null) || (matchingLenderStates.isEmpty())) {
throw new FlowException("No Initial Borrower State Exists");
} else {
inputInfoLenderState = matchingLenderStates.get(matchingLenderStates.size() - 1);
}
QueryCriteria criteriaForLoanVault = new QueryCriteria.LinearStateQueryCriteria(
null,
ImmutableList.of(loanId),
Vault.StateStatus.UNCONSUMED,
null);
List<StateAndRef<LoanState>> matchingLoanStates = getServiceHub().getVaultService().queryBy(LoanState.class, criteriaForLoanVault).getStates();
if ((matchingLoanStates == null) || (matchingLoanStates.isEmpty())) {
throw new FlowException("No Initial Loan State Exists");
} else {
inputLoanState = matchingLoanStates.get(0);
}
subFlow(new ShareStateAndSyncAccounts(inputLoanState, borrower.getHost()));
subFlow(new ShareStateAndSyncAccounts(inputLoanState, lender.getHost()));
PublicKey myKey = inputLoanState.getState().getData().getLender();
PublicKey borrowerKey = inputLoanState.getState().getData().getBorrower();
logger.info("inputState" + inputLoanState.getState().getData().getBorrower() + inputLoanState.getState().getData().getLender());
logger.info("mykey" + myKey);
logger.info("borrowerKey" + borrowerKey);
float updatedBorrowerCreditscore = inputLoanState.getState().getData().getCreditScore() - 15;
float updatedLenderCreditscore = inputInfoLenderState.getState().getData().getCreditScore() + 30;
float amount = inputLoanState.getState().getData().getAmount();
float borrowerBalance = inputBorrowerState.getState().getData().getBalance();
float lenderBalance = inputInfoLenderState.getState().getData().getBalance();
if (amount > lenderBalance) {
throw new FlowException("Insufficient Lender Balance");
}
float updatedBorrowerBalance = borrowerBalance + amount;
float updatedLenderBalance = lenderBalance - amount;
final Command<LendingContract.Commands.Transfer> command = new Command<LendingContract.Commands.Transfer>(new LendingContract.Commands.Transfer(), Arrays.asList(myKey, borrowerKey));
LoanState outputLoanState = new LoanState(borrowerKey, myKey, amount, updatedBorrowerCreditscore, "approved", new UniqueIdentifier());
logger.info("outputState" + outputLoanState.getLender() + outputLoanState.getBorrower());
InfoState outputBorrowerState = new InfoState(new AnonymousParty(borrowerKey), updatedBorrowerCreditscore, updatedBorrowerBalance, new UniqueIdentifier());
InfoState outputLenderState = new InfoState(new AnonymousParty(myKey), updatedLenderCreditscore, updatedLenderBalance, new UniqueIdentifier());
TransactionBuilder txBuilder = new TransactionBuilder(notary);
txBuilder.addInputState(inputLoanState);
txBuilder.addCommand(command);
txBuilder.addOutputState(outputBorrowerState, LendingContract.ID);
txBuilder.addOutputState(outputLenderState, LendingContract.ID);
txBuilder.addOutputState(outputLoanState, LendingContract.ID);
txBuilder.verify(getServiceHub());
SignedTransaction signedInitialTransaction = getServiceHub().signInitialTransaction(txBuilder, Arrays.asList(getOurIdentity().getOwningKey(), myKey));
FlowSession counterPartySession = initiateFlow(borrower.getHost());
List<? extends TransactionSignature> accountToMoveToSignature = subFlow(new CollectSignatureFlow(signedInitialTransaction, counterPartySession, borrowerKey));
SignedTransaction fullySignedTx = signedInitialTransaction.withAdditionalSignature(accountToMoveToSignature.get(0));
return subFlow(new FinalityFlow(fullySignedTx));
进入源代码后,错误似乎来自此--->
@Throws(IllegalArgumentException::class)
fun groupAbstractPartyByWellKnownParty(serviceHub: ServiceHub, parties: Collection<AbstractParty>, ignoreUnrecognisedParties: Boolean): Map<Party, List<AbstractParty>> {
val partyToPublicKey: Iterable<Pair<Party, AbstractParty>> = parties.mapNotNull {
(serviceHub.identityService.wellKnownPartyFromAnonymous(it) ?: if (ignoreUnrecognisedParties) return@mapNotNull null else throw IllegalArgumentException("Could not find Party for $it")) to it
}
return partyToPublicKey.toMultiMap()
}
我有类似的流程,但是没有输入状态在起作用。
州级:
private PublicKey borrower;
private PublicKey lender;
private float amount;
private float creditScore;
private String status;
private final UniqueIdentifier linearId;
仅供参考,在这种状态下,我也为借款人和贷方使用了PublicKey数据类型
仅供参考,该流在不使用输入状态的情况下工作正常 帐户创建流程
@Suspendable
override fun call(): AccountInfo {
//Create a new account
try {
val existingAccount = accountService.accountInfo(name = acctName)
if (existingAccount.size >= 1) {
throw FlowException("Account Already Exists")
}
val newAccount = accountService.createAccount(name = acctName).toCompletableFuture().getOrThrow()
val acct = newAccount.state.data
return acct
} catch (e: Exception) {
throw FlowException(e)
}
}
帐户共享流程
@Suspendable
override fun call(): Boolean {
//Create a new account
val AllmyAccounts = accountService.ourAccounts()
val SharedAccount = AllmyAccounts.single { it.state.data.name == acctNameShared }.state.data.identifier.id
accountService.shareAccountInfoWithParty(SharedAccount,shareTo)
return true
}
仅供参考-不同节点上有两个帐户
还添加了输入状态流。
public LoanRequestFlow(AccountInfo borrower, AccountInfo lender, float amount) {
this.borrower = borrower;
this.amount = amount;
this.lender = lender;
}
private final ProgressTracker progressTracker = new ProgressTracker();
private final static Logger logger = LoggerFactory.getLogger(LoanRequestFlow.class);
@Override
public ProgressTracker getProgressTracker() {
return progressTracker;
}
@Suspendable
@Override
public SignedTransaction call() throws FlowException {
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
List<StateAndRef<InfoState>> matchingBorrowerStates = null;
StateAndRef<InfoState> inputInfoBorrowerState = null;
PublicKey myKey = subFlow(new NewKeyForAccount(borrower.getIdentifier().getId())).getOwningKey();
PublicKey lenderKey = subFlow(new RequestKeyForAccount(lender)).getOwningKey();
try {
Vault.Page<InfoState> borrowerStateresults = (Vault.Page<InfoState>) subFlow(new CheckAccountInfoFlow(borrower.getName()));
matchingBorrowerStates = borrowerStateresults.getStates();
} catch (Exception e) {
throw new FlowException(e);
}
if ((matchingBorrowerStates == null) || (matchingBorrowerStates.isEmpty())) {
throw new FlowException("No Initial Borrower State Exists");
} else {
inputInfoBorrowerState = matchingBorrowerStates.get(matchingBorrowerStates.size() - 1);
}
final Command<LendingContract.Commands.Request> command = new Command<LendingContract.Commands.Request>(new LendingContract.Commands.Request(), Arrays.asList(myKey, lenderKey));
LoanState loanOutputState = new LoanState(myKey, lenderKey, amount, inputInfoBorrowerState.getState().getData().getCreditScore(), "pending", new UniqueIdentifier());
TransactionBuilder txBuilder = new TransactionBuilder(notary);
txBuilder.addCommand(command);
txBuilder.addOutputState(loanOutputState, LendingContract.ID);
txBuilder.verify(getServiceHub());
SignedTransaction signedInitialTransaction = getServiceHub().signInitialTransaction(txBuilder, Arrays.asList(getOurIdentity().getOwningKey(), myKey));
FlowSession counterPartySession = initiateFlow(lender.getHost());
List<? extends TransactionSignature> accountToMoveToSignature = subFlow(new CollectSignatureFlow(signedInitialTransaction, counterPartySession, lenderKey));
SignedTransaction fullySignedTx = signedInitialTransaction.withAdditionalSignature(accountToMoveToSignature.get(0));
return subFlow(new FinalityFlow(fullySignedTx));
答案 0 :(得分:0)
出现此错误的原因是,“确定性”流程正在查看您的输出状态和输入状态,并从中检索参与者。
然后尝试通过公钥将这些参与者分解为各方。
如果该节点在出现错误之前尚未看到那些公钥,则会抛出该错误。
由于问题中只有代码片段,因此不清楚导致问题的原因。
但是,以下示例将复制该问题:
LongByReference
如果您在测试中运行此流程(kotlin仅仅是因为我在现有项目中进行了测试),则会收到错误消息:
Observable
.FromEventPattern<EventHandler, EventArgs>(_ => SystemEvents.DisplaySettingsChanged += _, _ => SystemEvents.DisplaySettingsChanged -= _)
.Select(_ => SystemParameters.WorkArea)
.Do(_ =>
{
Left = _.Right - Width;
Top = _.Bottom - Height;
})
.Subscribe();
但是,如果您更改了这两行:
public class SaveLoanFlow extends FlowLogic<SignedTransaction> {
private AnonymousParty borrower;
private AnonymousParty lender;
private float amount;
private float creditScore;
public SaveLoanFlow(AnonymousParty borrower, AnonymousParty lender, float amount, float creditScore) {
this.borrower = borrower;
this.lender = lender;
this.amount = amount;
this.creditScore = creditScore;
}
@Suspendable
@Override
public SignedTransaction call() throws FlowException {
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
List<PublicKey> signingPubKeys = Arrays.asList(getOurIdentity().getOwningKey());
TransactionBuilder txBuilder = new TransactionBuilder(notary);
LoanState loanState = new LoanState(borrower, lender, amount, creditScore, "NEW", new UniqueIdentifier());
txBuilder.addOutputState(loanState);
txBuilder.addCommand(new LendingContract.Commands.Transfer(), signingPubKeys);
SignedTransaction signedInitialTransaction = getServiceHub().signInitialTransaction(txBuilder, signingPubKeys);
return subFlow(new FinalityFlow(signedInitialTransaction));
}
}
public class LendingContract implements Contract {
public static final Party ID = null;
@Override
public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException {
}
/**
* This contract only implements one command, Transfer.
*/
public interface Commands extends CommandData {
class Transfer implements Commands {}
}
}
@BelongsToContract(LendingContract.class)
public class LoanState implements LinearState {
private AnonymousParty borrower;
private AnonymousParty lender;
private float amount;
private float creditScore;
private String status;
private UniqueIdentifier linearId;
public LoanState(AnonymousParty borrower, AnonymousParty lender, float amount, float creditScore, String status, UniqueIdentifier linearId) {
this.borrower = borrower;
this.lender = lender;
this.amount = amount;
this.creditScore = creditScore;
this.status = status;
this.linearId = linearId;
}
@NotNull
@Override
public List<AbstractParty> getParticipants() {
return ImmutableList.of(borrower, lender);
}
@NotNull
@Override
public UniqueIdentifier getLinearId() {
return linearId;
}
//
//other getters/setters
//
}
以便从同一节点请求密钥,流程将运行并且测试将通过。
@Test
fun `Find party`() {
val borrowerAccountService = borrowerNode.services.cordaService(KeyManagementBackedAccountService::class.java)
val lenderAccountService = lenderNode.services.cordaService(KeyManagementBackedAccountService::class.java)
val borrowerAccount = borrowerAccountService.createAccount("Borrower-Account").getOrThrow().state.data
val lenderAccount = lenderAccountService.createAccount("Lender-Account").getOrThrow().state.data
network.runNetwork()
borrowerAccountService.shareAccountInfoWithParty(borrowerAccount.identifier.id, lenderNode.info.legalIdentities[0])
lenderAccountService.shareAccountInfoWithParty(lenderAccount.identifier.id, borrowerNode.info.legalIdentities[0])
network.runNetwork()
val borrowerPartyFuture = borrowerNode.startFlow(RequestKeyForAccount(borrowerAccount))
val lenderPartyFuture = lenderNode.startFlow(RequestKeyForAccount(lenderAccount))
network.runNetwork()
val borrowerParty = borrowerPartyFuture.getOrThrow()
val lenderParty = lenderPartyFuture.getOrThrow()
val newLoanFuture = lenderNode.startFlow(SaveLoanFlow(borrowerParty, lenderParty, 2F, 4F))
network.runNetwork()
val savedLoan = newLoanFuture.getOrThrow()
Assert.notEmpty(savedLoan.tx.outputStates)
}
}
原因是现在贷方知道两个帐户的密钥。
因此在您未显示的代码中,您遇到了类似的问题,因为两个节点上的帐户密钥均不可用。
您似乎在问题中发布的流程之前运行了另一个流程,因为您执行了保管库查找并将其用作输入状态。
其中一个节点上可能不存在来自保存状态的键之一。
出于(无法预见?)设计的原因,当将状态保存到流中时,不会保存生成的键,因此必须运行额外的流以确保所有生成的键都已同步。
您可以在未显示流程的末尾作为子流程来执行此操作,这可能会解决问题。
val borrowerPartyFuture = borrowerNode.startFlow(RequestKeyForAccount(borrowerAccount))
val lenderPartyFuture = lenderNode.startFlow(RequestKeyForAccount(lenderAccount))
跟踪this issue以获取更多信息。