长安链通过SmartIDE编写Go智能合约

首先通过长安链IDE进入网页进行登录

       

输入账号密码进行登录

然后开始合约编写,合约的功能是保存和查询用户的年龄信息,合约的名字叫 age_contract。合约有两个方法:

第一个方法 saveAge:保存年龄信息。接收两个参数:姓名 name 和年龄 age,把姓名和年龄保存到链上,成功返回成功信息,失败返回错误信息。

第二个方法 getAge:查询年龄信息。接收一个参数 name ,如果链上存在用户的年龄信息则返回,如果不存在则返回-1。

版本右上角应该优先选择v2.3.0+

       首先选择创建合约工程,输入合约名字 age_contract,然后点击创建,此时在文件目录会有一个合约工程age_contract。这里会自动生成main.go、go.mod、go.sum文件。

       然后开始编写合约

package main



import (

    "chainmaker/pb/protogo"

    "chainmaker/sdk"

    "chainmaker/sandbox"

)



// AgeContract save and get age

type AgeContract struct {

}



// InitContract 合约初始化方法,会在合约部署到链上时执行

func (ac *AgeContract) InitContract() protogo.Response {

    return sdk.Success([]byte("Init contract success"))

}



// InvokeContract 调用合约,在链上执行合约时,实际调用的是这个方法,此时调用合约会直接返回错误信息 `no contarct method`

func (ac *AgeContract) InvokeContract(method string) protogo.Response {

    return sdk.Error("invalid method")

}



// UpgradeContract 合约升级方法, 会在合约升级时候调用

func (ac *AgeContract) UpgradeContract() protogo.Response {

    return sdk.Success([]byte("Upgrade contract success"))

}



//合约入口

func main() {

    //运行合约

    err := sandbox.Start(new(AgeContract))

    if err != nil {

        log.Fatal(err)

    }

}

       这个是合约初始化的基本模版,像以后的都可以按照这个来实现。

       然后需要添加saveAge 和 getAge方法:

// saveAge 保存用户年龄信息
func (ac *AgeContract) saveAge() protogo.Response {
    //获取所有的合约参数
    args := sdk.Instance.GetArgs()

    name := string(args["name"])
    ageStr := string(args["age"])
    if name == "" || ageStr == "" {
        message := "name or age is empty"
        //打印日志,调试合约时,日志会在控制台输出中展示
        sdk.Instance.Infof(message)
        //返回合约执行错误信息
        return sdk.Error(message)
    }

    _, err := strconv.Atoi(ageStr)
    if err != nil {
        message := "convert age to int fail. err: " + err.Error()
        //打印日志,调试合约时,日志会在控制台输出中展示
    sdk.Instance.Infof(message)
        //返回合约执行错误信息
        return sdk.Error(message)
    }

    //保存用户年龄信息到链
    err = sdk.Instance.PutStateFromKey(name, ageStr)
    if err != nil {
        message := "put state from key fail. err: " + err.Error()
        //打印日志,调试合约时,日志会在控制台输出中展示
        sdk.Instance.Infof(message)
        //返回合约执行错误信息
        return sdk.Error(message)
    }

    //返回合约执行成功信息
    return sdk.Success([]byte("success"))
}

// getAge 获取用户年龄信息
func (ac *AgeContract) getAge() protogo.Response {
    //获取所有的合约参数
    args := sdk.Instance.GetArgs()

    name := string(args["name"])
    if name == "" {
        message := "name is empty"
        //打印日志,调试合约时,日志会在控制台输出中展示
        sdk.Instance.Infof(message)
        //返回合约执行错误信息
        return sdk.Error("-1")
    }

    ageStr, err := sdk.Instance.GetStateFromKey(name)
    if err != nil {
        message := "get state from key fail. err: " + err.Error()
        //打印日志,调试合约时,日志会在控制台输出中展示
        sdk.Instance.Infof(message)
        //返回合约执行错误信息
        return sdk.Error("-1")
    }

    if ageStr == "" {
        message := "age not found"
        //打印日志,调试合约时,日志会在控制台输出中展示
        sdk.Instance.Infof(message)
        //返回合约执行错误信息
        return sdk.Error("-1")
    }

    //返回用户年龄
    return sdk.Success([]byte(ageStr))
}

       然后修改关联合约方法,再此之前合约都是相互独立的存在,我们现在要做的就是将合约联系起来:

// InvokeContract 调用合约,在链上执行合约时,实际调用的是这个方法
func (ac *AgeContract) InvokeContract(method string) protogo.Response {

    switch method {
    case "saveAge":
    return ac.saveAge()
    case "getAge":
    return ac.getAge()
    default:
        return sdk.Error("no contract method")
    }
}

       整体代码如下:

package main



import (

       "chainmaker/pb/protogo"

       "chainmaker/sandbox"

       "chainmaker/sdk"

       "log"

       "strconv"

     "fmt"

)



// AgeContract save and get age

type AgeContract struct {

}



