HyperLedger Fabric1.4.4 的部署以及测试

本贴最后更新于 1987 天前,其中的信息可能已经天翻地覆

HyperLedger Fabric 的部署以及测试

一、部署

1、软硬件准备(Mine)

* a、centos 7.x * b、jdk 1.8 * c、go 1.12.13 * d、node-v12.13.1 * e、python 3.6 (这里我用了anaconda) * f、docker 18.03.1-ce * g、docker-compose 1.25.0 * f、git
//conda 国内镜像 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --set show_channel_urls yes
// 安装yum管理工具 yum install -y yum-utils // 添加镜像源 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo // 查看docker版本 yum list docker-ce --showduplicates|sort -r //如果上个命令没有查询出来,先执行下面的 curl -o /etc/yum.repos.d/Docker-ce-Ali.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo // 安装 yum install docker-ce-18.03.1.ce-1.el7.centos //设置docker 的国内镜像 # vi /etc/docker/daemon.json { "registry-mirrors": ["http://hub-mirror.c.163.com"] } systemctl restart docker.service
//pip设置源 mkdir ~/.pip vim pip.conf cd ~/.pip vim pip.conf [global] index-url=http://mirrors.aliyun.com/pypi/simple/ [install] trusted-host=mirrors.aliyun.com
//安装 docker-compose pip install docker-compose

2、部署

//下载项目文件 git clone https://github.com/hyperledger/fabric.git //进入scripts目录 cd fabric/scripts //执行 bootstrap.sh 下载相关镜像,比较慢 bash bootstrap.sh

3、生成网络

// 如果 first-network目录 cd fabric/scripts/fabric-samples/first-network/ // 生成创世区块 ./byfn.sh -m generate -C channel_name_xxxx //启动网络 ./byfn.sh -m up -C channel_name_xxxx

二、开发链码进行部署测试

参考 https://blog.csdn.net/TripleS_X/article/details/80550401

1、链码脚本

