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
圖(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