为了账号安全,请及时绑定邮箱和手机立即绑定

实战-超级账本 fabric 编写部署调用第一条链码

标签:
区块链
一、部署本地开发环境

文/谦益

1、在GOPATH目录下git源码

GOPATH 目录下,下载源码:

git clone http://gerrit.hyperledger.org/r/fabric
git clone http://gerrit.hyperledger.org/r/fabric-ca

我们写链码需要用到里面的包。

2、新建一个go文件

  • 随便建一个目录,反正不在本地调试,建议是在GOPATH目录下面新建
  • 再新建一个go文件,写入代码:

package main

import (
    "fmt"
    "strconv"
    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

type LGSimpleChaincode struct {
}

func (t *LGSimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
    fmt.Println("LGSimpleChaincode -> Init")
    _, args := stub.GetFunctionAndParameters()
    var A, B string
    var Aval, Bval int
    var err error

    if len(args) != 4 {
        return shim.Error("参数数量不对")
    }

    A = args[0]
    Aval, err = strconv.Atoi(args[1])
    if err != nil {
        return shim.Error("参数值类型不对")
    }

    B = args[2]
    Bval, err = strconv.Atoi(args[3])
    if err != nil {
        return shim.Error("参数值类型不对")
    }

    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    return shim.Success(nil)
}

func (t *LGSimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    fmt.Println("LGSimpleChaincode -> Invoke")

    function, args := stub.GetFunctionAndParameters()
    if function == "invoke" {

        return t.invoke(stub, args)
    } else if function == "delete" {

        return t.delete(stub, args)
    } else if function == "query" {

        return t.query(stub, args)
    }

    return shim.Error("方法名不对,只支持 invoke,delete,query")
}

//交易转账
func (t *LGSimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    var A, B string
    var Aval, Bval int
    var X int
    var err error

    if len(args) != 3 {
        return shim.Error("参数数量不对")
    }

    A = args[0]
    B = args[1]

    Avalbytes, err := stub.GetState(A)
    if err != nil {
        return shim.Error("没找到第一个的用户金额")
    }
    if Avalbytes == nil {
        return shim.Error("第一个用户金额为nil")
    }
    Aval, _ = strconv.Atoi(string(Avalbytes))

    Bvalbytes, err := stub.GetState(B)
    if err != nil {
        return shim.Error("没找到第二个的用户金额")
    }
    if Bvalbytes == nil {
        return shim.Error("第二个用户金额为nil")
    }
    Bval, _ = strconv.Atoi(string(Bvalbytes))

    X, err = strconv.Atoi(args[2])
    if err != nil {
        return shim.Error("转账金额异常")
    }
    Aval = Aval - X
    Bval = Bval + X
    fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

    //重新更新用户金额
    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    return shim.Success(nil)
}

func (t *LGSimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    if len(args) != 1 {
        return shim.Error("参数异常")
    }
    A := args[0]

    err := stub.DelState(A)
    if err != nil {
        return shim.Error("删除用户异常")
    }

    return shim.Success(nil)
}

func (t *LGSimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    var A string
    var err error

    if len(args) != 1 {
        return shim.Error("查询参数异常")
    }

    A = args[0]

    Avalbytes, err := stub.GetState(A)
    if err != nil {
        jsonResp := "{\"Error\":\"用户金额查询异常 " + A + "\"}"
        return shim.Error(jsonResp)
    }

    if Avalbytes == nil {
        jsonResp := "{\"Error\":\"用户金额为nil " + A + "\"}"
        return shim.Error(jsonResp)
    }

    jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
    fmt.Printf("Query Response:%s\n", jsonResp)
    return shim.Success(Avalbytes)
}

func main() {
    err := shim.Start(new(LGSimpleChaincode))
    if err != nil {
        fmt.Printf("链码部署失败: %s", err)
    }
}

3、拷贝链码到docker容器里面

  • 这里要注意一点是,链码必须是放在容器的/opt/gopath/src目录下,也就是GOPATH目录下
  • 这里使用 docker cp 命令,从本地拷贝到容器中,3316a70035e8是我的容器id,这个你得要看你起的服务里面容器id是多少
    docker cp ./hello/hello.go 3316a70035e8:/opt/gopath/src/github.com/chaincode/lyg/

怎么查看你容器的id,执行

docker ps -a

找到 名字为 cli 的容器

其实 docker cp 也可以直接使用容器的名字进行拷贝:

docker cp ./hello/hello.go cli:/opt/gopath/src/github.com/chaincode/lyg/

4、安装链码

这里我启动的服务是官方的 first-network 网络,怎么启动,怎么搭建环境,可以查看我的另一篇文章:
实战-fabric 环境搭建,创建我们的第一条网络

  • 进入到docker容器
    docker exec -it cli bash
  • 开始安装链码
    peer chaincode install -n lghello -v 1.0 -p github.com/chaincode/lyg/

解释下参数说明:

  • -n 链码名字
  • -v 版本
  • -p 链码目录,定位到链码目录下面

5、实例化链码

peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n lghello -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P 'OR ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')'

解释下参数说明:

  • -n 链码名字
  • -v 版本
  • -p 链码目录,定位到链码目录下面
  • --tls 是否启用tls证书
  • --cafile 如果启用tls证书,这参数是ca的地址
  • -P 这是背书 方案,背书可以理解是执行链码成功的策略,要那几个节点同意后,链码就执行生效
  • -o 排序节点,要指定到端口
  • -C 初始化参数

实例化完成后,会再docker里面创建一个容器,可以通过

docker ps -a

查看

6、调用链码

  • 查询
    peer chaincode query -C mychannel -n lghello -c '{"Args":["query","a"]}'
  • 转账
    peer chaincode invoke -C mychannel -n lghello -c '{"Args":["invoke","a","b","10"]}' -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

    这里要注意,转账需要传对应的排序节点和tls证书

觉得内容不错可以关注我的慕课账号【谦益】,我会继续更新

[获取授权]

点击查看更多内容
6人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
1.6万
获赞与收藏
399

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消