在Golang的Fabric链码中,JSON编码的行为是怎样的?

huangapple go评论137阅读模式
英文:

json encode in golang fabric chaincode behavior

问题

我看过几篇类似错误的文章,但是没有一个对我有效。我看过了大理石示例以及其他很多示例,但仍然无法确定错误的原因。

我使用的是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) {
	
	// 将JSON输入转换为字节数组
	txData := []byte(values)

	// 将字节数组转换为HlpAsset结构体
	asset := new(asset)
	err = json.Unmarshal(txData, &asset)

	// 将结构体转换回字节数组
	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)

	// 将字节数组转换为HlpAsset结构体
	asset := new(Asset)
	err = json.Unmarshal(txBytes, &asset)

	return asset, nil
}

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

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

此外,我不太确定为什么需要进行Unmarshal/Marshal操作。我是否可以直接将字符串化的JSON转换为字节数组并保存?我知道这样可以工作,这只是为了数据验证目的而需要吗?

无论如何,非常感谢。

英文:

I've seen several articles with similar errors, but none seems to work for me. I've seen the marbles samples, as well as many others, and still can't pinpoint the error.

I'm in fabric 2.x. The chaincode below works just fine when saving data, but fails when reading with the following message:

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
}

testing with the following input data:

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

In addition, I'm not exactly sure why I need to Unmarshal/Marshal. Couldn't I just convert the stringified JSON to byte and save that? I know that works, is it "only" for data validation purposes that this is required?

Anyway, thanks a bunch.

答案1

得分: 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),除非你被困在你的问题中。

英文:

In omitempty fields, set also metadata:",optional" to pass validation. And you cannot set json:"omitempty" metadata:",optional" on all fields of your model. The default Fabric 2.X Go chaincode's transaction serializer does not like it for any reason. If you really need omitempty for those fields, you can add any other dumb field.

You can add a dumb boolean...

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

...or add the key/ID itself to the model...

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

...or a document type...

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

As an alternative, you can try to override default ContractChaincode's TransactionSerializer (https://pkg.go.dev/github.com/hyperledger/fabric-contract-api-go/contractapi#ContractChaincode). I've done it when migrating a chaincode that already had its own input validation from 1.X to 2.X, to avoid metadata checks and to return seralization errors in my own format; and may work for your case.

Or you can return a string instead of an *Asset from ReadAsset as a workaround to avoid the check that is causing your error, so that it is deserialized only in the client. In fact, I find not much coherent to receive an string in CreateAsset, but return an *Asset in ReadAsset. I would use the same format for both (*Asset, preferably, unless you are stuck with your issue).

答案2

得分: 0

我在这个问题中找到了提到这个错误的地方:
> 在结构属性的JSON标签中提供额外的有效数据会导致模式失败。

这个错误已经关闭了大约一年,然而,我仍然遇到这种行为。使用metadata覆盖JSON属性也没有起作用。

像这样使用结构体是完美的:

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

英文:

I found this question where this bug is mentioned:
> Supplying additional valid data in JSON tag of struct property causes schema to fail.

The bug has been closed for around a year, however, I still experience that behavior. Overriding the JSON property using medatada didn't work either.

Using the struct like this worked perfectly:

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

huangapple
  • 本文由 发表于 2021年10月20日 05:11:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/69637688.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定