一、代码入口
代码入口包名必须为 main。
合约必要代码
package main// 合约结构体,合约名称需要写入main()方法当中type FactContract struct {}// 合约必须实现下面三个方法:// InitContract() protogo.Response// UpgradeContract() protogo.Response// InvokeContract(method string) protogo.Response// 用于合约的部署// @return: 合约返回结果,包括Success和Errorfunc (f *FactContract) InitContract() protogo.Response { return sdk.Success([]byte("Init contract success"))}// 用于合约的升级// @return: 合约返回结果,包括Success和Errorfunc (f *FactContract) UpgradeContract() protogo.Response { return sdk.Success([]byte("Upgrade contract success"))}// 用于合约的调用// @param method: 交易请求调用的方法// @return: 合约返回结果,包括Success和Errorfunc (f *FactContract) InvokeContract(method string) protogo.Response { switch method { case "save": return f.save() case "findByFileHash": return f.findByFileHash() default: return sdk.Error("invalid method") }}
二、存证合约示例
1. 存储文件哈希、文件名称、时间。
2. 通过文件哈希查询该条记录。
package mainimport ( "encoding/json" "fmt" "strconv" "chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo" "chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox" "chainmaker.org/chainmaker/contract-sdk-go/v2/sdk")// FactContract contract for facttype FactContract struct {}// Fact object to storetype Fact struct { FileHash string `json:"fileHash"` FileName string `json:"fileName"` Time int32 `json:"time"`}// NewFact create a fact objectfunc NewFact(fileHash string, fileName string, time int32) *Fact { fact := &Fact{ FileHash: fileHash, FileName: fileName, Time: time, } return fact}// InitContract install contract funcfunc (f *FactContract) InitContract() protogo.Response { return sdk.Success([]byte("Init contract success"))}// UpgradeContract upgrade contract funcfunc (f *FactContract) UpgradeContract() protogo.Response { return sdk.Success([]byte("Upgrade contract success"))}// InvokeContract the entry func of invoke contract funcfunc (f *FactContract) InvokeContract(method string) protogo.Response { switch method { case "save": return f.save() case "findByFileHash": return f.findByFileHash() default: return sdk.Error("invalid method") }}func (f *FactContract) save() protogo.Response { params := sdk.Instance.GetArgs() // 获取参数 fileHash := string(params["file_hash"]) fileName := string(params["file_name"]) timeStr := string(params["time"]) time, err := strconv.ParseInt(timeStr, 10, 0) if err != nil { msg := "time is [" + timeStr + "] not int" sdk.Instance.Errorf(msg) return sdk.Error(msg) } // 构建结构体 fact := NewFact(fileHash, fileName, int32(time)) // 序列化 factBytes, err := json.Marshal(fact) if err != nil { return sdk.Error(fmt.Sprintf("marshal fact failed, err: %s", err)) } // 发送事件 sdk.Instance.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName}) // 存储数据 err = sdk.Instance.PutStateByte("fact_bytes", fact.FileHash, factBytes) if err != nil { return sdk.Error("fail to save fact bytes") } // 记录日志 sdk.Instance.Infof("[save] fileHash=" + fact.FileHash) sdk.Instance.Infof("[save] fileName=" + fact.FileName) // 返回结果 return sdk.Success([]byte(fact.FileName + fact.FileHash))}func (f *FactContract) findByFileHash() protogo.Response { // 获取参数 fileHash := string(sdk.Instance.GetArgs()["file_hash"]) // 查询结果 result, err := sdk.Instance.GetStateByte("fact_bytes", fileHash) if err != nil { return sdk.Error("failed to call get_state") } // 反序列化 var fact Fact if err = json.Unmarshal(result, &fact); err != nil { return sdk.Error(fmt.Sprintf("unmarshal fact failed, err: %s", err)) } // 记录日志 sdk.Instance.Infof("[findByFileHash] fileHash=" + fact.FileHash) sdk.Instance.Infof("[findByFileHash] fileName=" + fact.FileName) // 返回结果 return sdk.Success(result)}func main() { err := sandbox.Start(new(FactContract)) if err != nil { sdk.Instance.Errorf(err.Error()) }}
三、存证合约代码说明
| 参数名称 | 描述 |
| InitContract | 合约的初始化函数,在合约部署时被调用,在本合约中为空。 |
| UpgradeContract | 合约的升级函数,在合约升级时被调用,在本合约中为空。 |
| InvokeContract | 合约调用的函数。 |
| save | save 函数实现将文件相关信息记录到链上的功能。步骤如下:1. save 函数先通过参数处理 API 接口 GetArgs 函数拿到时间,文件哈希和文件名字等信息。2. 构造 Fact 结构,序列化为 byte 数据;且当序列化错误时调用其他辅助类 API 接口 Log 函数记录相应日志。3. 通过调用账本交互 API 接口 PutStateByte 函数将数据记录到链上。4. 最后通过调用其他辅助类 API 接口 Success 函数将操作结果记录到链上。 |
| findByFileHash | 通过文件哈希查询该条记录。步骤如下:1. findByFileHash 通过参数处理 API 接口 GetArgs 函数拿到要查找的文件的文件哈希。2. 通过账本交互 API 接口 GetStateByte 函数获取文件的信息;若失败则通过其他辅助类 API 接口 Error 函数将操作结果记录到链上,否则,通过其他辅助类 API 接口 Log 函数和 Success 函数记录相关日志和返回结果。 |