fabric提供了合约的操作接口,这些接口从原来的源代码里独立出来了,变成fabric-contract-api-go,这里以fabric v1.4.8 + fabric-contract-api-go v1.0.0为例进行说明。
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
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
## peer容器: 增加2条挂载目录,同时,增加7052端口
volumes:
- /usr/local/gocode/pkg:/opt/gopath/pkg
- /usr/local/gocode/src/github.com/hyperledger:/opt/gopath/src/github.com/hyperledger
ports:
- 7052:7052
## cli容器: 增加3条挂载目录
volumes:
- /usr/local/gocode/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode/chaincode:/opt/gopath/src
- /usr/local/gocode/src/github.com/hyperledger:/opt/gopath/src/github.com/hyperledger
- /usr/local/gocode/pkg:/opt/gopath/pkg
## chaincode容器: 增加1条挂载目录
volumes:
- /usr/local/gocode/pkg:/opt/gopath/pkg
修改路径chaincode的相对路径:
sed -i "s|./../chaincode|./chaincode|g" docker-compose.yaml
目录结构如下:
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。
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":[]}'
调用Create(),把tom的值设为80kg,命令如下:
peer chaincode invoke -C myc -n contracttwo -c '{"Args":["Create","tom","80kg"]}'
打印status=200,说明链码调用Create()函数成功。
查询key(“tom”)对应的状态数据
peer chaincode query -C myc -n contracttwo -c '{"Args":["Read","tom"]}'
效果如下:
更新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时,请关闭fabric网络
cd $GOPATH/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode
docker-compose down
contracttwo完整工程 提取码:uka9