Fabric:关于链码的编写及部署的问题记录
本篇主要记录里在链码的编写及配置过程中遇到的问题及解决方法
1. Init方法
在Hyperledger Fabric中,链码的Init()
方法是一个可选的方法,它主要用于链码实例化时执行一些初始化操作。如果我们账本的初始化方法可以在链码部署完成时执行,则可以将相关操作放到该方法中。举例如下:
func (s *SmartContract) Init(ctx contractapi.TransactionContextInterface) error {//账本初始化操作err := s.InitLedger(ctx)if err != nil {return err}return nil
}
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {assets := []Asset{{ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},{ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},{ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},{ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},{ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},{ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},}for _, asset := range assets {assetJSON, err := json.Marshal(asset)if err != nil {return err}err = ctx.GetStub().PutState(asset.ID, assetJSON)if err != nil {return fmt.Errorf("failed to put to world state. %v", err)}}return nil
}
但关于这种写法,有以下几点需要说明:
- 这种利用Init()方法进行账本初始化的操作不一定能生效,在用
Fabric-gateway-go
调用链码时能生效,但使用Peer CLI调用链码时不生效,仍然需要使用peer invoke
命令执行InitLedger
方法。原因暂时不明。 - 虽然在
fabric-contract-api-go
的官方文档中的Init
方法的返回类型为peer.Response
,比如下面的这种Init
写法:
func (s *SmartContract) Init(ctx contractapi.TransactionContextInterface) peer.Response {err := s.InitLedger(ctx)if err != nil {return peer.Response{Status:500,Message: "账本初始化失败",}}return peer.Response{Status:200,Message: "账本初始化成功",}
}
则在执行时可能会提示如下错误: Error creating business chaincode: Cannot use metadata. Metadata did not match schema:components.schemas..required: Array must have at least 1 items
2.链码返回类型
如果希望链码返回由多个JSON串组成的数组时,如果用[][]byte
,则可能产生Error: endorsement failure during query. response: status:500 message:"Error handling success response. Value did not match schema:\n1. return: Invalid type. Expected: array, given: string"
。这种情况下,最后将返回类型改成[]string
。具体案例如下:
func (s *SmartContract) GetTableAllItems(ctx contractapi.TransactionContextInterface, tableName string) ([]string, error) {query := `{"selector":{"docType":"` + tableName + `"}}`resultsIterator, err := ctx.GetStub().GetQueryResult(query)if err != nil {return nil, err}defer resultsIterator.Close()var tableItems []stringfor resultsIterator.HasNext() {queryResponse, err := resultsIterator.Next()if err != nil {return nil, err}tableItems = append(tableItems, string(queryResponse.Value))}return tableItems, nil
}