汽车信息的链码结构
1、引入依赖包
package main
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
sc "github.com/hyperledger/fabric/protos/peer"
)
2、声明一个结构体
type SimpleChaincode struct {
}
3、声明Init() 和 Invoke() 函数
// 在链码初始化过程中调用 Init 来数据,此处不做任何操作
func (s *SmartContract) Init(APIstub shim.ChaincodeStubInterface) sc.Response {
return shim.Success(nil)
}
// query 和 invoke 时被自动调用
func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response {
// 解析用户调用链码传递的函数名及参数
function, args := APIstub.GetFunctionAndParameters()
// 调用不同的函数
if function == "queryCar" {
return s.queryCar(APIstub, args)
} else if function == "initLedger" {
return s.initLedger(APIstub)
} else if function == "createCar" {
return s.createCar(APIstub, args)
} else if function == "queryAllCars" {
return s.queryAllCars(APIstub)
} else if function == "changeCarOwner" {
return s.changeCarOwner(APIstub, args)
}
return shim.Error("Invalid Smart Contract function name.")
}
4、对Invoke() 函数中的各个函数就是进行声明
// 初始化账本数据
func (s *SmartContract) initLedger(APIstub shim.ChaincodeStubInterface) sc.Response {
cars := []Car{
Car{
Make: "Toyota", Model: "Prius", Colour: "blue", Owner: "Tomoko"},
Car{
Make: "Ford", Model: "Mustang", Colour: "red", Owner: "Brad"},
Car{
Make: "Hyundai", Model: "Tucson", Colour: "green", Owner: "Jin Soo"},
Car{
Make: "Volkswagen", Model: "Passat", Colour: "yellow", Owner: "Max"},
Car{
Make: "Tesla", Model: "S", Colour: "black", Owner: "Adriana"},
Car{
Make: "Peugeot", Model: "205", Colour: "purple", Owner: "Michel"},
Car{
Make: "Chery", Model: "S22L", Colour: "white", Owner: "Aarav"},
Car{
Make: "Fiat", Model: "Punto", Colour: "violet", Owner: "Pari"},
Car{
Make: "Tata", Model: "Nano", Colour: "indigo", Owner: "Valeria"},
Car{
Make: "Holden", Model: "Barina", Colour: "brown", Owner: "Shotaro"},
}
i := 0
for i < len(cars) {
fmt.Println("i is ", i)
carAsBytes, _ := json.Marshal(cars[i])
// key 为编号 CARi,value 为 Car 结构体的 json 串
APIstub.PutState("CAR"+strconv.Itoa(i), carAsBytes)
fmt.Println("Added", cars[i])
i = i + 1
}
return shim.Success(nil)
}
// 根据编号查询汽车
func (s *SmartContract) queryCar(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
carAsBytes, _ := APIstub.GetState(args[0])
return shim.Success(carAsBytes)
}
// 创建一辆新的汽车数据
func (s *SmartContract) createCar(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 5 {
return shim.Error("Incorrect number of arguments. Expecting 5")
}
var car = Car{
Make: args[1], Model: args[2], Colour: args[3], Owner: args[4]}
carAsBytes, _ := json.Marshal(car)
APIstub.PutState(args[0], carAsBytes)
return shim.Success(nil)
}
// 查询全部的汽车
func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response {
// 查询 startKey(包括)到 endKey(不包括)间的值
startKey := "CAR0"
endKey := "CAR999"
resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close() // 延迟关闭迭代器
// 将查询结果以 json 字符串的形式写入 buffer
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(queryResponse.Key)
buffer.WriteString("\"")
buffer.WriteString(", \"Record\":")
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- queryAllCars:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
// 根据汽车编号改变车的拥有者
func (s *SmartContract) changeCarOwner(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
carAsBytes, _ := APIstub.GetState(args[0])
car := Car{
}
json.Unmarshal(carAsBytes, &car)
car.Owner = args[1] // 更改汽车拥有者
carAsBytes, _ = json.Marshal(car)
APIstub.PutState(args[0], carAsBytes) // 更新账本
return shim.Success(nil)
}
5、主函数
func main() {
err := shim.Start(new(SmartContract))
if err != nil {
fmt.Printf("Error creating new Smart Contract: %s", err)
}
}
PS:shim.Start() 中 的SmartContract 是上面声明的结构体
将该链码放于./fabric/fabric-samples/chaincode/car/go/
接下来我们启动本地测试网络
$ docker-compose -f docker-compose-simple.yaml up -d
docker-compose-simple.yaml文件一般是位于/fabric/fabric-samples/chaincode-docker-devmode
进入链码容器,对链码进行编译
$ docker exec -it chaincode bash
root@61638bc49a3b:/opt/gopath/src/chaincode# cd car
root@61638bc49a3b:/opt/gopath/src/chaincode/car# cd go
root@61638bc49a3b:/opt/gopath/src/chaincode/car/go# go build
执行成功后当前目录会生成一个可执行文件go,此时需要启动这个可执行文件.
CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=test:0 ./go
执行成功后显示:
这边为什么用7052端口,是因为peer:7052是用于链码专用监听地址及端口号,而7051是peer节点监听的是网络端口号.
2020-10-07 05:35:29.120 UTC [shim] SetupChaincodeLogging -> INFO 001 Chaincode log level not provided; defaulting to: INFO
2020-10-07 05:35:29.120 UTC [shim] SetupChaincodeLogging -> INFO 002 Chaincode (build level: ) starting up ...
打开终端二
进入cli容器中
$ docker exec -it cli bash
查看当前节点加入的通道
root@ef915a1edb32:/opt/gopath/src/chaincodedev# peer channel list
显示结果
Channels peers has joined:
myc
每一个人的通道不一定一样的,所有最好检查一下。
安装和实例化链码
root@ef915a1edb32:/opt/gopath/src/chaincodedev# peer chaincode install -p chaincodedev/chaincode/fabcar/go -n test -v 0
root@ef915a1edb32:/opt/gopath/src/chaincodedev# peer chaincode instantiate -n test -v 0 -c '{"Args":[]}' -C myc
初始化数据,调用initLedger函数:
root@ef915a1edb32:/opt/gopath/src/chaincodedev# peer chaincode invoke -n test -c '{"Args":["initLedger"]}' -C myc
查询所有汽车的信息:
root@ef915a1edb32:/opt/gopath/src/chaincodedev# peer chaincode query -n test -c '{"Args":["queryAllCars"]}' -C myc
[{
"Key":"CAR0", "Record":{
"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},
{
"Key":"CAR1", "Record":{
"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},
{
"Key":"CAR2", "Record":{
"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},
{
"Key":"CAR3", "Record":{
"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},
{
"Key":"CAR4", "Record":{
"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},
{
"Key":"CAR5", "Record":{
"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},
{
"Key":"CAR6", "Record":{
"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},
{
"Key":"CAR7", "Record":{
"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},
{
"Key":"CAR8", "Record":{
"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},
{
"Key":"CAR9", "Record":{
"make":"Holden","model":"Barina","colour":"brown","owner":"Shotaro"}}]
创建编号为CAR10的汽车信息
root@ef915a1edb32:/opt/gopath/src/chaincodedev# peer chaincode invoke -n test -c '{"Args":["createCar","CAR10","Toyota","Prius","blue","233"]}' -C myc
查询编号为CAR10的汽车信息
root@ef915a1edb32:/opt/gopath/src/chaincodedev# peer chaincode query -n test -c '{"Args":["queryCar","CAR10"]}' -C myc
{
"make":"Toyota","model":"Prius","colour":"blue","owner":"233"}
关闭网络:$ docker-compose -f docker-compose-simple.yaml down