前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >智能合约DAPP系统,智能合约DAPP系统开发功能,智能合约DAPP流动性质押挖矿分红系统开发应用案例及源码

智能合约DAPP系统,智能合约DAPP系统开发功能,智能合约DAPP流动性质押挖矿分红系统开发应用案例及源码

原创
作者头像
VX_I357O98O7I8
发布2022-12-15 17:12:47
2350
发布2022-12-15 17:12:47
举报
文章被收录于专栏:商业模式策划商业模式策划

3.4.1. shim.CMStubInterface 接口

shim.CMStubInterface 定义了和链交互的方法,我们通过在合约中调用该接口的方法和链交互。方法列表如下:

代码语言:javascript
复制
# 获取合约执行的参数
GetArgs() map[string][]byte

# 从链上查询信息
# 查询信息 指定 key field
GetState(key, field string) (string, error)
GetStateByte(key, field string) ([]byte, error)
# 查询信息 指定 key
GetStateFromKey(key string) (string, error)
GetStateFromKeyByte(key string) ([]byte, error)

# 存储数据到链上
# 存储信息 指定key field
PutState(key, field string, value string) error
PutStateByte(key, field string, value []byte) error
# 存储信息 指定 key
PutStateFromKey(key string, value string) error
PutStateFromKeyByte(key string, value []byte) error

# 从链上删除数据
# 删除信息 指定key field
DelState(key, field string) error
# 删除信息 指定key
DelStateFromKey(key string) error

# 获取合约创建者的组织ID
GetCreatorOrgId() (string, error)
# 获取合约创建者的角色
GetCreatorRole() (string, error)
# 获取合约创建者的公钥
GetCreatorPk() (string, error)
# 获取交易发起者的组织ID
GetSenderOrgId() (string, error)
# 获取交易交易发起者的角色
GetSenderRole() (string, error)
# 获取交易发起者的公钥
GetSenderPk() (string, error)
# 获取当前块高度
GetBlockHeight() (int, error)
# 获取交易ID
GetTxId() (string, error)
# 获取交易时间戳
GetTxTimeStamp() (string, error)

# 发布合约事件
EmitEvent(topic string, data []string)

# 记录合约日志
Log(message string)

# 跨合约调用
CallContract(contractName, contractVersion string, args map[string][]byte) protogo.Response

# 范围查询迭代器 [startKey, limitKey)
NewIterator(startKey string, limitKey string) (ResultSetKV, error)
# 范围查询迭代器 [key+startField, key+limitField)
NewIteratorWithField(key string, startField string, limitField string) (ResultSetKV, error)
# 前缀范围查询迭代器 有 `key+field` 前缀的数据
NewIteratorPrefixWithKeyField(key string, field string) (ResultSetKV, error)
# 前缀范围查询迭代器 有 `key` 前缀的数据
NewIteratorPrefixWithKey(key string) (ResultSetKV, error)
          
# 历史数据查询迭代器 key+field 数据的历史版本
NewHistoryKvIterForKey(key, field string) (KeyHistoryKvIter, error)

# 查询交易发起方地址
GetSenderAddr() (string, error)
          
// 结果集
type ResultSet interface {
	// NextRow get next row,
	// sql: column name is EasyCodec key, value is EasyCodec string val. as: val := ec.getString("columnName")
	// kv iterator: key/value is EasyCodec key for "key"/"value", value type is []byte. as: k, _ := ec.GetString("key") v, _ := ec.GetBytes("value")
	NextRow() (*serialize.EasyCodec, error)
	// HasNext return does the next line exist
	HasNext() bool
	// Close .
	Close() (bool, error)
}

type ResultSetKV interface {
	ResultSet
	// Next return key,field,value,code
	Next() (string, string, []byte, error)
}

type KeyHistoryKvIter interface {
	ResultSet
	// Next return txId, blockHeight, timestamp, value, isDelete, error
	Next() (*KeyModification, error)
}

写合约的时候我们通过编写代码完成合约逻辑,SDK提供了合约和链交互的方法,帮助我们完成和链交互。

