#java #hyperledger-fabric
#java #hyperledger-fabric
Вопрос:
У меня есть проект fabric samples. Я изменил один из примеров, чтобы поэкспериментировать. Я включил CouchDB и пытаюсь получить историю транзакций. в ядре.yaml я включил историю.
@Transaction(intent = Transaction.TYPE.EVALUATE)
public ArrayList<String> GetAssetHistory(final Context ctx, final String assetID) {
ChaincodeStub stub = ctx.getStub();
ArrayList<String> results = new ArrayList<>();
try {
QueryResultsIterator<KeyModification> history = stub.getHistoryForKey(assetID);
Iterator<KeyModification> iter = history.iterator();
while(iter.hasNext()){
results.add(iter.next().getStringValue());
}
}
catch(Exception e){
results.add(e.getMessage());
results.add(e.getCause().getMessage());
results.add(e.getStackTrace().toString());
}
return results;
}
Если я запускаю свое приложение, которое использует новый метод в контракте, я попадаю org.hyperledger.fabric.gateway.ContractException: error in simulation: transaction returned with failure: Unexpected error
в терминал intellij. Я проверил разные журналы docker. org1.example.com имеет ту же ошибку. Но у peer0.org1 …. docker есть исключение, но более информативное.
15:41:31:432 SEVERE org.hyperledger.fabric.Logger error nulljava.lang.NullPointerException
at org.hyperledger.fabric.contract.execution.JSONTransactionSerializer.toBuffer(JSONTransactionSerializer.java:84)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.convertReturn(ContractExecutionService.java:89)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.executeRequest(ContractExecutionService.java:67)
at org.hyperledger.fabric.contract.ContractRouter.processRequest(ContractRouter.java:115)
at org.hyperledger.fabric.contract.ContractRouter.invoke(ContractRouter.java:126)
at org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask.call(ChaincodeInvocationTask.java:91)
at org.hyperledger.fabric.shim.impl.InvocationTaskManager.lambda$newTask$17(InvocationTaskManager.java:225)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
15:41:31:436 SEVERE org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask call [e0aa10de] Invoke failed with error code 500. Sending ERROR
Похоже, что история по-прежнему нигде не сохраняется. Или он пытается связаться с каким-либо узлом, которого не существует.
Ответ №1:
Я столкнулся с той же проблемой и, наконец, решил ее, изменив возвращаемое значение функции, в вашем случае, из
public ArrayList<String> GetAssetHistory(final Context ctx, final String assetID)
Для
public String GetAssetHistory(final Context ctx, final String assetID)
Если вы посмотрите на этот класс org.hyperledger.fabric.contract.execution.JSONTransactionSerializer
на Github, вы можете найти функцию toBuffer
преобразования типов в json.
Вот урезанная версия:
public byte[] toBuffer(final Object value, final TypeSchema ts) {
final String type = ts.getType();
if (type != null) {
switch (type) {
case "array":
...
case "string":
...
case "number":
case "integer":
case "boolean":
default:
...
}
} else {
// at this point we can assert that the value is
// representing a complex data type
// so we can get this from
// the type registry, and get the list of propertyNames
// it should have
final DataTypeDefinition dtd = this.typeRegistry.getDataType(ts);
final Set<String> keySet = dtd.getProperties().keySet();
...
}
}
В моем коде я не использовал ArrayList
, но настраиваемый тип, поэтому он будет else
использоваться напрямую. Но в вашем коде я не знаю, ArrayList
войдет ли он в if
массив или будет интерпретироваться как настраиваемый тип. Я думаю, это может пойти на else
. Таким образом, in else
, ArrayList
не зарегистрирован как пользовательский тип via @DataType()
, это привело NullPointerException
бы к.
Итак, здесь я предлагаю вам просто использовать String
вместо этого, если работает.
Ответ №2:
Я столкнулся с той же проблемой. Вам необходимо реализовать пользовательский сериализатор для вашего цепного кода. Обратитесь к моему сообщению в блоге https://thusithathilina.medium.com/how-to-register-a-custom-serializer-for-chaincode-in-hyperledger-fabric-9e865f6d68d0
Шаги
- Реализуйте
SerializerInterface
и предоставьте реализацию дляtoBuffer
метода для преобразования вашегоArrayList
вbyte[]
- Зарегистрируйте свой сериализатор в контракте, используя
transactionSerializer
атрибут внутри@Contract
аннотации