区块链笔记(2)-fabric1.4的HelloWorld编写

序言

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

相关源码可点击下载本文全部文件,,由于本人没有积分,有时候下载资源需要付费,迫于无奈设置5积分下载,实在抱歉。

1、创建helloworld目录

# 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目录的权限

# chmod -R 777 ./bin

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

  • crypto-config.yaml:生成证书配置文件,配置如下。(其实就是/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/basic-network目录下crypto-config.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的文件内容)

    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.1 for Application is a catchall flag for behavior which has been
            # determined to be desired for all peers running v1.0.x, but the
            # modification of which would cause incompatibilities.  Users should
            # leave this flag set to true.
            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文件夹

    # ./bin/cryptogen generate --config=./crypto-config.yaml
    
  • 生成创世区块

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

    # ./bin/configtxgen -profile OneOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel
    

上述操作见截图

image-20210319161706204

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文件

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文件

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文件:

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文件

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容器

    docker exec -it cli bash 
    
  • 创建Channel

    # 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

    peer channel join -b mychannel.block
    

7、安装与运行智能合约

  • 安装智能合约

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

    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

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

    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"]}' 
    
  • 退出,清除网络

    docker stop $(docker ps -aq)
    docker rm $(docker ps -aq)
    

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

    image-20210319163701293

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

    参数n说明
    -n链码名称
    -v版本
    -p(小写)链码本地路径
    -P(大写)指定链码所关联的背书策略
    -c(小写)指定链码的初始化参数值
    -C(大写)指定通道名称
    –tls是否启动TLS与Orderer通信
    –cafile $ORDERER_CA指定Orderer服务的TLS证书,TLS启动时有效
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值