【问题标题】:json encode in golang fabric chaincode behaviorgolang结构链码行为中的json编码
【发布时间】:2021-10-19 21:11:05
【问题描述】:

我看过几篇有类似错误的文章,但似乎没有一篇适合我。我已经查看了弹珠样本以及许多其他样本,但仍然无法确定错误。

我使用的是 Fabric 2.x。下面的链码在保存数据时工作正常,但在读取时失败并显示以下消息:

ERROR] Error submitting transaction: No valid responses from any peers. Errors:
    peer=org1peer-api.127-0-0-1.nip.io:8080, status=500, message=Error handling success response. Value did not match schema:
1. return: Additional property field1 is not allowed
2. return: Additional property field2 is not allowed
3. return: field1,omitempty is required
4. return: field2,omitempty is required
type Asset struct {
    Field1 string `json:"field1,omitempty"`
    Field2 string `json:"field2,omitempty"`
}

func (c *AssetContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetID string, values string) (bool, error) {
    
    // convert json input to byte array
    txData := []byte(values)

    // convert byte array to HlpAsset struct
    asset := new(asset)
    err = json.Unmarshal(txData, &asset)

    // convert struct back to bytes
    txBytes, err := json.Marshal(asset)

    return true, ctx.GetStub().PutState(assetID, txBytes)
}

func (c *AssetContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetID string) (*Asset, error) {

    txBytes, _ := ctx.GetStub().GetState(assetID)

    // convert byte array to HlpAsset struct
    asset := new(Asset)
    err = json.Unmarshal(txBytes, &asset)

    return asset, nil
}

使用以下输入数据进行测试:

assetID: "3",
values: "{\"field1\":\"123\",\"field2\":\"a05\"}"

此外,我不确定为什么需要 Unmarshal/Marshal。我不能将字符串化的 JSON 转换为字节并保存吗?我知道这可行,是否“仅”用于数据验证目的?

无论如何,非常感谢。

【问题讨论】:

    标签: go hyperledger-fabric hyperledger-chaincode chaincode


    【解决方案1】:

    omitempty 字段中,还要设置metadata:",optional" 以通过验证。而且您不能在模型的所有字段上设置json:"omitempty" metadata:",optional"。默认的 Fabric 2.X Go 链码的事务序列化器出于任何原因都不喜欢它。如果这些字段确实需要omitempty,您可以添加任何其他哑字段。

    您可以添加一个愚蠢的布尔值...

    type Asset struct {
        Dumb bool `json:"dumb"`
        Field1 string `json:"field1,omitempty" metadata:",optional"`
        Field2 string `json:"field2,omitempty" metadata:",optional"`
    }
    

    ...或将密钥/ID 本身添加到模型中...

    type Asset struct {
        ID string `json:"id"`
        Field1 string `json:"field1,omitempty" metadata:",optional"`
        Field2 string `json:"field2,omitempty" metadata:",optional"`
    }
    

    ...或文档类型...

    type Asset struct {
        DocType string `json:"docType"`
        Field1 string `json:"field1,omitempty" metadata:",optional"`
        Field2 string `json:"field2,omitempty" metadata:",optional"`
    }
    

    作为替代方案,您可以尝试覆盖默认 ContractChaincode 的 TransactionSerializer (https://pkg.go.dev/github.com/hyperledger/fabric-contract-api-go/contractapi#ContractChaincode)。我在将已经有自己的输入验证的链码从 1.X 迁移到 2.X 时已经完成了它,以避免metadata 检查并以我自己的格式返回序列化错误;并且可能适用于您的情况。

    或者您可以从ReadAsset 返回一个string 而不是*Asset 作为一种解决方法,以避免导致您的错误的检查,以便它仅在客户端中反序列化。事实上,我发现在CreateAsset 中接收string 并没有多大连贯性,但在ReadAsset 中返回*Asset。我会为两者使用相同的格式(最好是*Asset,除非您遇到问题)。

    【讨论】:

    • 是“您不能在模型的所有字段上设置 json:"omitempty"。”具体到golang中json包的处理方式,还是和fabric有关?
    • 在反序列化/验证输入和序列化/验证输出时与 Fabric 2.X Go 链码的 TransactionSerializer 相关。 metadata:",optional"也有一些类似的行为。
    • 事实上,我忘了提到metadata:",optional" 也需要omitempty 字段才能通过验证(答案已编辑)。但是,无论如何,默认 Fabric 2.X 链码的序列化程序并不喜欢所有字段都是 omitempty
    【解决方案2】:

    我发现这个question 提到了这个bug

    在结构属性的 JSON 标记中提供额外的有效数据会导致架构失败。

    该错误已关闭大约一年,但是我仍然遇到这种行为。使用 medatada 覆盖 JSON 属性也不起作用。

    使用这样的结构效果很好:

    type Asset struct {
        Field1 string `json:"field1"`
        Field2 string `json:"field2"`
    }
    
    

    【讨论】:

    猜你喜欢
    • 2014-01-18
    • 2017-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-29
    • 1970-01-01
    相关资源
    最近更新 更多