区块链笔记(2)-fabric的HelloWorld编写

序言

通过第一篇博客的学习,初步搭建了fabric的基础环境并运行了官方的案例。但是官方End-2-End案例把执行过程集成,通过一条命令即可完成全部操作,初学者通过这些操作只能了解Fabric网络搭建成功与否,对Fabric网络的执行细节还是会感到迷惑。因此打算通过手动的方式搭建一个Orderer、一个Org和一个Peer的Solo排序的Fabric网络。把配置独立出来,形成Orderer和Peer配置的单个yaml配置文件,通过手动执行Orderer和Peer搭建Fabric网络。

1、创建helloworld目录

shell 复制代码
# cd $GOPATH/src/github.com/hyperledger/fabric
# mkdir helloworld
# cd helloworld
# cd $GOPATH/src/github.com/hyperledger/fabric

2、获取生成工具

解压第一篇博客中附带的hyperledger-fabric-ca-linux-amd64-1.4.6.tar压缩包资源,解压后把bin目录复制到helloworld目录下。修改bin目录的权限

shell 复制代码
# chmod -R 777 ./bin

3、准备生成证书和区块配置文件

  • crypto-config.yaml:生成证书配置文件,配置如下。(其实就是/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/basic-network目录下crypto-config.yaml的文件内容,直接拷贝来即可)

    yaml 复制代码
    OrdererOrgs:  ##  定义Orderer组织结构
      - Name: Orderer   ##  Orderer的名称
        Domain: example.com  ##  组织的命名域
           # "Specs" - 有关完整说明,请参阅下面的PeerOrgs
        Specs:
          - Hostname: orderer  # hostname + Domain的值组成Orderer节点的完整域名
                                 #在crypto-config/ordererOrganizations/example.com/orderers 目录下生成orderer.example.com目录
    
    # "PeerOrgs" - 管理Peer节点的组织的定义
    PeerOrgs:
      - Name: Org1  ##  组织名称  组织 1
        Domain: org1.example.com  ##  组织域
        EnableNodeOUs: true     ## 如果设置了EnableNodeOUs,就在msp下生成config.yaml文件
        Template:               ##  允许定义从模板顺序创建的1个或多个主机。
          Count: 1                ##  表示生成几个Peer
        Users:
          Count: 1               ##  表示生成几个普通User,除Admin之外的用户帐户数量
  • configtx.yaml:生成区块及通道配置文件,配置如下。(其实就是修改一下/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network目录下configtx.yaml的文件内容)

    yaml 复制代码
    Organizations:
        ##定义Orderer组织
        - &OrdererOrg
            Name: OrdererOrg
            ID: OrdererMSP
            MSPDir: crypto-config/ordererOrganizations/example.com/msp
            Policies:
                Readers:
                    Type: Signature
                    Rule: "OR('OrdererMSP.member')"
                Writers:
                    Type: Signature
                    Rule: "OR('OrdererMSP.member')"
                Admins:
                    Type: Signature
                    Rule: "OR('OrdererMSP.admin')"
        ##定义Peer组织 1
        - &Org1
            Name: Org1MSP
            ID: Org1MSP
            MSPDir: crypto-config/peerOrganizations/org1.example.com/msp
            Policies:
                Readers:
                    Type: Signature
                    Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
                Writers:
                    Type: Signature
                    Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
                Admins:
                    Type: Signature
                    Rule: "OR('Org1MSP.admin')"
    
            AnchorPeers:   ##  定义组织锚节点 用于跨组织 Gossip 通信
                - Host: peer0.org1.example.com
                  Port: 7051
    Capabilities:
        Channel: &ChannelCapabilities
            V1_4_3: true
            V1_3: false
            V1_1: false
        Orderer: &OrdererCapabilities
            V1_4_2: true
            V1_1: false
        Application: &ApplicationCapabilities
            V1_4_2: true
            V1_3: false
            V1_2: false
            V1_1: false
    
    #Application应用通道相关配置,主要包括 参与应用网络的可用组织信息
    Application: &ApplicationDefaults
    
        Organizations:
    
        Policies:
            Readers:
                Type: ImplicitMeta
                Rule: "ANY Readers"
            Writers:
                Type: ImplicitMeta
                Rule: "ANY Writers"
            Admins:
                Type: ImplicitMeta
                Rule: "MAJORITY Admins"
    
        Capabilities:
            <<: *ApplicationCapabilities
    
    #Orderer系统通道相关配置,包括 Orderer 服务配置和参与Orderer 服务的可用组织
    Orderer: &OrdererDefaults
        OrdererType: solo
        Addresses:
            - orderer.example.com:7050
        BatchTimeout: 2s
        BatchSize:     ##  区块打包的最大包含交易数
            MaxMessageCount: 10
            AbsoluteMaxBytes: 99 MB
            PreferredMaxBytes: 512 KB
    
        Kafka:
            Brokers:
                - 127.0.0.1:9092   ##  kafka的 brokens 服务地址 允许有多个
        Organizations:    ##  参与维护 Orderer 的组织,默认为空
    
        Policies:
            Readers:
                Type: ImplicitMeta
                Rule: "ANY Readers"
            Writers:
                Type: ImplicitMeta
                Rule: "ANY Writers"
            Admins:
                Type: ImplicitMeta
                Rule: "MAJORITY Admins"
            BlockValidation:
                Type: ImplicitMeta
                Rule: "ANY Writers"
        Capabilities:
            <<: *OrdererCapabilities
    
    #Channel系统通道相关配置
    Channel: &ChannelDefaults
        Policies:
            Readers:
                Type: ImplicitMeta
                Rule: "ANY Readers"
            Writers:
                Type: ImplicitMeta
                Rule: "ANY Writers"
            Admins:
                Type: ImplicitMeta
                Rule: "MAJORITY Admins"
        Capabilities:
            <<: *ChannelCapabilities
    
    
    #一系列通道配置模板,包括Orderer 系统通道模板 和 应用通道类型模板
    Profiles:
        ##Orderer的系统通道模板 必须包括 Orderer、 Consortiums 两部分
        OneOrgsOrdererGenesis:
            <<: *ChannelDefaults
            Orderer:
                <<: *OrdererDefaults
                Organizations:
                    - *OrdererOrg
            Consortiums:
                SampleConsortium:
                    Organizations:
                        - *Org1
        OneOrgsChannel:
            Consortium: SampleConsortium
            Application:
                <<: *ApplicationDefaults
                Organizations:
                    - *Org1
  • 生成公私钥和证书,执行该命令后会生成一个crypto-config文件夹

    shell 复制代码
    # ./bin/cryptogen generate --config=./crypto-config.yaml
  • 生成创世区块

    shell 复制代码
    # mkdir channel-artifacts
    # ./bin/configtxgen -profile OneOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
  • 生成通道配置区块

    shell 复制代码
    # ./bin/configtxgen -profile OneOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel

