Я создаю новое состояние в потоке, а затем пытаюсь использовать это состояние, используя эталонный ввод. Но каждый раз, когда я вижу в результате неиспользованное состояние, хотя я предоставлял эталонное состояние на входе транзакции.
public SignedTransaction call() throws FlowException {
//------------------------------------------------------------------------------------------------------------
// STEP-1:
// FIRST FLOW MUST CREATE THE NEW STATE WHICH HAS NO INPUT ( THIS WILL CREATE NEW RECORD-ANCHOR WITH LINEARID )
//
//------------------------------------------------------------------------------------------------------------
// We retrieve the notary identity from the network map.
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
// We create the transaction components.
AnchorState outputState = new
AnchorState(ownerId,contentHash,description,classid,timestamp,expiry, getOurIdentity(), otherParty,new UniqueIdentifier());
//required signers
List<PublicKey> requiredSigners = Arrays.asList(getOurIdentity().getOwningKey(),otherParty.getOwningKey());
//send create command with required signer signatures as below
Command command = new Command<>(new AnchorStateContract.Commands.CreateRecAnchorCmd(), requiredSigners);
// We create a transaction builder and add the components.
TransactionBuilder txBuilder = new TransactionBuilder(notary)
.addOutputState(outputState, AnchorStateContract.ID)
.addCommand(command);
// Verifying the transaction.
txBuilder.verify(getServiceHub());
// 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)
.addOutputState(outputState, AnchorStateContract.ID)
.addCommand(storeCommand);
txBuilder2.verify(getServiceHub());
// signing
SignedTransaction signedTx2 = getServiceHub().signInitialTransaction(txBuilder2);
// Creating a session with the other party.
FlowSession otherPartySession2 = initiateFlow(otherParty);
// Finalising the transaction.
SignedTransaction fullySignedTx2 = subFlow(new CollectSignaturesFlow(
signedTx2, Arrays.asList(otherPartySession2), CollectSignaturesFlow.Companion.tracker()));
//notarized transaction
return subFlow(new FinalityFlow(fullySignedTx2, otherPartySession2));
}
В своем классе инициатора потока я сначала создаю новое состояние хэша, которым я являюсьвызывая как AnchorState. Это состояние исходит от одного из участников, а затем оно просит другого участника подписать. после этого подписанная запись сохраняется в бухгалтерской книге, но ее ссылка используется в качестве входных данных для нового изменения состояния, я просто хочу сделать это состояние как использованное, а не как неиспользованное.
Класс отвечающего потока участника B выглядит следующим образом:
public SignedTransaction call() throws FlowException
{
//this class is used inside call function for the verification purposes before signed by this party
class SignTxFlow extends SignTransactionFlow
{
private SignTxFlow(FlowSession otherPartySession) {
super(otherPartySession);
}
@Override
protected void checkTransaction(SignedTransaction stx) {
requireThat(require -> {
ContractState output = stx.getTx().getOutputs().get(0).getData();
require.using("This must be an AnchorState transaction.", output instanceof AnchorState);
AnchorState state = (AnchorState) output;
require.using("The AnchorState's value should be more than 6 characters", state.getContentHash().length() > 6);
return null;
});
}
}
SecureHash expectedTxId = subFlow(new SignTxFlow(otherPartySession)).getId();
return subFlow(new ReceiveFinalityFlow(otherPartySession, expectedTxId));
}
Этот поток успешно выполняется и возвращает мне уникальный идентификатор для транзакции, но я перепробовал все и не смог найти, как изменить состояниеот неиспользованного к потребленному?
ПОСЛЕ ИСПРАВЛЕНИЯ
Я понял, что vaultQuery на CordaOS по умолчанию возвращает неизрасходованное состояние. Теперь понятно, почему я не смог получить состояние потребления в первую очередь. Еще одна проблема, которую я обнаружил, была нехватка ресурсов в CORDA для Java, хотя я нашел много основанных на kotlin ответов для транзакции с «созданием и потреблением» в одном рабочем процессе, однако преобразование их в JAVA потребовало некоторых усилий.
Ответ на основе Kotlin
Некоторые различия, которые я наблюдал между подходом Java и Kotlin
1) Когда я пытался использоватьтот же сеанс в моей второй транзакции, который использовался в первой транзакции, затем я получаю эту ошибку
java.util.concurrent.ExecutionException: net.corda.core.flows.UnexpectedFlowEndException: попытался получить доступ к завершенной сессии SessionId (toLong = 1984916257986245538) с пустым буфером в java.util.concurrent.CompletableFuture.reportGet (CompletableFuture.java:357) в java.util.concurrent.CompletableFuture.get (CompletableFuture.java:1895) в net.corda.core. concurrent.CordaFutureImpl.get (CordaFutureImpl.kt)
Это означает, что мы должны каждый раз создавать новую сессию для новой транзакции независимо от того, находятся ли они в одном рабочем процессе.
2) Как я понялПосмотрев на решение Kotlin, нам не нужно добавлять выходные данные в транзакцию, если мы просто хотим, чтобы она использовалась. Однако, когда я не добавляю состояние вывода во второй транзакции, я получаю следующую ошибку, которая означает, что даже для потребленного состояния я должен добавить тот же вывод внутри транзакции. В противном случае снова возникнет следующая ошибка.
ava.util.concurrent.ExecutionException: net.corda.core.flows.UnexpectedFlowEndException: встречный поток с ошибкой в java.util.concurrent.CompletableFuture.reportGet (CompletableFuture.java: 357) в java.util.concurrent.CompletableFuture.get (CompletableFuture.java:1895) в net.corda.core.internal.concurrent.CordaFutureImpl.get (CordaFutureImpl.kt) в com.etasjil.Client.testFlow (Client.java:92)
Таким образом, ясно, что в отличие от kotlin, в java нам нужно явно добавить состояние вывода и новый сеанс, если мы хотим создать и использовать состояние в одном и том же рабочем процессе.
Примечание. Поскольку для меня это новая кривая обучения, поэтому, если я допустил какую-либо ошибку в приведенной выше реализации, пожалуйста, поправьте меня. Этот ответ может быть полезен для новичков в Corda, которые хотят писать код на Java, а не на Kotlin.