天天看点

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/[email protected]
           

    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
           
fabric contract链码案例

图(1) 在cli容器里,设置hyperledger挂载目录

fabric contract链码案例

图(2) 在peer容器里,设置hyperledger挂载目录和7052端口

    目录结构如下:

fabric contract链码案例

图(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。

fabric contract链码案例

图(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"]}'
           
fabric contract链码案例

图(5) 返回200,说明链码调用成功

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

6、查询链码里的key-value

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

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

    效果如下:

fabric contract链码案例

图(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"]}'
           
fabric contract链码案例

图(7) 更新tom的值

8、关闭fabric网络

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

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

9、完整工程

    contracttwo完整工程 提取码:uka9