fabric contract链码案例

Posted sanqima

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fabric contract链码案例相关的知识,希望对你有一定的参考价值。

    fabric提供了合约的操作接口,这些接口从原来的源代码里独立出来了,变成fabric-contract-api-go,这里以fabric v1.4.8 + fabric-contract-api-go v1.0.0为例进行说明。

1、环境

  • Ubuntu 16.04
  • fabric v1.4.8
  • fabric-sample v1.4.8
  • fabric-contract-api-go v1.0.0
  • go 1.14.12

    a) 拉取fabric源码,并切换到v1.4.8分支;

## 创建目录
mkdir -p $GOPATH/src/github.com/hyperledger
cd $GOPATH/src/github.com/hyperledger

## 拉取源码
git clone https://github.com/hyperledger/fabric.git

## 切换到v1.4.8分支
cd fabric 
git branch -a 
git checkout v1.4.8

    b) 拉取fabric-sample源码,并切换到v1.4.8分支;

cd $GOPATH/src/github.com/hyperledger

## 拉取源码
git clone https://github.com/hyperledger/fabric-samples.git

## 切换到v1.4.8分支
cd fabric 
git branch -a 
git checkout -b sample v1.4.3

    c) 下载fabric-contract-api-go v1.0.0源码;

cd $GOPATH/src/github.com/hyperledger

wget https://github.com/hyperledger/fabric-contract-api-go/archive/refs/tags/v1.0.0.tar.gz
tar -zxvf fabric-contract-api-go-1.0.0.tar.gz

2、编写contracttwo工程

    a) 创建一个文件夹夹名称为contracttwo,然后对该文件夹进行go mod init

mkdir contracttwo
go mod init contracttwo

    b)修改contracttwo/go.mod文件,并拉取fabric-contract-api-go v1.0.0
//go.mod

module contracttwo

go 1.13

require github.com/hyperledger/fabric-contract-api-go v1.0.0

    拉取fabric-contract-api-go v1.0.0

go env -w GOPROXY=https://goproxy.cn,direct
go get -u github.com/hyperledger/fabric-contract-api-go@v1.0.0

    c) 新建contracttwo.go文件,并编译

//contracttwo.go

package main


import (
	"errors"
	"fmt"

	"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// SimpleContract contract for handling writing and reading from the world state
type SimpleContract struct {
	contractapi.Contract
}

// Create adds a new key with value to the world state
func (sc *SimpleContract) Create(ctx contractapi.TransactionContextInterface, key string, value string) error {
	existing, err := ctx.GetStub().GetState(key)

	if err != nil {
		return errors.New("Unable to interact with world state")
	}

	if existing != nil {
		return fmt.Errorf("Cannot create world state pair with key %s. Already exists", key)
	}

	err = ctx.GetStub().PutState(key, []byte(value))

	if err != nil {
		return errors.New("Unable to interact with world state")
	}

	return nil
}

// Update changes the value with key in the world state
func (sc *SimpleContract) Update(ctx contractapi.TransactionContextInterface, key string, value string) error {
	existing, err := ctx.GetStub().GetState(key)

	if err != nil {
		return errors.New("Unable to interact with world state")
	}

	if existing == nil {
		return fmt.Errorf("Cannot update world state pair with key %s. Does not exist", key)
	}

	err = ctx.GetStub().PutState(key, []byte(value))

	if err != nil {
		return errors.New("Unable to interact with world state")
	}

	return nil
}

// Read returns the value at key in the world state
func (sc *SimpleContract) Read(ctx contractapi.TransactionContextInterface, key string) (string, error) {
	existing, err := ctx.GetStub().GetState(key)

	if err != nil {
		return "", errors.New("Unable to interact with world state")
	}

	if existing == nil {
		return "", fmt.Errorf("Cannot read world state pair with key %s. Does not exist", key)
	}

	return string(existing), nil
}



func main() {
	simpleContract := new(SimpleContract)

	cc, err := contractapi.NewChaincode(simpleContract)

	if err != nil {
		panic(err.Error())
	}

	if err := cc.Start(); err != nil {
		panic(err.Error())
	}
}

go build contracttwo

    d)在$GOPATH/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode目录下,新建一个文件夹名称为chaincode,然后把contracttwo拷贝到该目录。

