建立您的第一个网络
注意
这些说明已通过验证,可与提供的tar文件中的最新稳定Docker映像和预编译的设置实用程序一起使用。如果使用当前主分支中的图像或工具运行这些命令,则可能会看到配置和紧急错误。
构建您的第一个网络(BYFN)方案将提供一个示例Hyperledger Fabric网络,该网络由两个组织组成,每个组织维护两个对等节点。尽管可以使用其他订购服务实现,但默认情况下还将部署“ Solo”订购服务。
安装先决条件
在我们开始之前,如果您尚未这样做,则不妨检查一下是否已在要开发区块链应用程序和/或运行Hyperledger Fabric的平台上安装了所有必备软件。
您还需要安装Samples,Binaries和Docker Images。您会注意到fabric-samples
存储库中包含许多示例。我们将使用 first-network
示例。现在打开该子目录。
cd fabric-samples/first-network
注意
本文档中提供的命令必须从存储库克隆first-network
的子目录中运行 fabric-samples
。如果选择从其他位置运行命令,则提供的各种脚本将无法找到二进制文件。
要立即运行吗?
我们提供了一个带有完整注释的脚本- byfn.sh
利用这些Docker映像快速引导Hyperledger Fabric网络,该网络默认情况下由代表两个不同组织的四个对等方和一个订购者节点组成。它还将启动一个容器来运行脚本执行,该脚本执行会将对等方加入到通道中,部署链码并根据已部署的链码推动事务的执行。
这是byfn.sh
脚本的帮助文本:
Usage:
byfn.sh [-c ] [-t ] [-d ] [-f ] [-s ] [-l ] [-o ] [-i ] [-v]"
- one of 'up', 'down', 'restart', 'generate' or 'upgrade'"
- 'up' - bring up the network with docker-compose up"
- 'down' - clear the network with docker-compose down"
- 'restart' - restart the network"
- 'generate' - generate required certificates and genesis block"
- 'upgrade' - upgrade the network from version 1.3.x to 1.4.0"
-c - channel name to use (defaults to \"mychannel\")"
-t - CLI timeout duration in seconds (defaults to 10)"
-d - delay duration in seconds (defaults to 3)"
-f - specify which docker-compose file use (defaults to docker-compose-cli.yaml)"
-s - the database backend to use: goleveldb (default) or couchdb"
-l - the chaincode language: golang (default), node, or java"
-o - the consensus-type of the ordering service: solo (default), kafka, or etcdraft"
-i - the tag to be used to launch the network (defaults to \"latest\")"
-v - verbose mode"
byfn.sh -h (print this message)"
Typically, one would first generate the required certificates and
genesis block, then bring up the network. e.g.:"
byfn.sh generate -c mychannel"
byfn.sh up -c mychannel -s couchdb"
byfn.sh up -c mychannel -s couchdb -i 1.4.0"
byfn.sh up -l node"
byfn.sh down -c mychannel"
byfn.sh upgrade -c mychannel"
Taking all defaults:"
byfn.sh generate"
byfn.sh up"
byfn.sh down"
如果选择不提供标志,则脚本将使用默认值。
生成网络工件
准备好尝试了吗?好吧!执行以下命令:
./byfn.sh generate
您将看到有关发生的情况的简短说明,以及是/否命令行提示符。用a响应y
或按回车键执行所描述的操作。
Generating certs and genesis block for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds
Continue? [Y/n] y
proceeding ...
/Users/xxx/dev/fabric-samples/bin/cryptogen
##########################################################
##### Generate certificates using cryptogen tool #########
##########################################################
org1.example.com
2017-06-12 21:01:37.334 EDT [bccsp] GetDefault -> WARN 001 Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP.
...
/Users/xxx/dev/fabric-samples/bin/configtxgen
##########################################################
######### Generating Orderer Genesis block ##############
##########################################################
2017-06-12 21:01:37.558 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.562 EDT [msp] getMspConfig -> INFO 002 intermediate certs folder not found at [/Users/xxx/dev/byfn/crypto-config/ordererOrganizations/example.com/msp/intermediatecerts]. Skipping.: [stat /Users/xxx/dev/byfn/crypto-config/ordererOrganizations/example.com/msp/intermediatecerts: no such file or directory]
...
2017-06-12 21:01:37.588 EDT [common/configtx/tool] doOutputBlock -> INFO 00b Generating genesis block
2017-06-12 21:01:37.590 EDT [common/configtx/tool] doOutputBlock -> INFO 00c Writing genesis block
#################################################################
### Generating channel configuration transaction 'channel.tx' ###
#################################################################
2017-06-12 21:01:37.634 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.644 EDT [common/configtx/tool] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2017-06-12 21:01:37.645 EDT [common/configtx/tool] doOutputChannelCreateTx -> INFO 003 Writing new channel tx
#################################################################
####### Generating anchor peer update for Org1MSP ##########
#################################################################
2017-06-12 21:01:37.674 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.678 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2017-06-12 21:01:37.679 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update
#################################################################
####### Generating anchor peer update for Org2MSP ##########
#################################################################
2017-06-12 21:01:37.700 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.704 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2017-06-12 21:01:37.704 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update
第一步将为我们的各种网络实体生成所有证书和密钥,用于引导订购服务,以及配置Channel所需的配置事务的集合 。genesis block
建立网络
接下来,您可以使用以下命令之一启动网络:
./byfn.sh up
上面的命令将编译Golang链码图像并旋转相应的容器。Go是默认的链码语言,但是还支持Node.js和Java 链码。如果您想使用节点链码来完成本教程,请改用以下命令:
# we use the -l flag to specify the chaincode language
# forgoing the -l flag will default to Golang
./byfn.sh up -l node
注意
有关Node.js填充程序的更多信息,请参阅其 文档。
注意
有关Java填充程序的更多信息,请参阅其 文档。
使样本使用Java chaincode运行,您必须指定如下内容:-l java
./byfn.sh up -l java
注意
不要同时运行这两个命令。除非您关闭并重新建立两者之间的网络,否则只能尝试一种语言。
除了支持多种链码语言外,您还可以发出一个标志,该标志将显示一个五节点的Raft订购服务或Kafka订购服务,而不是一个节点的Solo订购服务。有关当前支持的订购服务实现的更多信息,请查看The Ordering Service。
要使用Raft订购服务启动网络,请发出:
./byfn.sh up -o etcdraft
要使用Kafka订购服务建立网络,请发出:
./byfn.sh up -o kafka
再次提示您是否要继续还是中止。回应一个y
或点击返回键:
Starting for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds
Continue? [Y/n]
proceeding ...
Creating network "net_byfn" with the default driver
Creating peer0.org1.example.com
Creating peer1.org1.example.com
Creating peer0.org2.example.com
Creating orderer.example.com
Creating peer1.org2.example.com
Creating cli
____ _____ _ ____ _____
/ ___| |_ _| / \ | _ \ |_ _|
\___ \ | | / _ \ | |_) | | |
___) | | | / ___ \ | _ < | |
|____/ |_| /_/ \_\ |_| \_\ |_|
Channel name : mychannel
Creating channel...
日志将从此处继续。这将启动所有容器,然后驱动一个完整的端到端应用程序方案。成功完成后,它将在您的终端窗口中报告以下内容:
Query Result: 90
2017-05-16 17:08:15.158 UTC [main] main -> INFO 008 Exiting.....
===================== Query successful on peer1.org2 on channel 'mychannel' =====================
===================== All GOOD, BYFN execution completed =====================
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
您可以滚动浏览这些日志以查看各种事务。如果未得到此结果,请跳至“ 故障排除”部分,让我们看看我们是否可以帮助您发现问题所在。
中断网络
最后,让我们将其全部介绍下来,以便我们一次可以探索网络设置。以下内容将杀死您的容器,删除加密材料和四个工件,并从Docker注册表中删除链码映像:
./byfn.sh down
再次,您将被提示继续,用a响应y
或按回车键:
Stopping with channel 'mychannel' and CLI timeout of '10'
Continue? [Y/n] y
proceeding ...
WARNING: The CHANNEL_NAME variable is not set. Defaulting to a blank string.
WARNING: The TIMEOUT variable is not set. Defaulting to a blank string.
Removing network net_byfn
468aaa6201ed
...
Untagged: dev-peer1.org2.example.com-mycc-1.0:latest
Deleted: sha256:ed3230614e64e1c83e510c0c282e982d2b06d148b1c498bbdcc429e2b2531e91
...
如果您想了解更多有关底层工具和引导机制的信息,请继续阅读。在接下来的几节中,我们将逐步介绍构建一个功能齐全的Hyperledger Fabric网络的各个步骤和要求。
注意
下面概述的手动步骤假定FABRIC_LOGGING_SPEC
在cli
容器被设置为DEBUG
。您可以通过修改目录中的docker-compose-cli.yaml
文件来进行设置first-network
。例如
cli:
container_name: cli
image: hyperledger/fabric-tools:$IMAGE_TAG
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=DEBUG
#- FABRIC_LOGGING_SPEC=INFO
加密发生器
我们将使用该cryptogen
工具为我们的各种网络实体生成加密材料(x509证书和签名密钥)。这些证书代表身份,它们允许在我们的实体进行通信和交易时进行签名/验证身份验证。
它是如何工作的?
Cryptogen使用一个文件- crypto-config.yaml
包含网络拓扑,并允许我们为组织和属于这些组织的组件生成一组证书和密钥。每个组织都有一个唯一的根证书(ca-cert
),它将特定组件(对等和订购者)绑定到该组织。通过为每个组织分配唯一的CA证书,我们正在模仿一个典型的网络,参与的成员将使用其自己的证书颁发机构。Hyperledger Fabric中的事务和通信由实体的私钥(keystore
)签名,然后通过公钥()进行验证signcerts
。
您会count
在此文件中注意到一个变量。我们使用它来指定每个组织的对等点数;在我们的案例中,每个单位有两个同级。我们现在不会深入研究x.509证书和公钥基础结构的细节 。如果您有兴趣,可以自行研究这些主题。
运行该cryptogen
工具后,生成的证书和密钥将保存到名为的文件夹中crypto-config
。请注意,该crypto-config.yaml
文件列出了五个与订购者组织相关的订购者。尽管该 cryptogen
工具将为所有五个订购者创建证书,除非使用了Raft或Kafka订购服务,否则这些订购者中只有一个将用于Solo订购服务实现中并用于创建系统频道和mychannel
。
配置事务生成器
该configtxgen
工具用于创建四个配置工件:
- 订购者,
genesis block
- 通道,
configuration transaction
- 和两个-每个对等组织一个。
anchor peer transactions
有关此工具功能的完整说明,请参见configtxgen。
订购者模块是订购服务的创世纪模块,并且在频道创建时将频道配置事务文件广播到订购者。顾名思义,锚点对等事务指定此通道上的每个组织的锚点对等体。
它是如何工作的?
Configtxgen使用文件-- configtx.yaml
包含示例网络的定义。有三个成员-一个订购者组织(OrdererOrg
)和两个对等组织(Org1
&Org2
),每个成员都管理和维护两个对等节点。该文件还指定了一个财团- SampleConsortium
由我们的两个对等组织组成。请特别注意此文件底部的“配置文件”部分。您会注意到我们有几个唯一的配置文件。一些值得注意的地方:
-
TwoOrgsOrdererGenesis
:生成独奏订购服务的创始块。 -
SampleMultiNodeEtcdRaft
:生成筏订购服务的创始块。仅在发出-o
标志并指定时使用etcdraft
。 -
SampleDevModeKafka
:为Kafka订购服务生成创世块。仅在发出-o
标志并指定时使用kafka
。 -
TwoOrgsChannel
:为我们的频道生成创世块mychannel
。
这些标题很重要,因为在创建工件时,我们会将它们作为参数传递。
注意
注意,我们SampleConsortium
是在系统级配置文件中定义的,然后由我们的通道级配置文件引用。渠道存在于联盟的权限范围内,所有联盟都必须在整个网络范围内定义。
该文件还包含两个值得注意的附加规范。首先,我们为每个对等组织(peer0.org1.example.com
&peer0.org2.example.com
)指定锚点对等体。其次,我们指向每个成员的MSP目录的位置,从而允许我们将每个组织的根证书存储在订购者创始块中。这是一个关键的概念。现在,与订购服务通信的任何网络实体都可以验证其数字签名。
运行工具
您可以使用configtxgen
和cryptogen
命令手动生成证书/密钥和各种配置工件。或者,您可以尝试改编byfn.sh脚本以实现目标。
手动生成工件
您可以generateCerts
在byfn.sh脚本中引用该函数,以获取生成用于crypto-config.yaml
文件中定义的网络配置的证书所需的命令。但是,为方便起见,我们还将在此处提供参考。
首先,让我们运行该cryptogen
工具。我们的二进制文件在bin
目录中,因此我们需要提供工具所在的相对路径。
../bin/cryptogen generate --config=./crypto-config.yaml
您应该在终端中看到以下内容:
org1.example.com
org2.example.com
证书和密钥(即MSP资料)将输出到目录crypto-config
-位于目录根first-network
目录下。
接下来,我们需要告诉该configtxgen
工具在哪里寻找configtx.yaml
需要提取的 文件。我们将在当前的工作目录中告诉它:
export FABRIC_CFG_PATH=$PWD
然后,我们将调用该configtxgen
工具来创建订购者创始块:
../bin/configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
要输出筏订购服务的创始块,此命令应为:
../bin/configtxgen -profile SampleMultiNodeEtcdRaft -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
请注意SampleMultiNodeEtcdRaft
此处使用的配置文件。
要输出Kafka订购服务的创世块,请发出:
../bin/configtxgen -profile SampleDevModeKafka -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
如果您未使用Raft或Kafka,则应看到类似于以下内容的输出:
2017-10-26 19:21:56.301 EDT [common/tools/configtxgen] main -> INFO 001 Loading configuration
2017-10-26 19:21:56.309 EDT [common/tools/configtxgen] doOutputBlock -> INFO 002 Generating genesis block
2017-10-26 19:21:56.309 EDT [common/tools/configtxgen] doOutputBlock -> INFO 003 Writing genesis block
注意
订购者的创世块和我们将要创建的后续工件将输出到channel-artifacts
该项目根目录下的目录中。上面命令中的channelID是系统通道的名称。
创建渠道配置交易
接下来,我们需要创建通道事务构件。确保替换$CHANNEL_NAME
或设置CHANNEL_NAME
为可在以下说明中使用的环境变量:
# The channel.tx artifact contains the definitions for our sample channel
export CHANNEL_NAME=mychannel && ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
请注意,如果您使用的是Raft或Kafka订购服务,则不必对通道发出特殊命令。该TwoOrgsChannel
配置文件将使用您在创建网络的创世纪模块时指定的订购服务配置。
如果您不使用Raft或Kafka订购服务,则应在终端中看到类似于以下内容的输出:
2017-10-26 19:24:05.324 EDT [common/tools/configtxgen] main -> INFO 001 Loading configuration
2017-10-26 19:24:05.329 EDT [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2017-10-26 19:24:05.329 EDT [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 003 Writing new channel tx
接下来,我们将在正在构建的通道上为Org1定义锚点。同样,请确保$CHANNEL_NAME
为以下命令替换或设置环境变量。终端输出将模拟通道事务工件的输出:
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
现在,我们将在同一通道上为Org2定义锚点:
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
启动网络
注意
如果您byfn.sh
以前运行了上面的示例,请确保在继续操作之前关闭了测试网络(请参阅 关闭网络)。
我们将利用脚本来启动我们的网络。docker-compose文件引用了我们先前下载的图像,并使用我们先前生成的引导了订购程序genesis.block
。
我们希望手动检查命令,以显示每个调用的语法和功能。
首先,让我们开始我们的网络:
docker-compose -f docker-compose-cli.yaml up -d
如果要查看网络的实时日志,请不要提供该-d
标志。如果让日志流传输,则需要打开第二个终端以执行CLI调用。
创建并加入频道
回想一下,我们使用上面configtxgen
“ 创建渠道配置交易”部分中的 工具创建了渠道配置交易。您可以使用configtx.yaml
传递给configtxgen
工具的相同或不同的配置文件,重复该过程以创建其他渠道配置事务。然后,您可以重复本节中定义的过程以在网络中建立其他通道。
我们将使用以下命令输入CLI容器:docker exec
docker exec -it cli bash
如果成功,您应该看到以下内容:
root@0d78bb69300d:/opt/gopath/src/github.com/hyperledger/fabric/peer#
为了使以下CLI命令起作用,我们需要在命令前添加以下四个环境变量。这些for peer0.org1.example.com
的变量 被烘焙到CLI容器中,因此我们可以在不传递它们的情况下进行操作。但是,如果要将呼叫发送给其他对等方或订购者,请在进行任何CLI呼叫时覆盖环境变量,如以下示例所示:
# Environment variables for PEER0
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_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
接下来,作为创建通道请求的一部分,我们将把在“ 创建通道配置事务”部分(称为channel.tx
)中创建的生成的通道配置事务工件传递给订购者。
我们用-c
标志指定通道名称,并用标志指定通道配置事务-f
。在这种情况下为channel.tx
,但是您可以使用其他名称挂载自己的配置事务。再次,我们将CHANNEL_NAME
在CLI容器中设置环境变量,以便我们不必显式传递此参数。频道名称必须全部为小写字母,少于250个字符,并且与正则表达式匹配 [a-z][a-z0-9.-]*
。
export CHANNEL_NAME=mychannel
# the channel.tx file is mounted in the channel-artifacts directory within your CLI container
# as a result, we pass the full path for the file
# we also pass the path for the orderer ca-cert in order to verify the TLS handshake
# be sure to export or replace the $CHANNEL_NAME variable appropriately
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
注意
请注意--cafile
,我们作为此命令的一部分进行了传递。这是订购者根证书的本地路径,使我们可以验证TLS握手。
此命令返回一个创世块-
我们将使用它来加入频道。它包含在中指定的配置信息。channel.tx
如果您未对默认通道名称进行任何修改,则该命令将返回标题为的原型mychannel.block
。
注意
这些手动命令的其余部分将保留在CLI容器中。当定位除以外的对等对象时,您还必须记住在所有命令前加上相应的环境变量 peer0.org1.example.com
。
现在让我们加入peer0.org1.example.com
频道。
# By default, this joins ``peer0.org1.example.com`` only
# the was returned by the previous command
# if you have not modified the channel name, you will join with mychannel.block
# if you have created a different channel name, then pass in the appropriately named block
peer channel join -b mychannel.block
您可以通过在上面的“ 创建和加入频道” 部分中使用的四个环境变量进行适当的更改,使其他对等节点加入频道。
与其加入每个对等点,不如简单地加入,peer0.org2.example.com
以便我们可以正确地更新频道中的锚点对等点定义。由于我们将覆盖烘焙到CLI容器中的默认环境变量,因此该完整命令如下:
``
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt peer channel join -b mychannel.block
注意
在v1.4.1之前,docker网络中的所有对等点都使用port `7051`。如果使用v1.4.1之前的版本的fabric-samples,请将`CORE_PEER_ADDRESS`本教程中所有出现的都修改为使用port `7051`。
另外,您可以选择单独设置这些环境变量,而不是传入整个字符串。设置好之后,您只需再次发出命令,CLI容器将代表。`peer channel join``peer0.org2.example.com`
### 更新锚点
以下命令是通道更新,它们将传播到通道的定义。本质上,我们在通道的创世块之上添加了其他配置信息。请注意,我们不是在修改创世块,而只是将增量添加到将定义锚点对等点的链中。
更新通道定义以将Org1的锚点对等定义为`peer0.org1.example.com`:
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
现在更新通道定义,将Org2的锚点对等定义为`peer0.org2.example.com`。与Org2对等方的命令相同,我们需要在此调用之前加上适当的环境变量。`peer channel join`
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
### 安装并实例化Chaincode
注意
我们将利用一个简单的现有链码。要了解如何编写自己的链码,请参阅《[开发人员链码》](https://hyperledger-fabric.readthedocs.io/en/release-1.4/chaincode4ade.html)教程。
应用程序通过进行与区块链分类账的交互`chaincode`。因此,我们需要在将执行并认可我们交易的每个对等方上安装链码,然后在通道上实例化链码。
首先,将示例Go,Node.js或Java chaincode安装到Org1中的peer0节点上。这些命令将指定的源代码样式放置到我们对等方的文件系统上。
注意
每个链码名称和版本只能安装一个版本的源代码。源代码在链代码名称和版本的上下文中存在于对等方的文件系统上;它与语言无关。同样,实例化的链码容器将反映对等方上已安装的任何语言。
**golang**
this installs the Go chaincode. For go chaincode -p takes the relative path from $GOPATH/src
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
**Node.js**
this installs the Node.js chaincode
make note of the -l flag to indicate "node" chaincode
for node chaincode -p takes the absolute path to the node.js chaincode
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/
**Java**
make note of the -l flag to indicate "java" chaincode
for java chaincode -p takes the absolute path to the java chaincode
peer chaincode install -n mycc -v 1.0 -l java -p /opt/gopath/src/github.com/chaincode/chaincode_example02/java/
当我们实例化通道上的链码时,将设置背书策略以要求来自Org1和Org2中的对等方的背书。因此,我们还需要在Org2的对等节点上安装chaincode。
修改以下四个环境变量以对Org2中的peer0发出安装命令:
Environment variables for PEER0 in Org2
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org2.example.com:9051
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
现在,将示例Go,Node.js或Java链码安装到Org2中的peer0上。这些命令将指定的源代码样式放置到我们对等方的文件系统上。
**Golang**
this installs the Go chaincode. For go chaincode -p takes the relative path from $GOPATH/src
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
**Node.js**
this installs the Node.js chaincode
make note of the -l flag to indicate "node" chaincode
for node chaincode -p takes the absolute path to the node.js chaincode
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/
**Java**
make note of the -l flag to indicate "java" chaincode
for java chaincode -p takes the absolute path to the java chaincode
peer chaincode install -n mycc -v 1.0 -l java -p /opt/gopath/src/github.com/chaincode/chaincode_example02/java/
接下来,实例化通道上的链码。这将初始化通道上的链码,为链码设置背书策略,并为目标对等方启动链码容器。注意`-P` 论点。这是我们的政策,其中我们针对要验证的链码指定了交易所需的背书级别。
在下面的命令中,您会注意到我们将策略指定为 。这意味着我们需要来自Org1 **和** Org2 的对等方的“背书” (即两次背书)。如果将语法更改为,则只需要一个背书即可。`-P "AND ('Org1MSP.peer','Org2MSP.peer')"``OR`
**Golang**
be sure to replace the $CHANNEL_NAME environment variable if you have not exported it
if you did not install your chaincode with a name of mycc, then modify that argument as well
peer chaincode instantiate -o orderer.example.com:7050 --tls --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 "AND ('Org1MSP.peer','Org2MSP.peer')"
**Node.js**
注意
Node.js链代码的实例化大约需要一分钟。该命令未挂起;而是在编译映像时安装了fabric-shim层。
be sure to replace the $CHANNEL_NAME environment variable if you have not exported it
if you did not install your chaincode with a name of mycc, then modify that argument as well
notice that we must pass the -l flag after the chaincode name to identify the language
peer chaincode instantiate -o orderer.example.com:7050 --tls --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 -l node -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"
**Java**
注意
请注意,Java链代码实例化可能会花费一些时间,因为它会在Java环境中编译链代码并下载docker容器。
peer chaincode instantiate -o orderer.example.com:7050 --tls --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 -l java -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"
有关 政策实施的更多详细信息,请参阅[背书政策](http://hyperledger-fabric.readthedocs.io/en/latest/endorsement-policies.html)文档。
如果希望其他对等方与分类帐进行交互,则需要将它们加入通道,并将链码源的相同名称,版本和语言安装到适当的对等方的文件系统上。一旦每个对等方尝试与该特定链式代码进行交互,就会为每个对等者启动一个链式代码容器。同样,请注意Node.js图像的编译速度较慢。
一旦链码已在通道上实例化,我们就可以放弃该`l` 标志。我们只需要输入通道标识符和链码的名称即可。
### 询问
让我们查询值`a`以确保正确地实例化了链码并填充了状态数据库。查询的语法如下:
be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
### 调用
现在让我们`10`从`a`移至`b`。此事务将剪切一个新块并更新状态数据库。调用的语法如下:
be sure to set the -C and -n flags appropriately
peer chaincode invoke -o orderer.example.com:7050 --tls true --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 --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'
### 询问
让我们确认先前的调用已正确执行。我们`a`使用值初始化键,`100`并在`10`之前的调用中将其删除。因此,针对的查询`a`应返回`90`。查询的语法如下。
be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
我们应该看到以下内容:
Query Result: 90
随意重新开始并操作键值对和后续调用。
### 安装
现在,我们将链码安装在第三个对等节点Org2中的peer1上。修改以下四个环境变量以对Org2中的peer1发出安装命令:
Environment variables for PEER1 in Org2
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer1.org2.example.com:10051
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
现在,将示例Go,Node.js或Java chaincode安装到Org2中的peer1上。这些命令将指定的源代码样式放置到我们对等方的文件系统上。
**Golang**
this installs the Go chaincode. For go chaincode -p takes the relative path from $GOPATH/src
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
**Node.js**
this installs the Node.js chaincode
make note of the -l flag to indicate "node" chaincode
for node chaincode -p takes the absolute path to the node.js chaincode
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/
**Java**
make note of the -l flag to indicate "java" chaincode
for java chaincode -p takes the absolute path to the java chaincode
peer chaincode install -n mycc -v 1.0 -l java -p /opt/gopath/src/github.com/chaincode/chaincode_example02/java/
### 询问
让我们确认我们可以向Org2中的Peer1发出查询。我们`a`使用值初始化键,`100`并在`10`之前的调用中将其删除。因此,针对的查询`a`仍应返回`90`。
Org2中的peer1必须首先加入通道,然后它才能响应查询。可以通过发出以下命令来加入通道:
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer1.org2.example.com:10051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt peer channel join -b mychannel.block
连接命令返回后,可以发出查询。查询的语法如下。
# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
我们应该看到以下内容:
Query Result: 90
随意重新开始并操作键值对和后续调用。
幕后发生了什么?
注意
这些步骤描述了script.sh
由'./byfn.sh up'运行的情况 。使用清洁网络,并确保此命令处于活动状态。然后使用相同的docker-compose提示符再次启动网络./byfn.sh down
- 脚本--
script.sh
在CLI容器中烘焙。该脚本createChannel
根据提供的通道名称驱动命令,并使用channel.tx文件进行通道配置。 - 的输出
createChannel
是一个创世块--
存储在对等方的文件系统上,并包含从channel.tx指定的通道配置。.block -
joinChannel
对所有四个对等设备执行该命令,该命令将先前生成的创世块作为输入。此命令指示对等方加入
并创建以开头的链
。.block - 现在,我们有一个由四个对等方和两个组织组成的渠道。这是我们的
TwoOrgsChannel
个人资料。 -
peer0.org1.example.com
而peer1.org1.example.com
属于ORG1;peer0.org2.example.com
而peer1.org2.example.com
属于ORG2 - 这些关系是通过定义的
crypto-config.yaml
,MSP路径是在我们的docker compose中指定的。 - 然后,更新Org1MSP(
peer0.org1.example.com
)和Org2MSP(peer0.org2.example.com
)的锚点。为此,我们将Org1MSPanchors.tx
和Org2MSPanchors.tx
工件以及渠道名称一起传递给订购服务。 - 一个chaincode - chaincode_example02 -安装在
peer0.org1.example.com
与peer0.org2.example.com
- 然后将链码“实例化”到
mychannel
。实例化将链码添加到通道,启动目标对等方的容器,并初始化与链码关联的键值对。此示例的初始值为[“ a”,“ 100”,“ b”,“ 200”]。这种“实例化”产生了一个名为“dev-peer0.org2.example.com-mycc-1.0
starting ”的容器。 - 实例化还为背书策略传递了一个参数。该策略定义为 ,这意味着任何事务都必须由与Org1和Org2绑定的对等方认可。
-P "AND ('Org1MSP.peer','Org2MSP.peer')"
- 向“ a”的值发出查询
peer0.org2.example.com
。dev-peer0.org2.example.com-mycc-1.0
实例化链码时,已启动名为Org2 peer0的容器。返回查询结果。没有发生写操作,因此对“ a”的查询仍将返回值“ 100”。 - 发送调用并将 “ 10”从“ a”移动到“ b”
peer0.org1.example.com
并将peer0.org2.example.com
其移动 - 查询发送到
peer0.org2.example.com
“ a”的值。返回值90,正确反映了先前的交易,在该交易中,键“ a”的值被修改了10。 - 链码-chaincode_example02-安装在
peer1.org2.example.com
- 查询发送到
peer1.org2.example.com
“ a”的值。这将启动名为的第三个chaincode容器dev-peer1.org2.example.com-mycc-1.0
。返回值90,正确反映了先前的交易,在该交易中,键“ a”的值被修改了10。
这说明了什么?
必须在对等方上安装Chaincode ,以使其能够对分类帐成功执行读/写操作。此外,直到init
针对该链码执行了传统的交易(读/写)(例如,查询“ a”的值)后,方才启动链码容器。事务导致容器启动。而且,通道中的所有对等方都维护分类账的精确副本,该副本包括将区块,不可变的顺序记录存储在块中的区块链,以及维护当前状态快照的状态数据库。这包括未在其上安装链码的那些对等方(peer1.org1.example.com
如上例所示)。最后,安装链码后即可访问它(例如peer1.org2.example.com
在上面的示例中),因为它已被实例化。
我如何看待这些交易?
检查CLI Docker容器的日志。
docker logs -f cli
您应该看到以下输出:
2017-05-16 17:08:01.366 UTC [msp] GetLocalMSP -> DEBU 004 Returning existing local MSP
2017-05-16 17:08:01.366 UTC [msp] GetDefaultSigningIdentity -> DEBU 005 Obtaining default signing identity
2017-05-16 17:08:01.366 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AB1070A6708031A0C08F1E3ECC80510...6D7963631A0A0A0571756572790A0161
2017-05-16 17:08:01.367 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: E61DB37F4E8B0D32C9FE10E3936BA9B8CD278FAA1F3320B08712164248285C54
Query Result: 90
2017-05-16 17:08:15.158 UTC [main] main -> INFO 008 Exiting.....
===================== Query successful on peer1.org2 on channel 'mychannel' ========================================== All GOOD, BYFN execution completed =====================
| ____| | \ | | | _
| | | | | | | | |
| |__ | |\ | | || |
|_____| || _| |____/
您可以滚动浏览这些日志以查看各种事务。
如何查看链码日志?
检查各个chaincode容器,以查看针对每个容器执行的单独事务。这是每个容器的合并输出:
$ docker logs dev-peer0.org2.example.com-mycc-1.0
04:30:45.947 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Init
Aval = 100, Bval = 200$ docker logs dev-peer0.org1.example.com-mycc-1.0
04:31:10.569 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210$ docker logs dev-peer1.org2.example.com-mycc-1.0
04:31:30.420 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}
了解Docker Compose拓扑
BYFN示例向我们提供了两种Docker Compose文件,这两种文件都是从扩展的docker-compose-base.yaml
(位于base
文件夹中)。我们的第一个风格,docker-compose-cli.yaml
为我们提供了一个CLI容器以及一个订购者和四个对等方。我们将此文件用于此页面上的全部说明。
注意
本节的其余部分介绍了为SDK设计的docker-compose文件。 有关运行这些测试的详细信息,请参考Node SDK仓库。
第二种风味docker-compose-e2e.yaml
构造为使用Node.js SDK运行端到端测试。除了可以使用SDK之外,它的主要区别还在于,Fabric-ca服务器具有容器。因此,我们能够将REST调用发送到组织CA,以进行用户注册和注册。
如果要在docker-compose-e2e.yaml
不先运行byfn.sh脚本的情况下使用,那么我们将需要进行四个小修改。我们需要指向本组织CA的私钥。您可以在crypto-config文件夹中找到这些值。例如,要找到Org1的私钥,我们将遵循以下路径- crypto-config/peerOrganizations/org1.example.com/ca/
。私钥是一个长哈希值,后跟_sk
。Org2的路径为- crypto-config/peerOrganizations/org2.example.com/ca/
。
在docker-compose-e2e.yaml
更新中,ca0和ca1的FABRIC_CA_SERVER_TLS_KEYFILE变量。您还需要编辑命令中提供的路径以启动ca服务器。您为每个CA容器两次提供相同的私钥。
使用CouchDB
可以将状态数据库从默认(goleveldb)切换到CouchDB。CouchDB可以使用相同的链码功能,但是,还具有对链码数据建模为JSON的状态数据库数据内容执行丰富和复杂查询的功能。
要使用CouchDB代替默认数据库(goleveldb),请遵循前面概述的用于生成工件的过程,但同时也要启动网络传递docker-compose-couch.yaml
:
docker-compose -f docker-compose-cli.yaml -f docker-compose-couch.yaml up -d
chaincode_example02现在应该可以在下面使用CouchDB了。
注意
如果您选择实现fabric-couchdb容器端口到主机端口的映射,请确保您了解安全隐患。在开发环境中端口的映射使CouchDB REST API可用,并允许通过CouchDB Web界面(Fauxton)可视化数据库。生产环境可能会避免实施端口映射,以限制外部对CouchDB容器的访问。
您可以使用上述步骤针对CouchDB状态数据库使用chaincode_example02链码,但是,为了行使CouchDB查询功能,您将需要使用链数据编码为JSON的链码(例如,marbles02)。您可以在目录中找到marbles02链码 fabric/examples/chaincode/go
。
我们将按照上述createandjoin一节中所述的相同过程来创建和加入渠道 。将同伴加入频道后,请执行以下步骤与marbles02链码进行交互:
- 在以下位置安装并实例化链码
peer0.org1.example.com
:
# be sure to modify the $CHANNEL_NAME variable accordingly for the instantiate command
peer chaincode install -n marbles -v 1.0 -p github.com/chaincode/marbles02/go
peer chaincode instantiate -o orderer.example.com:7050 --tls --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 marbles -v 1.0 -c '{"Args":["init"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
- 创建一些大理石并将其移动:
# be sure to modify the $CHANNEL_NAME variable accordingly
peer chaincode invoke -o orderer.example.com:7050 --tls --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 marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --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 marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --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 marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --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 marbles -c '{"Args":["transferMarble","marble2","jerry"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --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 marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --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 marbles -c '{"Args":["delete","marble1"]}'
-
如果选择在docker-compose中映射CouchDB端口,则现在可以通过打开浏览器并导航至以下URL,通过CouchDB Web界面(Fauxton)查看状态数据库:
http://localhost:5984/_utils
您应该看到一个名为mychannel
(或您唯一的频道名称)的数据库以及其中的文档。
注意
对于以下命令,请确保适当地更新$ CHANNEL_NAME变量。
您可以从CLI运行常规查询(例如阅读marble2
):
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["readMarble","marble2"]}'
输出应显示以下内容的详细信息marble2
:
Query Result: {"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}
您可以检索特定大理石的历史记录-例如marble1
:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'
输出应显示以下交易marble1
:
Query Result: [{"TxId":"1c3d3caf124c89f91a4c0f353723ac736c58155325f02890adebaa15e16e6464", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}},{"TxId":"755d55c281889eaeebf405586f9e25d71d36eb3d35420af833a20a2f53a3eefd", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"jerry"}},{"TxId":"819451032d813dde6247f85e56a89262555e04f14788ee33e28b232eef36d98f", "Value":}]
您还可以对数据内容执行丰富的查询,例如按所有者查询大理石字段jerry
:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesByOwner","jerry"]}'
输出应显示以下所有的两个弹珠jerry
:
Query Result: [{"Key":"marble2", "Record":{"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}},{"Key":"marble3", "Record":{"color":"blue","docType":"marble","name":"marble3","owner":"jerry","size":70}}]
为什么选择CouchDB
CouchDB是一种NoSQL解决方案。它是一个面向文档的数据库,其中文档字段存储为键值映射。字段可以是简单的键值对,列表或映射。除了LevelDB支持的键/复合键/键范围查询外,CouchDB还支持完整的数据丰富查询功能,例如针对整个区块链数据的非键查询,因为其数据内容以JSON格式存储,并且完全可查询的。因此,CouchDB可以满足LevelDB不支持的许多用例的链码,审计,报告要求。
CouchDB还可以增强区块链中合规性和数据保护的安全性。因为它能够通过过滤和屏蔽事务中的各个属性来实现字段级安全性,并且仅在需要时才授权只读权限。
另外,CouchDB属于CAP定理的AP类型(可用性和分区容差)。它使用带有的主-主复制模型。在CouchDB文档的“ 最终一致性”页面上可以找到更多信息 。但是,在每个结构同位体下,没有数据库副本,可以保证对数据库的写入是一致且持久的(不是)。Eventual Consistency
Eventual Consistency
CouchDB是第一个用于Fabric的外部可插入状态数据库,并且可能并且应该有其他外部数据库选项。例如,IBM为其区块链启用关系数据库。并且可能还需要CP类型(一致性和分区容差)数据库,以便在不保证应用程序级别的情况下实现数据一致性。
关于数据持久性的说明
如果需要在对等容器或CouchDB容器上保持数据持久性,一种选择是将docker-host中的目录挂载到容器中的相关目录中。例如,您可以在docker-compose-base.yaml
文件的对等容器规范中添加以下两行:
volumes:
- /var/hyperledger/peer0:/var/hyperledger/production
对于CouchDB容器,您可以在CouchDB容器规范中添加以下两行:
volumes:
- /var/hyperledger/couchdb0:/opt/couchdb/data
故障排除
- 始终重新启动网络。使用以下命令删除工件,加密,容器和链码图像:
./byfn.sh down
注意
你**会**看到错误,如果你不删除旧容器和图像。
-
如果您看到Docker错误,请首先检查您的Docker版本(Prerequisites),然后尝试重新启动Docker进程。Docker的问题通常无法立即识别。例如,您可能会看到由于无法访问安装在容器中的加密材料而导致的错误。
如果它们仍然存在,请删除您的图像并从头开始:
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -q)
如果在创建,实例化,调用或查询命令时看到错误,请确保已正确更新了通道名称和链码名称。提供的示例命令中包含占位符值。
如果看到以下错误:
Error: Error endorsing chaincode: rpc error: code = 2 desc = Error installing chaincode code mycc:1.0(chaincode /var/hyperledger/production/chaincodes/mycc.1.0 exits)
您可能具有先前运行的链码图像(例如`dev-peer1.org2.example.com-mycc-1.0`或 `dev-peer0.org1.example.com-mycc-1.0`)。删除它们,然后重试。
docker rmi -f $(docker images | grep peer[0-9]-peer[0-9] | awk '{print $3}')
- 如果您看到类似以下内容的内容:
Error connecting: rpc error: code = 14 desc = grpc: RPC failed fast due to transport failure
Error: rpc error: code = 14 desc = grpc: RPC failed fast due to transport failure
确保针对重新标记为“最新”的“ 1.0.0”图像运行网络。
- 如果看到以下错误:
[configtx/tool/localconfig] Load -> CRIT 002 Error reading configuration: Unsupported Config Type ""
panic: Error reading configuration: Unsupported Config Type ""
然后,您没有`FABRIC_CFG_PATH`正确设置环境变量。configtxgen工具需要此变量才能找到configtx.yaml。返回并执行一个,然后重新创建您的通道工件。`export FABRIC_CFG_PATH=$PWD`
- 要清理网络,请使用以下
down
选项:
./byfn.sh down
- 如果看到错误消息指出您仍然具有“活动端点”,请修剪Docker网络。这将清除以前的网络,并为您提供一个全新的环境:
docker network prune
您将看到以下消息:
WARNING! This will remove all networks not used by at least one container.
Are you sure you want to continue? [y/N]
选择`y`。
- 如果看到类似于以下内容的错误:
/bin/bash: ./scripts/script.sh: /bin/bash^M: bad interpreter: No such file or directory
确保有问题的文件(在本示例中为**script.sh**)以Unix格式编码。这很可能是由于未在Git配置中将设置`core.autocrlf`为引起的 `false`(请参阅 [Windows Extras](https://hyperledger-fabric.readthedocs.io/en/release-1.4/prereqs.html#windows-extras))。有几种解决方法。例如,如果您有权访问vim编辑器,请打开文件:
vim ./fabric-samples/first-network/scripts/script.sh
然后通过执行以下vim命令来更改其格式:
:set ff=unix
注意
如果仍然看到错误,请在Hyperledger Rocket Chat 或StackOverflow的结构问题通道上 共享日志 。