linux系统版本:CentOS Linux release 7.2.1511 (Core)
  
 
  
   构建您的第一个网络(BYFN)场景提供了一个由两个组织组成的示例Hyperledger Fabric网络,每个组织都有两个peer节点,以及一个“solo”ordering服务。
  
 
  
   
  
 
  
   (1)先决条件
  
 
  
   -  安装curl
 
   -  安装docker & docker compose,Docker 版本要求 17.06.2-ce or greater
 
  
  
    我本机的docker 版本是Docker version 17.09.0-ce, build afdb6d4
  
 
  
    docker-compose version 1.16.1, build 6d1ac219
  
 
  
   -  安装go语言,版本1.9.x or greater
 
   -  安装node.js和npm
 
   -  python 2.7
 
  
   
    
   The Fabric Node.js SDK requires an iteration of Python 2.7 in order
  
 
   
   for 
   npm install
    operations to complete successfully
  
 
  
   
   
   cd
   
   first
   -
   network
  
 
  
   curl
   
   -
   sSL
   
   https
   :
   //
   goo
   .
   gl
   /
   Q3YRTi
   
   |
   
   bash 如果这个命令不能成功执行的话,就先去下载好对应的脚本,然后再执行,执行好后会发现当前目录多了一个bin目录,目录里面有:
  
 
  
   cryptogen,
  
 
  
   configtxgen,
  
 
  
   configtxlator, and
  
 
  
   peer
  
 
  
   然后把这个bin目录添加到系统的环境变量中去
  
 
   
   
    (2)官网提供了两种方法创建网络:
   
 
   
    -  懒人方法,一键运行脚本
 
   
    
    cd
    
    first
    -
    network
   
 
    
    ./
    byfn
    .
    sh
    
    -
    m
    
    generate
   
 
    
    ./
    byfn
    .
    sh
    
    -
    m
    
    up
   
 
    
    ./
    byfn
    .
    sh
    
    -
    m
    
    down
   
 
   
    -  逐步运行命令
 
   
   
   
    用
    cryptogen来为网络中的实体生成加密材料(证书),这些证书是身份的代表,它们允许在我们的实体进行交流和交易时进行签名/验证身份验证。
   
 
   
    证书是如何工作的:
   
 
   
    cryptogen工具读取包含网络拓扑的
    crypto-config.yaml配置文件来生成相关证书,并允许我们为组织和属于这些组织的组件生成一组证书和密钥。每个组织都配置了一个唯一的根证书(ca-cert),它将特定组件(peer node和ordering node)绑定到该组织。通过为每个组织分配唯一的CA证书,我们正在模仿一个典型的网络,参与会员将使用自己的证书授权。 Hyperledger Fabric中的交易和通信由实体的私钥(keystore)签名,然后通过公钥(signcerts)进行验证。
   
 
   
    我们运行完 
    cryptogen
     这个工具后, 生成的证书和秘钥会保存在一个名为
    crypto-config
    的文件夹里面
   
 
   
   
    configtxgen tool
     用来创建4个配置文件:
   
 
   
    -  orderer genesis block,
 
    -  channel channel configuration transaction,
 
    -  and two anchor peer transactions - one for each Peer Org.
 
   
   
     order block是用于ordering服务的创世纪块,
     channel transaction文件在通道创建时广播给orderer。
    anchor peer transactions, 按照名称可能得出的提示,
    anchor peer transactions在此通道上指定每个组织的锚点peer。
   
 
    
    
   
 
   
    configtxgen
     
    tool是如何工作的?
   
 
   
    Configtxgen 工具读取 - 
    configtx.yaml
     - 这个配置文件,这个配置文件包含一个简单网络的定义。有3个会员 - 一个 Orderer Org (
    OrdererOrg
    ) 和2个 Peer Orgs (
    Org1
     & 
    Org2
    ) ,这两个Org分别管理着两个peer,这个文件也指定了一个 组合- 
    SampleConsortium
     - ,包含了两个Peer Orgs.
   
 
   
    注意:sampleConsortium被定义在system-level profile中,接下来被channel-level profile引用。Channels存在在consortium的范围内,所有的consortium都在network的范围内。
   
 
   
    你会看到这个文件有两个不同的头部,一个是给- 
    TwoOrgsOrdererGenesis
     - 用,另一个是给通道用- 
    TwoOrgsChannel
    .
   
 
   
    这两个头部很重要,因为会作为创建上面4个配置文件的参数给传递出去。
   
 
   
    这个配置文件还有两个附加的定义是值得我们注意的:
   
 
   
    Org(peer0.org1.example.com & peer0.org2.example.com)的anchor节点,另外一个就是指向每个成员的MSP目录的位置,基于此,我们可以将每个Org的根证书存放在orderer Genesis block中,这是一个很重要的概念。现在任意network entity与ordering service通信时就能对其数字签名进行验证。
   
 
   
   
    可以通过configtxgen and cryptogen手动生成证书/密钥以及各项配置文件。同样,可以参考byfn.sh脚本实现。
   
 
   
    可以参考byfn.sh脚本中的generateCerts函数用来生成证书(这些证书被定义在crypto-config.yaml中的网络配置所使用)所需要的命令。为了方便起见,我们提供一个参考如下。
   
 
   
    首先,先跑起来cryptogen工具,我们的二进制文件都在bin目录下,因此我们需要cd到tool所在的目录下.
   
 
   
    ../bin/cryptogen generate --config=./crypto-config.yaml
   
 
    
   
    接下来,我们会告诉configtxgen工具去哪找到需要调用的configtx.yaml文件。
   
 
   
    首先,我们需要设置一个环境变量,用于告知configtxgen根据去哪找configtx.yaml配置文件。接下来,我们调用configtxgen工具创建orderer Genesis block
   
 
   
    export FABRIC_CFG_PATH=
    $PWD..
    /bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
   
 
   
   
    
   
   
    接着,我们创建channel transaction artifact(channel.tx)。然后,确保替换$CHANNEL_NAME
   
 
   
    export CHANNEL_NAME=
    mychannel
   
 
   
    ..
    /bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
   
 
   
   
    
   
   
    接着,我们在我们正在创建的channel上定义Org1的anchor节点。然后,确保替换$CHANNEL_NAME
   
 
   
    ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
   
 
   
   
    
   
   
    然后,我们在相同的channel上定义Org2的anchor节点。
   
 
   
    ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
   
 
   
   
    
   
   
   
    我们利用docker-compose脚本来启动我们的network。docker-compose文件引用了我们之前下载的镜像,并使用前面生成的genesis block来引导orderer。
   
 
   
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/
    peer# command: 
    /bin/bash -c
    ‘./scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT‘
    volumes ---------docker-compose-cli.yaml
   
 
   
    如果没有注释掉上面的命令的话,在network启动的时候,其将执行所有的CLI命令,然后就会导致文章末尾中的错误。
   
 
   
    启动network,注意$CHANNEL_NAME,<pick_a_value>自己设定
   
 
   
    CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=<pick_a_value> docker-compose -f docker-compose-cli.yaml up -d
   
 
   
   
    对于以下针对peer0.org1.example.com的CLI命令,我们需要使用以下给出的四个环境变量来介绍我们的命令。这些peer0.org1.example.com变量都被包含在CLI容器里,因此我们可以不用传递的操作它们。然而!,如果你想发送calls到其他peers或者orderer,你需要根据情况提供这些变量。打开docker-compose-base.yaml并查看具体的路径信息
   
 
   
    # Environment variables
    for
     PEER0CORE_PEER_MSPCONFIGPATH
    =/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/
    mspCORE_PEER_ADDRESS
    =peer0.org1.example.com:
    7051
    CORE_PEER_LOCALMSPID
    =
    "Org1MSP"
    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
   
 
   
   
    docker exec -it cli bash
   
 
   
   
    
   
   
    请回忆下我们使用configtxgen工具生成channel配置artifact-channel.tx。我们将把artifact作为创建channel的请求的一部分发送给orderer。
   
 
   
    注意到在接下来的命令中我们发送了-- cafile作为命令的一部分。这个是orderer证书的本地路径,使得我们可以验证TLS握手。
   
 
   
    我们使用-c flag 标注出我们的channel名称,用-f flag标注出我们的channel 配置transaction。在本例中是channel.tx,然而你可以使用不同的名称用于挂载配置transaction。使用下面创建channel的语句的时候注意channel-name。
   
 
   
    export CHANNEL_NAME=
    mychannel
   
 
   
    peer channel create
    -o orderer.example.com:
    7050
     -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
   
 
   
    上述命令返回了一个genesis block- <channel-ID.block> -我们可以通过这个id进入到channel。它包含channel.tx中指定的配置信息,创建成功后有如下输出:
   
 
   
   
    
   
   
    接下来的操作都需要在CLI容器中进行,在操作peer0.org1.example.com之外的peer时,需要记得相关环境变量的命令。
   
 
   
    接下来我们把peer0.org1.example.com加入到channel中去,channel-ID.block是之前生成的,这里我的是mychannel.block。
   
 
   
    peer channel join
    -b <channel-ID.block>
   
 
   
   
    
   
   
    你可把其他的peer加入到该channel上,但是需要设置上述的四个环境变量。
   
 
   
   
    我们这里只是使用已经存在的chaincode。
   
 
   
    application通过chaincode与blockchain ledger进行交互。我们把chaincode安装到execute与endorse我们transaction的peer上,接下来在channel上初始化chaincode。
   
 
   
    首先,安装sample go代码到4个peer之一的peer上。以下命令把chaincode的源代码放到了peer节点的文件系统上。
   
 
   
    peer
    
    chaincode
    
    install
    
    -
    n
    
    mycc
    
    -
    v
    
    1.0
    
    -
    p
    
    github
    .
    com
    /
    hyperledger
    /
    fabric
    /
    examples
    /
    chaincode
    /
    go
    /
    chaincode_example02
   
 
    
   
    
   
 
   
    接下来,在channel上实例化chaincode。这将在channel上初始化chaincode,同时设置chaincode的endorsement的策略,然后在目标peer上启动chaincode容器。请注意-P参数,我们通过设置这个参数,来指定transaction的endorsement的需求level,用于验证chaincode。
   
 
   
    在下面的命令,我们定义了endorsement策略为-P "OR (‘Org0MSP.member‘,‘Org1MSP.member‘)"。这表示我们需要隶属于Org1或者Org2的peer进行“endorsement”(也就是说,只有一个endorsement)。如果把or改为and则说明我们需要两个endorsement
   
 
   
    peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
   
 
   
   
    
   
   
   
    首先查询a的值,确保chaincode已经正常的实例化,同时确保state DB已经被填充
   
 
   
    peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
   
 
   
   
    
   
   
   
    让我们从a账户转移10个到b账户,这个命令将会创建新的block同时更新state DB。
   
 
   
    peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
   
 
   
   
    
   
   
    peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
   
 
   
   
    
   
   
   
    -  script.sh脚本在CLI容器内部执行,该脚本执行了createChannel命令,提供了channel名称,同时使用channel.tx进行channel配置
 
    -  createChannel的输出是一个genesis block,使用channel名称命名的block,例如mychannel.block,该block在peers的文件系统上存储,该block包括channel.tx指定的channel配置信息。
 
    -  加入channel的命令对所有4个peer进行执行,把之前生成的genesis block作为输入。这个join命令使得peers加入mychannel里面,同时创建了一个以mychannel.block作为开始的chain。
 
    -  接着,我们拥有了由4个peer,两个organization组成的channel。这都在我们TwoOrgsChannel profile.里面。
 
    -  peer0.org1.example.com 与 peer1.org1.example.com 隶属于 Org1; peer0.org2.example.com 以及 peer1.org2.example.com 隶属于 Org2。这些关系在crypto-config.yaml中定义,同时在我们的docker compose中指定了MSP的路径。
 
    -  Org1MSP (peer0.org1.example.com) 以及 Org2MSP (peer0.org2.example.com)的anchor节点接下来被更新了。我们基于建立的channel把Org1MSPanchors.tx 与 Org2MSPanchors.tx 的artifacts,发送给orderering service,以实现上述的更新。
 
    -  chaincode_example02被安装在了peer0.org1.example.com 与 peer0.org2.example.com
 
    -  接着chaincode在peer0.org2.example.com被实例化。实例化把chaincode加到channel上,并启动目标peer的容器,接着初始化chaincode有关的键-值对( [“a”,”100” “b”,”200”])。实例化的过程导致了dev-peer0.org2.example.com-zeychaincode-1.0的启动。
 
    -  实例化需要有endorsement策略的参数,这里设置为-P "OR    (‘Org1MSP.member‘,‘Org2MSP.member‘)",表示任意transaction必须被Org1 或者 Org2的一个peer进行endorsed。
 
    -  接下来把对“a”的查询发送给peer0.org1.example.com,即在peer0.org1.example.com查询a的值。chaincode之前已经安装在了peer0.org1.example.com上,因此这个查询将会针对Org1 peer0 启动一个容器(dev-peer0.org1.example.com-zeychaincode-1.0),然后查询结果得到返回,没有任何写的操作发生,因此返回值是100
 
    -  接着调用请求发送给peer0.org1.example.com,把10个从a转移到b。
 
    -  然后chaincode在peer1.org2.example.com进行安装。
 
    -  然后一个查询a的余额的请求发送到peer1.org2.example.com。这个启动了第三个chaincode容器(dev-peer1.org2.example.com-mycc-1.0),90被返回。正确的反应了上述transaction,a的值被改为了10。
 
   
   
    Error: Got unexpected status: BAD_REQUEST
   
 
   
    原因是存在同名的channel