Fabric-小例子

汽车信息记录

汽车信息的链码结构
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

你可能感兴趣的:(fabric,区块链,golang)