// InitContract 合约初始化方法,会在合约部署到链上时执行

func (ac *AgeContract) InitContract() protogo.Response {

       return sdk.Success([]byte("Init contract success"))

}



// InvokeContract 调用合约,在链上执行合约时,实际调用的是这个方法

func (ac *AgeContract) InvokeContract(method string) protogo.Response {



       switch method {

       case "saveAge":

              return ac.saveAge()

       case "getAge":

              return ac.getAge()



       case "crossCall":

              return ac.crossCall()

       case "historyKvIterator":

              return ac.historyKvIterator()

       default:

              return sdk.Error("no contract method")

       }



}



// UpgradeContract 合约升级方法, 会在合约升级时候调用

func (ac *AgeContract) UpgradeContract() protogo.Response {

       return sdk.Success([]byte("Upgrade contract success"))

}



// saveAge 保存用户年龄信息

func (ac *AgeContract) saveAge() protogo.Response {

       //获取所有的合约参数

       args := sdk.Instance.GetArgs()



       name := string(args["name"])

       ageStr := string(args["age"])

       if name == "" || ageStr == "" {

              message := "name or age is empty"

              //打印日志,调试合约时,日志会在控制台输出中展示

              sdk.Instance.Infof(message)

              //返回合约执行错误信息

              return sdk.Error(message)

       }



       _, err := strconv.Atoi(ageStr)

       if err != nil {

              message := "convert age to int fail. err: " + err.Error()

              //打印日志,调试合约时,日志会在控制台输出中展示

              sdk.Instance.Infof(message)

              //返回合约执行错误信息

              return sdk.Error(message)

       }



       //保存用户年龄信息到链

       err = sdk.Instance.PutStateFromKey(name, ageStr)

       if err != nil {

              message := "put state from key fail. err: " + err.Error()

              //打印日志,调试合约时,日志会在控制台输出中展示

              sdk.Instance.Infof(message)

              //返回合约执行错误信息

              return sdk.Error(message)

       }



       //返回合约执行成功信息

       return sdk.Success([]byte("success"))

}



// getAge 获取用户年龄信息

func (ac *AgeContract) getAge() protogo.Response {

       //获取所有的合约参数

       args := sdk.Instance.GetArgs()



       name := string(args["name"])

       if name == "" {

              message := "name is empty"

              //打印日志,调试合约时,日志会在控制台输出中展示

              sdk.Instance.Infof(message)

              //返回合约执行错误信息

              return sdk.Error("-1")

       }



       ageStr, err := sdk.Instance.GetStateFromKey(name)

       if err != nil {

              message := "get state from key fail. err: " + err.Error()

              //打印日志,调试合约时,日志会在控制台输出中展示

              sdk.Instance.Infof(message)

              //返回合约执行错误信息

              return sdk.Error("-1")

       }



       if ageStr == "" {

              message := "age not found"

              //打印日志,调试合约时,日志会在控制台输出中展示

              sdk.Instance.Infof(message)

              //返回合约执行错误信息

              return sdk.Error("-1")

       }



       //返回用户年龄

       return sdk.Success([]byte(ageStr))

}



//crossCall 跨合约调用

func (ac *AgeContract) crossCall() protogo.Response {



    //要调用的合约的基本信息

    contractName := "age_contract"

    calledMethod := "getAge"



    //跨合约调用的参数

    crossContractArgs := make(map[string][]byte)

    crossContractArgs["method"] = []byte(calledMethod)

    crossContractArgs["name"] = []byte("Bob")



    //开合约调用响应信息

    response := sdk.Instance.CallContract(contractName, calledMethod, crossContractArgs)

    sdk.Instance.EmitEvent("cross contract", []string{"success"})

    return response

}



//historyKvIterator 历史迭代器

func (ac *AgeContract) historyKvIterator() protogo.Response {

    key := "Bob"

    //创建历史迭代器

    result, err := sdk.Instance.NewHistoryKvIterForKey(key, "")

    if err != nil {

        msg := "failed to call get_state"

        sdk.Instance.Log(msg + " " + err.Error())

        return sdk.Error(msg)

    }



    //判断迭代器是否有数据,如果有迭代输出数据

    for result.HasNext() {

        v, err := result.Next()

        if err != nil {

            msg := "failed to call iterator"

            sdk.Instance.Log(msg + " " + err.Error())

            return sdk.Error(msg)

        }

        sdk.Instance.Log(fmt.Sprintf("NewHistoryKvIterForKey %v\n", v))

    }



    return sdk.Success([]byte("success"))

}



func main() {

       //运行合约

       err := sandbox.Start(new(AgeContract))

       if err != nil {

              log.Fatal(err)

       }

}

       保存之后找到左边的第二个按钮调试:

在这里选择我们的age_contract合约,然后合约方法为saveAge,key和value自己输入,然后构建合约再执行合约

执行完合约会显示这些成功界面

调用getAge则会返回刚刚的age信息

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值