3.4.2. shim.CMStubInterface 详细介绍

  1. 跨合约调用,即在A合约中调用B合约的方法。跨合约调用需要用到 CallContract 方法。代码如下: //crossCall 跨合约调用 func (ac *AgeContract) crossCall(stub shim.CMStubInterface) protogo.Response { //要调用的合约的基本信息 contractName := "age_contract" contractVersion := "1.0.0" calledMethod := "getAge" //跨合约调用的参数 crossContractArgs := make(map[string][]byte) crossContractArgs["method"] = []byte(calledMethod) crossContractArgs["name"] = []byte("Bob") //开合约调用响应信息 response := stub.CallContract(contractName, contractVersion, crossContractArgs) stub.EmitEvent("cross contract", []string{"success"}) return response }
  2. 迭代器使用,查询用户年龄的历史版本。 //historyKvIterator 历史迭代器 func (ac *AgeContract) historyKvIterator(stub shim.CMStubInterface) protogo.Response { key := "Bob" //创建历史迭代器 result, err := stub.NewHistoryKvIterForKey(key, "") if err != nil { msg := "failed to call get_state" stub.Log(msg + " " + err.Error()) return shim.Error(msg) } //判断迭代器是否有数据,如果有迭代输出数据 for result.HasNext() { v, err := result.Next() if err != nil { msg := "failed to call iterator" stub.Log(msg + " " + err.Error()) return shim.Error(msg) } stub.Log(fmt.Sprintf("NewHistoryKvIterForKey %v\n", v)) } return shim.Success([]byte("success")) }
  3. 完整合约。包含 保存用户年龄信息saveAge、 查询用户年龄信息getAge 开合约调用crossCall 和 历史迭代器historyKvIterator。 package main import ( "fmt" "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 "***" 关联方法名 "***" 到 ac.*** switch method { case "saveAge": return ac.saveAge(stub) case "getAge": return ac.getAge(stub) case "crossCall": return ac.crossCall(stub) case "historyKvIterator": return ac.historyKvIterator(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)) } //crossCall 跨合约调用 func (ac *AgeContract) crossCall(stub shim.CMStubInterface) protogo.Response { //要调用的合约的基本信息 contractName := "age_contract" contractVersion := "1.0.0" calledMethod := "getAge" //跨合约调用的参数 crossContractArgs := make(map[string][]byte) crossContractArgs["method"] = []byte(calledMethod) crossContractArgs["name"] = []byte("Bob") //开合约调用响应信息 response := stub.CallContract(contractName, contractVersion, crossContractArgs) stub.EmitEvent("cross contract", []string{"success"}) return response } //historyKvIterator 历史迭代器 func (ac *AgeContract) historyKvIterator(stub shim.CMStubInterface) protogo.Response { key := "Bob" //创建历史迭代器 result, err := stub.NewHistoryKvIterForKey(key, "") if err != nil { msg := "failed to call get_state" stub.Log(msg + " " + err.Error()) return shim.Error(msg) } //判断迭代器是否有数据,如果有迭代输出数据 for result.HasNext() { v, err := result.Next() if err != nil { msg := "failed to call iterator" stub.Log(msg + " " + err.Error()) return shim.Error(msg) } stub.Log(fmt.Sprintf("NewHistoryKvIterForKey %v\n", v)) } return shim.Success([]byte("success")) } func main() { //运行合约 err := shim.Start(new(AgeContract)) if err != nil { panic(err) } }

3.5. 编写合约注意事项

  1. 合约工程目录下必须有一个 main.go,且 main.go 的包名需要是 main,合约的入口需要在 main.go 中,且 InvokeContract() 方法代码需要在 main.go 中。即 : package main import ( "chainmaker/pb/protogo" "chainmaker/shim" ) ... ... ... ... // 调用合约方法 func (f *AgeContract) InvokeContract(stub shim.CMStubInterface) protogo.Response { //获取要调用的合约方法 method := string(stub.GetArgs()["method"]) //case "saveAge" 关联方法名 "saveAge" 到 f.saveAge() //case "getAge" 关联方法名 "getAge" 到 f.getAge() switch method { case "saveAge": return f.saveAge(stub) case "getAge": return f.getAge(stub) default: return shim.Error("no contarct method") } } // 合约入口 func main() { //运行合约 err := shim.Start(new(AgeContract)) if err != nil { panic(err) } }
  2. InvokeContract 里面关联方法逻辑需要是如下模式(合约调试会根据下面的模式解析方法名)。注意不要在 case 后面使用定义的常量。 switch method { case "字符串": ... ... case "字符串": ... ... default: return shim.Error("no contarct method") }
  3. 不能使用全局变量。在编写合约时,不要使用全局变量来存储数据,数据的存储可以直接存到链上,用 getStateputState 等方法存储。
  4. 不支持在合约工程内创建内嵌的 go module。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3.4.1. shim.CMStubInterface 接口
  • 3.4.2. shim.CMStubInterface 详细介绍
  • 3.5. 编写合约注意事项
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档