上述操作见截图

4、准备Docker配置文件

配置docker-orderer.yaml和 docker-peer.yaml文件,复制到helloworld目录下。序言说过本例子是一个Orderer、一个Org和一个Peer的Solo排序的Fabric网络 ,这两个配置文件其实是修改了/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/basic-network目录下的docker-compose.yml文件

先看docker-orderer.yaml文件

ruby 复制代码
version: '2'
services:
  orderer.example.com:
    container_name: orderer.example.com
    image: hyperledger/fabric-orderer
    environment:
      - ORDERER_GENERAL_LOGLEVEL=debug
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
      # enabled TLS
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
      - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
      - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: orderer
    volumes:
      - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
      - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
      - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
    ports:
      - 7050:7050

再看docker-peer.yaml文件

ini 复制代码
version: '2'

services:

  peer0.org1.example.com:
    container_name: peer0.org1.example.com
    image: hyperledger/fabric-peer
    environment:
      - GOPATH=/opt/gopath
      - CORE_PEER_ID=peer0.org1.example.com
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
  
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      # the following setting starts chaincode containers on the same
      # bridge network as the peers
      # https://docs.docker.com/compose/networking/
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=helloworld_default
      #- CORE_LOGGING_LEVEL=ERROR
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
    volumes:
        - /var/run/:/host/var/run/
        - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
        - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    ports:
      - 7051:7051
      - 7052:7052
      - 7053:7053

  cli:
    container_name: cli
    image: hyperledger/fabric-tools
    tty: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    volumes:
        - /var/run/:/host/var/run/
        - ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/helloworld/chaincode/go
        - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
        - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    depends_on:
      - peer0.org1.example.com

5、准备部署智能合约

helloworld目录新建chaincode/go/helloworld多级目录,编写智能合约文件到该目录下。该目录有两个文件,一个是cmd/main.go文件,一个是chaincode.go文件

cmd目录下的main.go文件:

go 复制代码
package main

import (
    "fmt"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    "github.com/hyperledger/fabric/helloworld/chaincode/go/helloworld"
)
func main() {
    err := shim.Start(new(helloworld.SimpleChaincode))
    if err != nil {
        fmt.Printf("Error starting Simple chaincode: %s", err)
    }
}

chaincode.go文件

go 复制代码
package helloworld