// chaincode_student.go // ====CHAINCODE EXECUTION SAMPLES (CLI) ================== // ==== 安装、实例化 ==== // peer chaincode install -p chaincodedev/chaincode/Student -n mycc -v 0 // peer chaincode instantiate -n mycc -v 0 -c '{"Args":[]}' -C myc // ==== 调用链码 ==== // peer chaincode invoke -n mycc -c '{"Args":["initSchool", "schoolId_A", "学校A"]}' -C myc // peer chaincode invoke -n mycc -c '{"Args":["initSchool", "schoolId_B", "学校B"]}' -C myc // peer chaincode invoke -n mycc -c '{"Args":["addStudent", "张三", "1", "schoolId_A", "classA"]}' -C myc // peer chaincode invoke -n mycc -c '{"Args":["addStudent", "李四", "2", "schoolId_A", "classA"]}' -C myc // peer chaincode invoke -n mycc -c '{"Args":["addStudent", "老王", "3", "schoolId_B", "classC"]}' -C myc // peer chaincode invoke -n mycc -c '{"Args":["updateStudent", "隔壁老王", "3", "schoolId_B", "classC"]}' -C myc // peer chaincode invoke -n mycc -c '{"Args":["queryStudentByID", "1"]}' -C myc package main import ( "encoding/json" "errors" "fmt" "github.com/hyperledger/fabric/core/chaincode/shim" pd "github.com/hyperledger/fabric/protos/peer" "strconv" ) type StudentChaincode struct { } type Student struct { UserId int `json:"user_id"` //学生id Name string `json:"name"` //姓名 SchoolId string `json:"school_id"` //学校id Class string `jsong:"class"` //班级名称 } type School struct { SchoolId string `json:"id"` //学校id School string `json:"name"` //学校名称 } // ********** chaincode begin ********** // func (t *StudentChaincode) Init(stub shim.ChaincodeStubInterface) pd.Response { return shim.Success(nil) } func (t *StudentChaincode) Invoke(stub shim.ChaincodeStubInterface) pd.Response { fn, args := stub.GetFunctionAndParameters() fmt.Println("invoke is running " + fn) if fn == "initSchool" { return t.initSchool(stub, args) } else if fn == "addStudent" { return t.addStudent(stub, args) } else if fn == "queryStudentByID" { return t.queryStudentByID(stub, args) } else if fn == "deleteSchool" { return t.deleteSchool(stub, args) } else if fn == "updateStudent" { return t.updateStudent(stub, args) } fmt.Println("invoke did not find func: " + fn) return shim.Error("Received unknown function invocation") } // 初始化学校,学生隶属于学校 func (t *StudentChaincode) initSchool(stub shim.ChaincodeStubInterface, args []string) pd.Response { if len(args) != 2 { return shim.Error("Incorrect number of arguments. Expecting 2(school_id, school_name)") } schoolId := args[0] schoolName := args[1] school := &School{schoolId, schoolName} //这里利用联合主键,使得查询school时,可以通过主键的“school”前缀找到所有school schoolKey, err := stub.CreateCompositeKey("School", []string{"school", schoolId}) if err != nil { return shim.Error(err.Error()) } //结构体转json字符串 schoolJSONasBytes, err := json.Marshal(school) if err != nil { return shim.Error(err.Error()) } //保存 err = stub.PutState(schoolKey, schoolJSONasBytes) if err != nil { return shim.Error(err.Error()) } return shim.Success(schoolJSONasBytes) } // 删除学校,包括删除所有对应学生信息 func (t *StudentChaincode) deleteSchool(stub shim.ChaincodeStubInterface, args []string) pd.Response { if len(args) < 1 { return shim.Error("Incorrect number of arguments. Expecting 1(schoolid)") } schoolidAsString := args[0] schoolKey, err := stub.CreateCompositeKey("School", []string{"school", schoolidAsString}) if err != nil { return shim.Error(err.Error()) } schoolAsBytes, err := stub.GetState(schoolKey) if err != nil { return shim.Error("Failed to get school:" + err.Error()) } else if schoolAsBytes == nil { return shim.Error("School does not exist") } //删除学校 err = stub.DelState(schoolKey) if err != nil { return shim.Error("Failed to delete school:" + schoolidAsString + err.Error()) } //删除学校下的所有学生 queryString := fmt.Sprintf("{\"selector\":{\"school_id\":\"%s\"}}", schoolidAsString) resultsIterator, err := stub.GetQueryResult(queryString) //富查询,必须是CouchDB才行 if err != nil { return shim.Error("Rich query failed") } defer resultsIterator.Close() for i := 0; resultsIterator.HasNext(); i++ { responseRange, err := resultsIterator.Next() if err != nil { return shim.Error(err.Error()) } err = stub.DelState(responseRange.Key) if err != nil { return shim.Error("Failed to delete student:" + responseRange.Key + err.Error()) } } return shim.Success(nil) } // 添加学生,需要检查所属学校是否已经初始化 func (t *StudentChaincode) addStudent(stub shim.ChaincodeStubInterface, args []string) pd.Response { st, err := studentByArgs(args) if err != nil { return shim.Error(err.Error()) } useridAsString := strconv.Itoa(st.UserId) //检查学校是否存在,不存在则添加失败 schools := querySchoolIds(stub) if len(schools) > 0 { for _, schoolId := range schools { if schoolId == st.SchoolId { goto SchoolExists } } fmt.Println("school " + st.SchoolId + " does not exist") return shim.Error("school " + st.SchoolId + " does not exist") } else { fmt.Println("school " + st.SchoolId + " does not exist") return shim.Error("school " + st.SchoolId + " does not exist") } SchoolExists: //检查学生是否存在 studentAsBytes, err := stub.GetState(useridAsString) if err != nil { return shim.Error(err.Error()) } else if studentAsBytes != nil { fmt.Println("This student already exists: " + useridAsString) return shim.Error("This student already exists: " + useridAsString) } //结构体转json字符串 studentJSONasBytes, err := json.Marshal(st) if err != nil { return shim.Error(err.Error()) } //保存 err = stub.PutState(useridAsString, studentJSONasBytes) if err != nil { return shim.Error(err.Error()) } return shim.Success(studentJSONasBytes) } // 删除学生 func (t *StudentChaincode) deleteStudent(stub shim.ChaincodeStubInterface, args []string) pd.Response { if len(args) < 1 { return shim.Error("Incorrect number of arguments. Expecting 1(userid)") } useridAsString := args[0] studentAsBytes, err := stub.GetState(useridAsString) if err != nil { return shim.Error("Failed to get student:" + err.Error()) } else if studentAsBytes == nil { return shim.Error("Student does not exist") } err = stub.DelState(useridAsString) if err != nil { return shim.Error("Failed to delete student:" + useridAsString + err.Error()) } return shim.Success(nil) } // 更新学生信息。如果学生不存在,则执行新增学生逻辑 func (t *StudentChaincode) updateStudent(stub shim.ChaincodeStubInterface, args []string) pd.Response { st, err := studentByArgs(args) if err != nil { return shim.Error(err.Error()) } useridAsString := strconv.Itoa(st.UserId) //检查学校是否存在,不存在则添加失败 schools := querySchoolIds(stub) if len(schools) > 0 { for _, schoolId := range schools { if schoolId == st.SchoolId { goto SchoolExists } } fmt.Println("school " + st.SchoolId + " does not exist") return shim.Error("school " + st.SchoolId + " does not exist") } else { fmt.Println("school " + st.SchoolId + " does not exist") return shim.Error("school " + st.SchoolId + " does not exist") } SchoolExists: //因为State DB是一个Key Value数据库,如果我们指定的Key在数据库中已经存在,那么就是修改操作,如果Key不存在,那么就是插入操作。 studentJSONasBytes, err := json.Marshal(st) if err != nil { return shim.Error(err.Error()) } //保存 err = stub.PutState(useridAsString, studentJSONasBytes) if err != nil { return shim.Error(err.Error()) } return shim.Success(studentJSONasBytes) } // 根据学生ID查看学生信息 func (t *StudentChaincode) queryStudentByID(stub shim.ChaincodeStubInterface, args []string) pd.Response { if len(args) < 1 { return shim.Error("Incorrect number of arguments. Expecting 1(userid)") } useridAsString := args[0] studentAsBytes, err := stub.GetState(useridAsString) if err != nil { return shim.Error("Failed to get student:" + err.Error()) } else if studentAsBytes == nil { return shim.Error("Student does not exist") } // 解析json字符串到结构体 // st := Student{} // err = json.Unmarshal(studentAsBytes, &st) // if err != nil { // return shim.Error(err.Error()) // } fmt.Printf("Query Response:%s\n", string(studentAsBytes)) return shim.Success(studentAsBytes) } // ********** chaincode end ********** // // ********** tool fun begin ********** // // 将参数构造成学生结构体 func studentByArgs(args []string) (*Student, error) { if len(args) != 4 { return nil, errors.New("Incorrect number of arguments. Expecting 4(name, userid, schoolid, classid)") } name := args[0] userId, err := strconv.Atoi(args[1]) //字符串转换int if err != nil { return nil, errors.New("2rd argument must be a numeric string") } schoolId := args[2] class := args[3] st := &Student{userId, name, schoolId, class} return st, nil } // 获取所有创建的学校id func querySchoolIds(stub shim.ChaincodeStubInterface) []string { resultsIterator, err := stub.GetStateByPartialCompositeKey("School", []string{"school"}) if err != nil { return nil } defer resultsIterator.Close() scIds := make([]string, 0) for i := 0; resultsIterator.HasNext(); i++ { responseRange, err := resultsIterator.Next() if err != nil { return nil } _, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key) if err != nil { return nil } returnedSchoolId := compositeKeyParts[1] scIds = append(scIds, returnedSchoolId) } return scIds } // ********** tool fun end ********** // // ********** main ********** // func main() { if err := shim.Start(new(StudentChaincode)); err != nil { fmt.Printf("Error starting student chaincode: %s", err) } }

2、开发环境测试链码

将上述的脚本拷贝到 fabric-samples/chaincode 目录
//进入链码开发环境目录 cd fabric-samples/chaincode-docker-devmode

开启 3 个终端

//终端 1 – 启动网络 docker-compose -f docker-compose-simple.yaml up
//终端 2 – 编译和部署链码 docker exec -it chaincode bash cd Student go build CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./Student
//终端3 – 使用链码 docker exec -it cli bash $ cd ../ //安装链码 $ peer chaincode install -p chaincodedev/chaincode/Student -n mycc -v 0 //初始化 $ peer chaincode instantiate -n mycc -v 0 -c '{"Args":[]}' -C myc //调用链码 peer chaincode invoke -n mycc -c '{"Args":["initSchool", "schoolId_A", "学校A"]}' -C myc peer chaincode invoke -n mycc -c '{"Args":["addStudent", "张三", "1", "schoolId_A", "classA"]}' -C myc
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    92 引用 • 752 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...