SDK
写一个简单合约下面我们将写一个合约,合约的功能是保存和查询用户的年龄信息,合约的名字叫 age_contract
。合约有两个方法:
第一个方法 saveAge
:保存年龄信息。接收两个参数:姓名 name
和年龄 age
,把姓名和年龄保存到链上,成功返回成功信息,失败返回错误信息。
第二个方法 getAge
:查询年龄信息。接收一个参数 name
,如果链上存在用户的年龄信息则返回,如果不存在则返回 -1
。
编写合约的步骤如下:
文件目录的
workspace
上点击鼠标右键,选择创建合约工程,输入合约名字 age_contract
,然后点击创建,此时在文件目录会有一个合约工程 age_contract
。age_contract
上点击鼠标右键,选择创建文件,输入 main.go
。然后点击创建,此时在 arg_contract
目录会有一个 main.go
文件。main.go
, 复制下面代码到代码编辑区。保存代码 (CTRL+s
),保存时合约IDE会自动生成 go.mod
和 go.sum
文件。
package main import ( "chainmaker/pb/protogo" "chainmaker/shim" ) // AgeContract save and get age type AgeContract struct { } // InitContract 合约初始化方法,会在合约部署到链上时执行 func (ac *AgeContract) InitContract(stub shim.CMStubInterface) protogo.Response { return shim.Success([]byte("Init Success")) } // InvokeContract 调用合约,在链上执行合约时,实际调用的是这个方法,此时调用合约会直接返回错误信息 `no contarct method` func (ac *AgeContract) InvokeContract(stub shim.CMStubInterface) protogo.Response { return shim.Error("no contarct method") } //合约入口 func main() { //运行合约 err := shim.Start(new(AgeContract)) if err != nil { panic(err) } }
这段代码是空合约模板,没有实现任何方法,以后写合约的时候都可以先复制这段代码初始化合约文件。后面我们要做的是增加两个合约方法 saveAge
和 getAge
。saveAge
和 getAge
方法。复制下面代码到 main.go
。
package main import ( "strconv" "chainmaker/pb/protogo" "chainmaker/shim" ) // AgeContract save and get age type AgeContract struct { } // InitContract 合约初始化方法,会在合约部署到链上时执行 func (ac *AgeContract) InitContract(stub shim.CMStubInterface) protogo.Response { return shim.Success([]byte("Init Success")) } // InvokeContract 调用合约,在链上执行合约时,实际调用的是这个方法 func (ac *AgeContract) InvokeContract(stub shim.CMStubInterface) protogo.Response { return shim.Error("no contarct method") } // saveAge 保存用户年龄信息 func (ac *AgeContract) saveAge(stub shim.CMStubInterface) protogo.Response { //获取所有的合约参数 args := stub.GetArgs() name := string(args["name"]) ageStr := string(args["age"]) if name == "" || ageStr == "" { message := "name or age is empty" //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error(message) } _, err := strconv.Atoi(ageStr) if err != nil { message := "convert age to int fail. err: " + err.Error() //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error(message) } //保存用户年龄信息到链 err = stub.PutStateFromKey(name, ageStr) if err != nil { message := "put state from key fail. err: " + err.Error() //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error(message) } //返回合约执行成功信息 return shim.Success([]byte("success")) } // getAge 获取用户年龄信息 func (ac *AgeContract) getAge(stub shim.CMStubInterface) protogo.Response { //获取所有的合约参数 args := stub.GetArgs() name := string(args["name"]) if name == "" { message := "name is empty" //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error("-1") } ageStr, err := stub.GetStateFromKey(name) if err != nil { message := "get state from key fail. err: " + err.Error() //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error("-1") } if ageStr == "" { message := "age not found" //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error("-1") } //返回用户年龄 return shim.Success([]byte(ageStr)) } func main() { //运行合约 err := shim.Start(new(AgeContract)) if err != nil { panic(err) } }
这段代码较第三步增加了两个方法:
func (ac *AgeContract) saveAge(stub shim.CMStubInterface) protogo.Response {} func (ac *AgeContract) getAge(stub shim.CMStubInterface) protogo.Response {}
这两个方法分别是存储和查询用户年龄。
此时saveAge
和 getAge
方法是孤立存在的,不能通过合约调用到对应的方法,下面我们将在合约调用方法中关联合约和方法,这样调用合约方法时就能找到对应的方法。main.go
。
修改 AgeContract
.InvokeContract()
方法,增加关联合约方法代码。修改后的内容如下:
// InvokeContract 调用合约,在链上执行合约时,实际调用的是这个方法 func (ac *AgeContract) InvokeContract(stub shim.CMStubInterface) protogo.Response { //获取要调用的合约方法 method := string(stub.GetArgs()["method"]) //case "saveAge" 关联方法名 "saveAge" 到 ac.saveAge() //case "getAge" 关联方法名 "getAge" 到 ac.getAge() switch method { case "saveAge": return ac.saveAge(stub) case "getAge": return ac.getAge(stub) default: return shim.Error("no contarct method") } }
完整的合约代码如下:
package main import ( "strconv" "chainmaker/pb/protogo" "chainmaker/shim" ) // AgeContract save and get age type AgeContract struct { } // InitContract 合约初始化方法,会在合约部署到链上时执行 func (ac *AgeContract) InitContract(stub shim.CMStubInterface) protogo.Response { return shim.Success([]byte("Init Success")) } // InvokeContract 调用合约,在链上执行合约时,实际调用的是这个方法 func (ac *AgeContract) InvokeContract(stub shim.CMStubInterface) protogo.Response { //获取要调用的合约方法 method := string(stub.GetArgs()["method"]) //case "saveAge" 关联方法名 "saveAge" 到 ac.saveAge() //case "getAge" 关联方法名 "getAge" 到 ac.getAge() switch method { case "saveAge": return ac.saveAge(stub) case "getAge": return ac.getAge(stub) default: return shim.Error("no contarct method") } } // saveAge 保存用户年龄信息 func (ac *AgeContract) saveAge(stub shim.CMStubInterface) protogo.Response { //获取所有的合约参数 args := stub.GetArgs() name := string(args["name"]) ageStr := string(args["age"]) if name == "" || ageStr == "" { message := "name or age is empty" //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error(message) } _, err := strconv.Atoi(ageStr) if err != nil { message := "convert age to int fail. err: " + err.Error() //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error(message) } //保存用户年龄信息到链上 err = stub.PutStateFromKey(name, ageStr) if err != nil { message := "put state from key fail. err: " + err.Error() //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error(message) } //返回合约执行成功信息 return shim.Success([]byte("success")) } // getAge 获取用户年龄信息 func (ac *AgeContract) getAge(stub shim.CMStubInterface) protogo.Response { //获取所有的合约参数 args := stub.GetArgs() name := string(args["name"]) if name == "" { message := "name is empty" //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error("-1") } ageStr, err := stub.GetStateFromKey(name) if err != nil { message := "get state from key fail. err: " + err.Error() //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error("-1") } if ageStr == "" { message := "age not found" //打印日志,调试合约时,日志会在控制台输出中展示 stub.Log(message) //返回合约执行错误信息 return shim.Error("-1") } //返回用户年龄 return shim.Success([]byte(ageStr)) } func main() { //运行合约 err := shim.Start(new(AgeContract)) if err != nil { panic(err) } }main.go
,然后点击合约调试图标。如图所示,选中 saveAge
方法,增加 name
和 age
参数。然后点击构建合约,等构建完成之后点击执行合约,保存用户年龄信息到链上。
左侧 构建和执行合约 按钮下面会显示合约执行结果。
控制台->输出 会打印合约执行日志 stub.Log()
的内容。
控制台->世界状态 会显示合约的世界状态。{key:"Bob","value":"22"}
getAge
方法,查询存储的用户年龄信息。如下图:选中 getAge
方法,增加 name
参数,然后点击构建并执行。
左侧 构建和执行合约 按钮下面会显示合约执行结果。
控制台->输出 会打印合约执行日志 stub.Log()
的内容。
控制台->世界状态 会显示合约的世界状态。{key:"Bob","value":"22"}
Smartide-invokeGetAge
上面我们一步一步创建了一个简单的合约,用到了SDK提供的一小部分方法。
//保存用户年龄信息到链上
err = stub.PutStateFromKey(name, ageStr)
//从链上查询用户年龄信息
ageStr, err := stub.GetStateFromKey(name)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。