import (
    "fmt"
    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

// SimpleChaincode implements a simple chaincode to manage an asset
type SimpleChaincode struct {
}

// 链码实例化时,调用Init函数初始化数据
// 链码升级时,也会调用此函数重置或迁移数据
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
    // 获取交易提案中的参数
    args := stub.GetStringArgs()
    if len(args) != 2 {
        return shim.Error("Incorrect arguments. Expecting a key and a value")
    }
    // 通过调用stub.PutState()设置变量和数值
    // 在账本上设置key和value
    err := stub.PutState(args[0], []byte(args[1]))
    if err != nil {
        return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
    }
    return shim.Success(nil)
}

// 调用Invoke函数进行资产交易
// 每笔交易通过get或set操作Init函数创建的key和value
// 通过set可以创建新的key和value
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    // 获取交易提案中的函数和参数
    fn, args := stub.GetFunctionAndParameters()

    var result string
    var err error
    if fn == "set" {
        result, err = set(stub, args)
    } else { // assume 'get' even if fn is nil
        result, err = get(stub, args)
    }
    if err != nil {
        return shim.Error(err.Error())
    }

    // Return the result as success payload
    return shim.Success([]byte(result))
}

// 保存key和value到账本上
// 如果key存在,覆盖原有的value
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 2 {
        return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
    }

    err := stub.PutState(args[0], []byte(args[1]))
    if err != nil {
        return "", fmt.Errorf("Failed to set asset: %s", args[0])
    }
    return args[1], nil
}

// 获取key对应的value
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 1 {
        return "", fmt.Errorf("Incorrect arguments. Expecting a key")
    }

    value, err := stub.GetState(args[0])
    if err != nil {
        return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
    }
    if value == nil {
        return "", fmt.Errorf("Asset not found: %s", args[0])
    }
    return string(value), nil
}

6、启动Fabric网络

  • 启动orderer

    docker-compose -f docker-orderer.yaml up -d
    
  • 启动peer

    docker-compose -f docker-peer.yaml up -d
    
  • 启动cli容器

    bash 复制代码
    docker exec -it cli bash 
  • 创建Channel

    shell 复制代码
    # ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
    
    # peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/mychannel.tx --tls --cafile $ORDERER_CA
  • Peer加入Channel

    bash 复制代码
    peer channel join -b mychannel.block

7、安装与运行智能合约

  • 安装智能合约

    bash 复制代码
    peer chaincode install -n mycc -p github.com/hyperledger/fabric/helloworld/chaincode/go/helloworld/cmd -v 1.0
  • 实例化智能合约

    swift 复制代码
    peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C mychannel -n mycc -v 1.0 -c '{"Args":["a","helloworld"]}' -P "OR ('Org1MSP.peer')"
  • Peer上查询A,显示Helloworld

    erlang 复制代码
    peer chaincode query -C mychannel -n mycc -c '{"Args":["get","a"]}'
  • 若想修改a的值,可以调用set方法

    css 复制代码
    peer chaincode invoke -C mychannel -n mycc -c '{"Args":["set","a","helloha"]}' --tls --cafile $ORDERER_CA
    #由helloworld变成了helloha
    peer chaincode query -C mychannel -n mycc -c '{"Args":["get","a"]}' 
    复制代码
  • 退出,清除网络

    javascript 复制代码
    docker stop $(docker ps -aq)
    docker rm $(docker ps -aq)

    操作截图,最后显示helloworld则表示成功

  • 智能合约操作命令参数说明

    参数n 说明
    -n 链码名称
    -v 版本
    -p(小写) 链码本地路径
    -P(大写) 指定链码所关联的背书策略
    -c(小写) 指定链码的初始化参数值
    -C(大写) 指定通道名称
    --tls 是否启动TLS与Orderer通信
    --cafile $ORDERER_CA 指定Orderer服务的TLS证书,TLS启动时有效
相关推荐
疯一样的码农21 分钟前
基于Spring Boot + Vue3实现的在线商品竞拍管理系统源码+文档
java·spring boot·后端
Y编程小白1 小时前
SpringBoot的pom.xml文件中,scope标签有几种配置?
xml·spring boot·后端
健康平安的活着2 小时前
springboot整合log4j2日志框架1
spring boot·后端·log4j
是一只派大鑫2 小时前
从头开始学MyBatis—04缓存、逆向工程、分页插件
java·后端·mybatis
GoGeekBaird3 小时前
69天探索操作系统-第25天:文件系统基础
后端·操作系统
技术小泽3 小时前
代码思想之快慢路径
java·开发语言·spring boot·后端·设计规范
*长铗归来*4 小时前
ASP.NET Core Web API Hangfire
后端·c#·asp.net·.netcore
江东飞过4 小时前
.net core 的文件操作
开发语言·后端·golang
久久不觉4 小时前
.net core 的字符串处理
开发语言·后端·golang
久久不觉4 小时前
.net core 的软件开发工具
开发语言·后端·golang