cd $GOPATH/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode
mkdir chaincode

cp -r /home/tools/contrattwo chaincode/

    e) 将chaincode-docker-devmode/docker-compose-simple.yaml复制一份,重命名为docker-compose.yaml文件,修改如下:
//docker-compose.yaml

## cli容器 增加挂载目录
    volumes:
        - /usr/local/gocode/src/github.com/hyperledger:/opt/gopath/src/github.com/hyperledger

## peer容器 既增加挂载目录,又增加7052端口
    volumes:
        - /usr/local/gocode/src/github.com/hyperledger:/opt/gopath/src/github.com/hyperledger
    ports:
      - 7052:7052

    修改路径chaincode的相对路径:

sed -i "s|./../chaincode|./chaincode|g" docker-compose.yaml
图(1) 在cli容器里,设置hyperledger挂载目录
图(2) 在peer容器里,设置hyperledger挂载目录和7052端口

    目录结构如下:

图(3) chaincode-docker-devmode的目录结构

3、初始化链码

    a) 启动docker服务

cd fabric-samples/chaincode-docker-devmode
docker-compose up -d 

    b) 打开一个新的终端2,依次输入如下命令,进入chaincode容器,编译contracttwo.go源文件

## 进入contracttwo.go所在的目录
cd fabric-samples/chaincode-docker-devmode/chaincode/contracttwo
sudo docker exec -it chaincode bash
go env -w GOPROXY=https://goproxy.cn,direct
go build contracttwo.go

    c) 启动链码

CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=contracttwo:1.0 CORE_PEER_TLS_ENABLED=false ./contracttwo -peer.address peer:7052

    该语句的含义是,在7052端口,启动一个contracttwo链码,版本为1.0。

图(4) 初始化链码

4、安装和实例化链码

    a) 进入chaincode-docker-devmode目录,再打开一个新的终端3,然后,进入cli容器

cd $GOPATH/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode
sudo docker exec -it cli bash

    b) 安装链码
    将contracttwo 1.0链码,安装到节点里

peer chaincode install -v 1.0 -n contracttwo -p chaincodedev/chaincode/contracttwo

    c) 实例化链码

peer chaincode instantiate -C myc -n contracttwo -v 1.0 -c '{"Args":[]}'

5、调用链码

    调用Create(),把tom的值设为80kg,命令如下:

peer chaincode invoke -C myc -n contracttwo -c '{"Args":["Create","tom","80kg"]}'
图(5) 返回200,说明链码调用成功

    打印status=200,说明链码调用Create()函数成功。

6、查询链码里的key-value

    查询key(“tom”)对应的状态数据

peer chaincode query -C myc -n contracttwo -c '{"Args":["Read","tom"]}'

    效果如下:

图(6) 查询tom的值

7、更新key对应的value

    更新tom的值

peer chaincode invoke -C myc -n contracttwo -c '{"Args":["Update", "tom", "100kg"]}' 

    再次查询tom的值,发现tom = 100kg,说明更新成功。

peer chaincode query -C myc -n contracttwo -c '{"Args":["Read","tom"]}'
图(7) 更新tom的值

8、关闭fabric网络

当不再使用fabric时,请关闭fabric网络

cd $GOPATH/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode
docker-compose down

9、完整工程

    contracttwo完整工程 提取码:uka9

以上是关于fabric contract链码案例的主要内容,如果未能解决你的问题,请参考以下文章

Fabric链码入门案例(go语言版本)

fabric 2.4.2-simple序

Fabric系列 - 链码-内部链码的特性

[Fabric] 第13章 区块链应用开发

Hyperledger Fabric 链码 生命周期和API

Fabric基础架构原理:链码 | 赠书活动