json 在 golang fabric 链码行为中编码

json encode in golang fabric chaincode behavior

我看过几篇有类似错误的文章,但 none 似乎对我有用。我看过弹珠样本以及许多其他样本,但仍然无法查明错误。

我在布料中 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 转换为字节并保存吗?我知道这行得通,是否“仅”出于数据验证目的才需要这样做?

总之,非常感谢。

我发现提到了这个 where this bug

Supplying additional valid data in JSON tag of struct property causes schema to fail.

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

使用这样的结构非常有效:

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

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"`
}

...或将 key/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 检查并以我自己的格式出现 return 序列化错误;并且可能适合您的情况。

或者您可以 return 一个 string 而不是 ReadAsset 中的 *Asset 作为解决方法来避免导致错误的检查,因此它是仅在客户端反序列化。事实上,我发现 CreateAsset 中的 string 不太连贯,但 ReadAsset 中的 return 和 *Asset 不太连贯。我会为两者使用相同的格式(*Asset,最好,除非你遇到问题)。