Return 交易类型?

Return type of transaction?

我是来自 fabric-samples 的 运行 chaincode-java

    @Transaction(intent = Transaction.TYPE.EVALUATE)
    public ArrayList<Asset> GetAllAssets(final Context ctx) {
        ChaincodeStub stub = ctx.getStub();

        ArrayList<Asset> queryResults = new ArrayList<Asset>();

        // To retrieve all assets from the ledger use getStateByRange with empty startKey & endKey.
        // Giving empty startKey & endKey is interpreted as all the keys from beginning to end.
        // As another example, if you use startKey = 'asset0', endKey = 'asset9' ,
        // then getStateByRange will retrieve asset with keys between asset0 (inclusive) and asset9 (exclusive) in lexical order.
        QueryResultsIterator<KeyValue> results = stub.getStateByRange("", "");

        for (KeyValue result: results) {
            Asset asset = genson.deserialize(result.getStringValue(), Asset.class);
            System.out.println(asset);
            queryResults.add(asset);
        }

//        final String response = genson.serialize(queryResults);

        return queryResults;
    }

GetAllAssets() 方法是 returning String,但我将其更改为 ArrayList。

因此,调用 GetAllAssets 时会抛出错误。

$ peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
Error: endorsement failure during query. response: status:500 message:"Unexpected error"

日志说

Thread[fabric-txinvoke:2,5,main] 11:15:01:224 INFO    org.hyperledger.fabric.contract.ContractRouter processRequest                    Got invoke routing request
Thread[fabric-txinvoke:2,5,main] 11:15:01:226 INFO    org.hyperledger.fabric.contract.ContractRouter processRequest                    Got the invoke request for:GetAllAssets []
Thread[fabric-txinvoke:2,5,main] 11:15:01:234 INFO    org.hyperledger.fabric.contract.ContractRouter processRequest                    Got routing:GetAllAssets:org.hyperledger.fabric.samples.assettransfer.AssetTransfer
Thread[fabric-txinvoke:2,5,main] 11:15:01:274 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:123)
        at org.hyperledger.fabric.contract.ContractRouter.invoke(ContractRouter.java:134)
        at org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask.call(ChaincodeInvocationTask.java:106)
        at org.hyperledger.fabric.shim.impl.InvocationTaskManager.lambda$newTask(InvocationTaskManager.java:265)
        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)

Thread[fabric-txinvoke:2,5,main] 11:15:01:276 SEVERE  org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask call                    [13733a23] Invoke failed with error code 500. Sending ERROR

我可以从交易中 return List 吗?除了String,我还能return什么类型?有没有我可以看一下的文档?

先介绍一些背景知识; Java 中可用的 ContractAPI,Go 和 Typescript 用于生成 'model'整个合同的一部分,包括从交易功能传递和 returned 的数据类型。 (Java脚本根据其输入尽可能支持有限的子集)。

为了支持这一点,必须有某种 'serializer' 来处理数据。 'invoke(byte[]): byte[]' 的底层链代码 API 赋予开发人员序列化他们希望的方式的能力,尽管并非所有人都需要使用这种能力。

合约中有默认值'serializer'API;如果需要,可以换掉它。

具体回答问题;

return 类型可以是:

  • 字符串,
  • 数字(对于 Java 这是任何原始 'number' 类型)
  • 布尔值,
  • 已标注的其他类型
  • 上面的数组

对于 'other types',有注释可用于定义类型,这些类型也可以传入和传出事务函数。

您可能会看到这样的内容:

@DataType()
public final class Complex {

    @Property()
    private final String id;

    @Property()
    private final Description description;

    @Property()
    private final int value;

    public String getID() {
        return id;
    }

    public int getValue() {
        return value;
    }

    public Description getDescription(){
        return description;
    }
}

描述还有一个class以类似的方式注释。

这将生成如下所示的合同元数据

            "Description": {
                "$id": "Description",
                "type": "object",
                "properties": {
                    "colour": {
                        "type": "string"
                    },
                    "owners": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "Complex": {
                "$id": "Complex",
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "value": {
                        "type": "number"
                    },
                    "description": {
                        "$ref": "Description"
                    }
                }
            }

关于合约模型,或合约元数据


处有一个 JSON 架构 https://github.com/hyperledger/fabric-chaincode-node/blob/main/apis/fabric-contract-api/schema/contract-schema.json

这不是限制吗?列表呢? 这是一个公平的评论,从 Java 的角度来看,像 ArrayList 或 Map 这样的东西对 return 来说是合理的。然而,挑战在于合同可能以不同的语言实施。此外,一旦部署,合约将 运行 一段时间,因此元数据在智能合约和客户端应用程序之间提供了强大的 'API Definition'。

哪些交易功能(也在元数据中)将被明确定义。

总结 我想提供更多示例(和文档!),但想先把它写下来。我们可以进行一些扩展和更改,并且愿意进行但时间有限!

作为这些存储库的维护者,如果这是一个感兴趣的领域,我们很乐意让人们加入进来。