入门
安装git
安装curl
2)、在fabric-samples目录下执行命令:
curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s
它将下载docker镜像,并将下载:
configtxgen,
configtxlator,
cryptogen,
discover,
idemixgen(这个没找到)
orderer,
peer,
fabric-ca-client,
fabric-ca-server
tips: 其实我执行上面的bash命令时,下载的文件跟上面的有些不一样,没有idenmixgen
[test@hst:fabric-samples]$ ls bin/
total 219M
drwxrwxr-x 31 test test 4.0K Apr 13 04:14 ..
-rwxr-xr-x 1 test test 46M Jan 28 12:57 peer
-rwxr-xr-x 1 test test 13M Jan 28 12:56 osnadmin
-rwxr-xr-x 1 test test 17M Jan 28 12:56 ledgerutil
-rwxr-xr-x 1 test test 17M Jan 28 12:56 discover
-rwxr-xr-x 1 test test 12M Jan 28 12:56 cryptogen
-rwxr-xr-x 1 test test 15M Jan 28 12:56 configtxlator
-rwxr-xr-x 1 test test 18M Jan 28 12:56 configtxgen
-rwxr-xr-x 1 test test 29M Jan 28 12:56 orderer
drwxr-xr-x 2 test test 4.0K Sep 9 2021 .
-rwxr-xr-x 1 test test 32M Sep 9 2021 fabric-ca-server
-rwxr-xr-x 1 test test 25M Sep 9 2021 fabric-ca-client
3)、把bin路径放到PATH中
export FABRIC_SAMPLE=/home/test/data/prj/fabric-samples
export PATH=$FABRIC_SAMPLE/bin:$PATH
在fabric-samples/test-network目录下查看network.sh的帮助:
./network.sh -h
[test@hst:test-network]$ ./network.sh -h
Using docker and docker-compose
Usage:
network.sh <Mode> [Flags]
Modes:
up - Bring up Fabric orderer and peer nodes. No channel is created
up createChannel - Bring up fabric network with one channel
createChannel - Create and join a channel after the network is created
deployCC - Deploy a chaincode to a channel (defaults to asset-transfer-basic)
down - Bring down the network
Flags:
Used with network.sh up, network.sh createChannel:
-ca <use CAs> - Use Certificate Authorities to generate network crypto material
-c <channel name> - Name of channel to create (defaults to "mychannel")
-s <dbtype> - Peer state database to deploy: goleveldb (default) or couchdb
-r <max retry> - CLI times out after certain number of attempts (defaults to 5)
-d <delay> - CLI delays for a certain number of seconds (defaults to 3)
-verbose - Verbose mode
Used with network.sh deployCC
-c <channel name> - Name of channel to deploy chaincode to
-ccn <name> - Chaincode name.
-ccl <language> - Programming language of the chaincode to deploy: go, java, javascript, typescript
-ccv <version> - Chaincode version. 1.0 (default), v2, version3.x, etc
-ccs <sequence> - Chaincode definition sequence. Must be an integer, 1 (default), 2, 3, etc
-ccp <path> - File path to the chaincode.
-ccep <policy> - (Optional) Chaincode endorsement policy using signature policy syntax. The default policy requires an endorsement from Org1 and Org2
-cccg <collection-config> - (Optional) File path to private data collections configuration file
-cci <fcn name> - (Optional) Name of chaincode initialization function. When a function is provided, the execution of init will be requested and the function will be invoked.
-h - Print this message
Possible Mode and flag combinations
up -ca -r -d -s -verbose
up createChannel -ca -c -r -d -s -verbose
createChannel -c -r -d -verbose
deployCC -ccn -ccl -ccv -ccs -ccp -cci -r -d -verbose
Examples:
network.sh up createChannel -ca -c mychannel -s couchdb
network.sh createChannel -c channelName
network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
network.sh deployCC -ccn mychaincode -ccp ./user/mychaincode -ccv 1 -ccl javascript
1)、先执行down命令,用于删除先前运行的所有容器或工程
可以通过执行以下命令来启动网络。如果您尝试从另一个目录运行脚本,则会遇到问题:
./network.sh up
此命令创建一个由两个对等节点和一个排序节点组成的Fabric网络。 运行./network.sh up时没有创建任何channel,如成功,则看到如下日志:
tips: 我这儿看到启动了4个container:一个fabric-tools容器,一个fabric-orderer容器,两个fabric-peer容器
[test@hst:test-network]$ ./network.sh up
Using docker and docker-compose
Starting nodes with CLI timeout of '5' tries and CLI delay of '3' seconds and using database 'leveldb' with crypto from 'cryptogen'
LOCAL_VERSION=2.4.2
DOCKER_IMAGE_VERSION=2.4.2
/home/test/data/prj/fabric-samples/test-network/../bin/cryptogen
Generating certificates using cryptogen tool
Creating Org1 Identities
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output=organizations
org1.example.com
+ res=0
Creating Org2 Identities
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-org2.yaml --output=organizations
org2.example.com
+ res=0
Creating Orderer Org Identities
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-orderer.yaml --output=organizations
+ res=0
Generating CCP files for Org1 and Org2
Creating network "fabric_test" with the default driver
Creating volume "compose_orderer.example.com" with default driver
Creating volume "compose_peer0.org1.example.com" with default driver
Creating volume "compose_peer0.org2.example.com" with default driver
Creating peer0.org1.example.com ... done
Creating orderer.example.com ... done
Creating peer0.org2.example.com ... done
Creating cli ... done
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cbea3bb297c hyperledger/fabric-tools:latest "/bin/bash" Less than a second ago Up Less than a second cli
a2d8d8f845a5 hyperledger/fabric-orderer:latest "orderer" 2 seconds ago Up Less than a second 0.0.0.0:7050->7050/tcp, :::7050->7050/tcp, 0.0.0.0:7053->7053/tcp, :::7053->7053/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp orderer.example.com
b13dce1a2347 hyperledger/fabric-peer:latest "peer node start" 2 seconds ago Up Less than a second 0.0.0.0:9051->9051/tcp, :::9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp, :::9445->9445/tcp peer0.org2.example.com
0dad98f8d648 hyperledger/fabric-peer:latest "peer node start" 2 seconds ago Up Less than a second 0.0.0.0:7051->7051/tcp, :::7051->7051/tcp, 0.0.0.0:9444->9444/tcp, :::9444->9444/tcp peer0.org1.example.com
2)、测试网络的组成部分
执行docker ps -a可以看到创建的节点:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cbea3bb297c hyperledger/fabric-tools:latest "/bin/bash" 2 minutes ago Up 2 minutes cli
a2d8d8f845a5 hyperledger/fabric-orderer:latest "orderer" 2 minutes ago Up 2 minutes 0.0.0.0:7050->7050/tcp, :::7050->7050/tcp, 0.0.0.0:7053->7053/tcp, :::7053->7053/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp orderer.example.com
b13dce1a2347 hyperledger/fabric-peer:latest "peer node start" 2 minutes ago Up 2 minutes 0.0.0.0:9051->9051/tcp, :::9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp, :::9445->9445/tcp peer0.org2.example.com
0dad98f8d648 hyperledger/fabric-peer:latest "peer node start" 2 minutes ago Up 2 minutes 0.0.0.0:7051->7051/tcp, :::7051->7051/tcp, 0.0.0.0:9444->9444/tcp, :::9444->9444/tcp peer0.org1.example.com
与Fabric网络互动的每个节点和用户都必须属于一个网络成员的组织。 Fabric网络成员的所有组织通常称为联盟(consortium)。 测试网络有两个联盟成员,Org1和Org2。 该网络还包括一个维护网络排序服务的排序组织
tips: "属于一个网络成员的组织":这个“一个”的理解是:不是“同一个”,而是“某一个”
一个联盟可以包含多个组织,一个组织可以包含多个节点
Peer节点 是任何Fabric网络的基本组件。
对等节点存储区块链账本并在进行
交易之前对其进行验证。 同行运行包含业务用于管理区块链账本的智能合约上的业务逻辑。
tips: 节点存储区块链账本;在交易前进行验证;运行智能合约上的业务逻辑(!!! 干嘛加那么多定语????)
网络中的每个对等方都必须属于该联盟的成员。 在测试网络里,每个组织各自运营一个对等节点, peer0.org1.example.com和peer0.org2.example.com.
每个Fabric网络还包括一个排序服务。 虽然对等节点验证交易并将交易块添加到区块链账本,他们不决定交易顺序或包含他们进入新的区块。 在分布式网络上,对等点可能运行得很远彼此之间没有什么共同点,并且对何时创建事务没有共同的看法。 在交易顺序上达成共识是一个代价高昂的过程,为同伴增加开销。
排序服务允许对等节点专注于验证交易并将它们提交到账本。 排序节点从客户那里收到认可的交易后,他们就交易顺序达成共识,然后添加区块。 这些区块之后被分配给添加这些区块到账本的对等节点。 排序节点还可以操作定义Fabric网络的功能的系统通道,例如如何制作块以及节点可以使用的Fabric版本。 系统通道定义了哪个组织是该联盟的成员。
该示例网络使用一个单节点Raft排序服务,该服务由排序组织运行。 您可以看到在您机器上正在运行的排序节点orderer.example.com。 虽然测试网络仅使用单节点排序服务,一个真实的网络将有多个排序节点,由一个或多个多个排序者组织操作。 不同的排序节点将使用Raft共识算法达成跨交易顺序的共识网络。
3)、
创建一个通道
现在我们的机器上正在运行对等节点和排序节点, 我们可以使用脚本创建用于在Org1和Org2之间进行交易的Fabric通道。 通道是特定网络成员之间的专用通信层。通道只能由被邀请加入通道的组织使用,并且对网络的其他成员不可见。 每个通道都有一个单独的区块链账本。被邀请的组织“加入”他们的对等节点来存储其通道账本并验证交易。
您可以使用network.sh
脚本在Org1和Org2之间创建通道并加入他们的对等节点。 运行以下命令以创建一个默认名称为“ mychannel”的通道:
./network.sh createChannel
如果命令成功执行,您将看到以下消息打印在您的日志:
========= Channel successfully joined ===========
您也可以使用channel标志创建具有自定义名称的通道。 作为一个例子,以下命令将创建一个名为channel1
的通道:
./network.sh createChannel -c channel1
通道标志还允许您创建多个不同名称的多个通道。 创建mychannel
或channel1
之后,您可以使用下面的命令创建另一个名为channel2
的通道:
./network.sh createChannel -c channel2
如果您想一步建立网络并创建频道,则可以使用up
和createChannel
模式一起:
./network.sh up createChannel
tips: 使用./network.sh createChannel -c st-channel1,结果如下:
[test@racknerd-82c692:test-network]$ ./network.sh createChannel -c st-channel1
Using docker and docker-compose
Creating channel 'st-channel1'.
If network is not up, starting nodes with CLI timeout of '5' tries and CLI delay of '3' seconds and using database 'leveldb
Network Running Already
Using docker and docker-compose
Generating channel genesis block 'st-channel1.block'
/home/test/data/prj/fabric-samples/test-network/../bin/configtxgen
+ configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/st-channel1.block -channelID st-channel1
2022-04-13 05:06:26.062 BST 0001 INFO [common.tools.configtxgen] main -> Loading configuration
2022-04-13 05:06:26.079 BST 0002 INFO [common.tools.configtxgen.localconfig] completeInitialization -> orderer type: etcdraft
2022-04-13 05:06:26.079 BST 0003 INFO [common.tools.configtxgen.localconfig] completeInitialization -> Orderer.EtcdRaft.Options unset, settingto tick_interval:"500ms" election_tick:10 heartbeat_tick:1 max_inflight_blocks:5 snapshot_interval_size:16777216
2022-04-13 05:06:26.079 BST 0004 INFO [common.tools.configtxgen.localconfig] Load -> Loaded configuration: /home/test/data/prj/fabric-samples/test-network/configtx/configtx.yaml
2022-04-13 05:06:26.084 BST 0005 INFO [common.tools.configtxgen] doOutputBlock -> Generating genesis block
2022-04-13 05:06:26.084 BST 0006 INFO [common.tools.configtxgen] doOutputBlock -> Creating application channel genesis block
2022-04-13 05:06:26.085 BST 0007 INFO [common.tools.configtxgen] doOutputBlock -> Writing genesis block
+ res=0
Creating channel st-channel1
Using organization 1
+ osnadmin channel join --channelID st-channel1 --config-block ./channel-artifacts/st-channel1.block -o localhost:7053 --ca-file /home/test/data/prj/fabric-samples/test-network/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem --client-cert /home/test/data/prj/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt --client-key /home/test/data/prj/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key
+ res=0
Status: 201
{
"name": "st-channel1",
"url": "/participation/v1/channels/st-channel1",
"consensusRelation": "consenter",
"status": "active",
"height": 1
}
Channel 'st-channel1' created
Joining org1 peer to the channel...
Using organization 1
+ peer channel join -b ./channel-artifacts/st-channel1.block
+ res=0
2022-04-13 05:06:32.249 BST 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2022-04-13 05:06:32.286 BST 0002 INFO [channelCmd] executeJoin -> Successfully submitted proposal to join channel
Joining org2 peer to the channel...
Using organization 2
+ peer channel join -b ./channel-artifacts/st-channel1.block
+ res=0
2022-04-13 05:06:35.384 BST 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2022-04-13 05:06:35.414 BST 0002 INFO [channelCmd] executeJoin -> Successfully submitted proposal to join channel
Setting anchor peer for org1...
Using organization 1
Fetching channel config for channel st-channel1
Using organization 1
Fetching the most recent configuration block for the channel
+ peer channel fetch config config_block.pb -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com -c st-channel1 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
2022-04-13 04:06:35.722 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2022-04-13 04:06:35.728 UTC 0002 INFO [cli.common] readBlock -> Received block: 0
2022-04-13 04:06:35.729 UTC 0003 INFO [channelCmd] fetch -> Retrieving last config block: 0
2022-04-13 04:06:35.730 UTC 0004 INFO [cli.common] readBlock -> Received block: 0
Decoding config block to JSON and isolating config to Org1MSPconfig.json
+ configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
+ jq '.data.data[0].payload.data.config' config_block.json
Generating anchor peer update transaction for Org1 on channel st-channel1
+ jq '.channel_group.groups.Application.groups.Org1MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.org1.example.com","port": 7051}]},"version": "0"}}' Org1MSPconfig.json
+ configtxlator proto_encode --input Org1MSPconfig.json --type common.Config --output original_config.pb
+ configtxlator proto_encode --input Org1MSPmodified_config.json --type common.Config --output modified_config.pb
+ configtxlator compute_update --channel_id st-channel1 --original original_config.pb --updated modified_config.pb --output config_update.pb
+ configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
+ jq .
++ cat config_update.json
+ echo '{"payload":{"header":{"channel_header":{"channel_id":"st-channel1", "type":2}},"data":{"config_update":{' '"channel_id":' '"st-channel1",' '"isolated_data":' '{},' '"read_set":' '{' '"groups":' '{' '"Application":' '{' '"groups":' '{' '"Org1MSP":' '{' '"groups":' '{},' '"mod_policy":' '"",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '},' '"write_set":' '{' '"groups":' '{' '"Application":' '{''"groups":' '{' '"Org1MSP":' '{' '"groups":' '{},' '"mod_policy":' '"Admins",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"AnchorPeers":' '{' '"mod_policy":' '"Admins",' '"value":' '{' '"anchor_peers":' '[' '{' '"host":' '"peer0.org1.example.com",''"port":' 7051 '}' ']' '},' '"version":' '"0"' '},' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '}}}}'
+ configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output Org1MSPanchors.tx
2022-04-13 04:06:36.102 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2022-04-13 04:06:36.123 UTC 0002 INFO [channelCmd] update -> Successfully submitted channel update
Anchor peer set for org 'Org1MSP' on channel 'st-channel1'
Setting anchor peer for org2...
Using organization 2
Fetching channel config for channel st-channel1
Using organization 2
Fetching the most recent configuration block for the channel
+ peer channel fetch config config_block.pb -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com -c st-channel1 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
2022-04-13 04:06:36.383 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2022-04-13 04:06:36.387 UTC 0002 INFO [cli.common] readBlock -> Received block: 1
2022-04-13 04:06:36.388 UTC 0003 INFO [channelCmd] fetch -> Retrieving last config block: 1
2022-04-13 04:06:36.390 UTC 0004 INFO [cli.common] readBlock -> Received block: 1
Decoding config block to JSON and isolating config to Org2MSPconfig.json
+ configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
+ jq '.data.data[0].payload.data.config' config_block.json
Generating anchor peer update transaction for Org2 on channel st-channel1
+ jq '.channel_group.groups.Application.groups.Org2MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.org2.example.com","port": 9051}]},"version": "0"}}' Org2MSPconfig.json
+ configtxlator proto_encode --input Org2MSPconfig.json --type common.Config --output original_config.pb
+ configtxlator proto_encode --input Org2MSPmodified_config.json --type common.Config --output modified_config.pb
+ configtxlator compute_update --channel_id st-channel1 --original original_config.pb --updated modified_config.pb --output config_update.pb
+ configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
+ jq .
++ cat config_update.json
+ echo '{"payload":{"header":{"channel_header":{"channel_id":"st-channel1", "type":2}},"data":{"config_update":{' '"channel_id":' '"st-channel1",' '"isolated_data":' '{},' '"read_set":' '{' '"groups":' '{' '"Application":' '{' '"groups":' '{' '"Org2MSP":' '{' '"groups":' '{},' '"mod_policy":' '"",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '},' '"write_set":' '{' '"groups":' '{' '"Application":' '{''"groups":' '{' '"Org2MSP":' '{' '"groups":' '{},' '"mod_policy":' '"Admins",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"AnchorPeers":' '{' '"mod_policy":' '"Admins",' '"value":' '{' '"anchor_peers":' '[' '{' '"host":' '"peer0.org2.example.com",''"port":' 9051 '}' ']' '},' '"version":' '"0"' '},' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '}}}}'
+ configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output Org2MSPanchors.tx
2022-04-13 04:06:36.747 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2022-04-13 04:06:36.768 UTC 0002 INFO [channelCmd] update -> Successfully submitted channel update
Anchor peer set for org 'Org2MSP' on channel 'st-channel1'
Channel 'st-channel1' joined
4)、ongoing
在通道启动一个链码
创建通道后,您可以开始使用智能合约与通道账本交互。 智能合约包含管理区块链账本上资产的业务逻辑。 由成员运行的应用程序网络可以在账本上调用智能合约创建,更改和转让这些资产。 应用程序还通过智能合约查询,以在分类帐上读取数据。
为确保交易有效,使用智能合约创建的交易通常需要由多个组织签名才能提交到通道账本。 多个签名是Fabric信任模型不可或缺的一部分。 一项交易需要多次背书,以防止一个通道上的单一组织使用通道不同意的业务逻辑篡改其对等节点的分类账本。 要签署交易,每个组织都需要调用并在其对等节点上执行智能合约,然后签署交易的输出。 如果输出是一致的并且已经有足够的组织签名,则可以将交易提交到账本。 该政策被称为背书政策,指定需要执行智能交易的通道上的已设置组织合同,针对每个链码设置为链码定义的一部分。
在Fabric中,智能合约作为链码以软件包的形式部署在网络上。 链码安装在组织的对等节点上,然后部署到某个通道,然后可以在该通道中用于认可交易和区块链账本交互。 在将链码部署到通道前,该频道的成员需要就链码定义达成共识,建立链码治理。 何时达到要求数量的组织同意后,链码定义可以提交给通道,并且可以使用链码了。
使用network.sh
创建频道后,您可以使用以下命令在通道上启动链码:
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
deployCC
子命令将在peer0.org1.example.com
和peer0.org2.example.com
上安装 asset-transfer (basic) 链码。 然后在使用通道标志(或mychannel
如果未指定通道)的通道上部署指定的通道的链码。 如果您第一次部署一套链码,脚本将安装链码的依赖项。默认情况下,脚本安装Go版本的 asset-transfer (basic) 链码。 但是您可以使用语言便签 -l
,用于安装 Java 或 javascript 版本的链码。 您可以在 fabric-samples
目录的 asset-transfer-basic
文件夹中找到 asset-transfer (basic) 链码。 此目录包含作为案例和用来突显 Fabric 特征的样本链码。
5)、
与网络交互
在您启用测试网络后,可以使用peer
CLI与您的网络进行交互。 peer
CLI允许您调用已部署的智能合约,更新通道,或安装和部署新的智能合约。
确保您正在从test-network
目录进行操作。 如果你按照说明安装示例,二进制文件和Docker映像, 您可以在fabric-samples
代码库的bin
文件夹中找到peer
二进制文件。 使用以下命令将这些二进制文件添加到您的CLI路径:
export PATH=${PWD}/../bin:$PATH
您还需要将fabric-samples
代码库中的FABRIC_CFG_PATH
设置为指向其中的core.yaml
文件:
export FABRIC_CFG_PATH=$PWD/../config/
现在,您可以设置环境变量,以允许您作为Org1操作peer
CLI:
# Environment variables for Org1
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
CORE_PEER_TLS_ROOTCERT_FILE
和CORE_PEER_MSPCONFIGPATH
环境变量指向Org1的organizations
文件夹中的的加密材料。 如果您使用 ./network.sh deployCC -ccl go
安装和启动 asset-transfer (basic) 链码,您可以调用链码(Go)的 InitLedger
方法来赋予一些账本上的初始资产(如果使用 typescript 或者 javascript,例如 ./network.sh deployCC -l javascript
,你会调用相关链码的 initLedger
功能)。 运行以下命令用一些资产来初始化账本:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'
如果命令成功,您将观察到类似以下的输出:
-> INFO 001 Chaincode invoke successful. result: status:200
现在你可以用你的 CLI 工具来查询账本。运行以下指令来获取添加到通道账本的资产列表:
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
如果成功,您将看到以下输出:
[
{"ID": "asset1", "color": "blue", "size": 5, "owner": "Tomoko", "appraisedValue": 300},
{"ID": "asset2", "color": "red", "size": 5, "owner": "Brad", "appraisedValue": 400},
{"ID": "asset3", "color": "green", "size": 10, "owner": "Jin Soo", "appraisedValue": 500},
{"ID": "asset4", "color": "yellow", "size": 10, "owner": "Max", "appraisedValue": 600},
{"ID": "asset5", "color": "black", "size": 15, "owner": "Adriana", "appraisedValue": 700},
{"ID": "asset6", "color": "white", "size": 15, "owner": "Michel", "appraisedValue": 800}
]
当一个网络成员希望在账本上转一些或者改变一些资产,链码会被调用。使用以下的指令来通过调用 asset-transfer (basic) 链码改变账本上的资产所有者:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset6","Christopher"]}'
如果命令成功,您应该看到以下响应:
2019-12-04 17:38:21.048 EST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
因为 asset-transfer (basic) 链码的背书策略需要交易同时被 Org1 和 Org2 签名,链码调用指令需要使用 --peerAddresses
标签来指向 peer0.org1.example.com
和 peer0.org2.example.com
。因为网络的 TLS 被开启,指令也需要用 --tlsRootCertFiles
标签指向每个 peer 节点的 TLS 证书。
调用链码之后,我们可以使用另一个查询来查看调用如何改变了区块链账本的资产。因为我们已经查询了 Org1 的 peer,我们可以把这个查询链码的机会通过 Org2 的 peer 来运行。设置以下的环境变量来操作 Org2:
# Environment variables for Org2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
你可以查询运行在 peer0.org2.example.com
asset-transfer (basic) 链码:
peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}'
结果显示 "asset6"
转给了 Christopher:
{"ID":"asset6","color":"white","size":15,"owner":"Christopher","appraisedValue":800}
关停网络
使用完测试网络后,您可以使用以下命令关闭网络:
该命令将停止并删除节点和链码容器,删除组织加密材料,并从Docker Registry移除链码镜像。 该命令还删除之前运行的通道项目和docker卷。如果您遇到任何问题,还允许您再次运行./ network.sh up
。
下一步
既然您已经使用测试网络在您的本地计算机上部署了Hyperledger Fabric,您可以使用教程来开始开发自己的解决方案:
- 使用将智能合约部署到通道 教程了解如何来将自己的智能合约部署到测试网络。
- 访问编写您的第一个应用程序 教程了解如何从您的客户端程序使用Fabric SDK提供的API调用智能合约。
- 如果您准备将更复杂的智能合约部署到网络,请跟随商业票据教程 探索两个组织使用区块链网络进行商业票据交易的用例。
您可以在教程页上找到Fabric教程的完整列表。
使用认证机构建立网络
Hyperledger Fabric使用公钥基础设施(PKI)来验证所有网络参与者的行为。 每个节点,网络管理员和用户提交的交易需要具有公共证书和私钥以验证其身份。 这些身份必须具有有效的信任根源,该证书是由作为网络中的成员组织颁发的。 network.sh
脚本在创建对等和排序节点之前创建所有部署和操作网络所有需要的加密材料。
默认情况下,脚本使用cryptogen工具创建证书和密钥。 该工具用于开发和测试,并且可以快速为具有有效根信任的Fabric组织创建所需的加密材料。 当您运行./network.sh up
时,您会看到cryptogen工具正在创建Org1,Org2和Orderer Org的证书和密钥。
creating Org1, Org2, and ordering service organization with crypto from 'cryptogen'
/Usr/fabric-samples/test-network/../bin/cryptogen
##########################################################
##### Generate certificates using cryptogen tool #########
##########################################################
##########################################################
############ Create Org1 Identities ######################
##########################################################
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output=organizations
org1.example.com
+ res=0
+ set +x
##########################################################
############ Create Org2 Identities ######################
##########################################################
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-org2.yaml --output=organizations
org2.example.com
+ res=0
+ set +x
##########################################################
############ Create Orderer Org Identities ###############
##########################################################
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-orderer.yaml --output=organizations
+ res=0
+ set +x
测试网络脚本还提供了使用证书颁发机构(CA)的网络的启动选项。 在产品网络中,每个组织操作一个CA(或多个中间CA)来创建属于他们的组织身份。 所有由该组织运行的CA创建的身份享有相同的组织信任根源。 虽然花费的时间比使用cryptogen多,使用CA建立测试网络,提供了在产品中部署网络的指导。 部署CA还可以让您注册Fabric SDK的客户端身份,并为您的应用程序创建证书和私钥。
如果您想使用Fabric CA建立网络,请首先运行以下命令关停所有正在运行的网络:
然后,您可以使用CA标志启动网络:
执行命令后,您可以看到脚本启动了三个CA,每个网络中的组织一个。
##########################################################
##### Generate certificates using Fabric CA's ############
##########################################################
Creating network "net_default" with the default driver
Creating ca_org2 ... done
Creating ca_org1 ... done
Creating ca_orderer ... done
值得花一些时间检查/ network.sh
脚本部署CA之后生成的日志。 测试网络使用Fabric CA客户端以每个组织的CA注册节点和用户身份。 之后这个脚本使用enroll命令为每个身份生成一个MSP文件夹。 MSP文件夹包含每个身份的证书和私钥,以及在运营CA的组织中建立身份的角色和成员身份。 您可以使用以下命令来检查Org1管理员用户的MSP文件夹:
tree organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/
该命令将显示MSP文件夹的结构和配置文件:
organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/
└── msp
├── IssuerPublicKey
├── IssuerRevocationPublicKey
├── cacerts
│ └── localhost-7054-ca-org1.pem
├── config.yaml
├── keystore
│ └── 58e81e6f1ee8930df46841bf88c22a08ae53c1332319854608539ee78ed2fd65_sk
├── signcerts
│ └── cert.pem
└── user
您可以在signcerts
文件夹中找到管理员用户的证书,然后在keystore
文件夹中找到私钥。 要了解有关MSP的更多信息,请参阅成员服务提供者概念主题。
cryptogen和Fabric CA都为每个组织在organizations
文件夹中生成加密材料。 您可以在organizations/fabric-ca
目录中的registerEnroll.sh
脚本中找到用于设置网络的命令。 要了解更多有关如何使用Fabric CA部署Fabric网络的信息,请访问Fabric CA操作指南。 您可以通过访问identity和membership概念主题了解有关Fabric如何使用PKI的更多信息。
幕后发生了什么?
如果您有兴趣了解有关示例网络的更多信息,则可以调查test-network
目录中的文件和脚本。 下面的步骤提供了有关在您发出./network.sh up
命令时会发生什么情况的导览。
./ network.sh
为两个对等组织和排序组织创建证书和密钥。 默认情况下,脚本利用cryptogen工具使用位于organizations/cryptogen
文件夹中的配置文件。 如果使用-ca
标志创建证书颁发机构,则脚本使用Fabric CA服务器配置文件和位于organizations/fabric-ca
文件夹的registerEnroll.sh
脚本。 cryptogen和Fabric CA均会在organisations
文件夹创建所有三个组织中的加密资料和MSP文件夹。- 该脚本使用configtxgen工具创建系统通道生成块。 Configtxgen使用了
TwoOrgsOrdererGenesis
通道配置文件中的configtx/configtx.yaml
文件创建创世区块。 区块被存储在system-genesis-block
文件夹中。 - 一旦组织的加密资料和系统通道的创始块生成后,
network.sh
就可以启动网络的节点。 脚本使用docker
文件夹中的docker-compose-test-net.yaml
文件创建对等节点和排序节点。 docker
文件夹还包含 docker-compose-e2e.yaml
文件启动网络节点三个Fabric CA。 该文件旨在用于Fabric SDK 运行端到端测试。 请参阅Node SDK代码库有关运行这些测试的详细信息。 - 如果您使用
createChannel
子命令,则./ network.sh
使用提供的频道名称, 运行在scripts
文件夹中的createChannel.sh
脚本来创建通道。 该脚本使用configtx.yaml
文件来创建通道创作事务,以及两个锚对等节点更新交易。 该脚本使用对等节点cli创建通道,加入peer0.org1.example.com
和peer0.org2.example.com
到频道, 以及使两个对等节点都成为锚对等节点。 - 如果执行
deployCC
命令,./ network.sh
会运行deployCC.sh
脚本在两个 peer 节点上安装**asset-transfer (basic)**链码, 然后定义通道上的链码。 一旦将链码定义提交给通道,对等节点cli使用Init
初始化链码并调用链码将初始数据放入账本。
故障排除
如果您对本教程有任何疑问,请查看以下内容:
您应该始终重新启动网络。 您可以使用以下命令删除先前运行的工件,加密材料,容器,卷和链码镜像:
如果您不删除旧的容器,镜像和卷,将看到报错。
如果您看到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-asset-transfer-1.0
或 dev-peer0.org1.example.com-asset-transfer-1.0
)。 删除它们并再次尝试。
docker rmi -f $(docker images | grep dev-peer[0-9] | awk '{print $3}')
如果您看到以下错误:
[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/configtx/configtx.yaml
,然后重新创建您的通道工件。
如果看到错误消息指出您仍然具有“active endpoints”,请清理您的Docker网络。 这将清除您以前的网络,并以全新环境开始:
您将看到一下信息:
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/createChannel.sh: /bin/bash^M: bad interpreter: No such file or directory
确保有问题的文件(在此示例中为createChannel.sh)为以Unix格式编码。 这很可能是由于未在Git配置中将core.autocrlf
设置为false
(查看Windows Extras)。 有几种解决方法。 如果你有例如vim编辑器,打开文件:
vim ./fabric-samples/test-network/scripts/createChannel.sh
然后通过执行以下vim命令来更改其格式:
如果您的排序者在创建时退出,或者您看到由于无法连接到排序服务创建通道命令失败, 请使用docker logs
命令从排序节点读取日志。 你可能会看到以下消息:
PANI 007 [channel system-channel] config requires unsupported orderer capabilities: Orderer capability V2_0 is required but not supported: Orderer capability V2_0 is required but not supported
当您尝试使用Fabric 1.4.x版本docker镜像运行网络时,会发生这种情况。 测试网络需要使用Fabric 2.x版本运行。