Set up the Blockchain Network
Step 1: Open Docker Desktop, to let the Docker Daemon runs
Once you click open the software, Docker Daemon is already running. No further actions needed.
Step 2: Clone the Hyperledger Fabric Sample repository, pull down the Docker images, and download the platform-specific binary
Determine a directory you want the sample repo to be in and run:
curl -sSL https://bit.ly/2ysbOFE | bash -s
The curl command will perform clone, pull down, download, and show result in both Terminal and Docker Desktop:
Terminal
Clone hyperledger/fabric-samples repo
===> Cloning hyperledger/fabric-samples repo
Cloning into 'fabric-samples'...
remote: Enumerating objects: 12075, done.
remote: Counting objects: 100% (115/115), done.
remote: Compressing objects: 100% (82/82), done.
remote: Total 12075 (delta 31), reused 101 (delta 27), pack-reused 11960
Receiving objects: 100% (12075/12075), 22.19 MiB | 16.22 MiB/s, done.
Resolving deltas: 100% (6476/6476), done.
===> Checking out v2.4.9 of hyperledger/fabric-samples
Pull Hyperledger Fabric binaries
===> Downloading version 2.4.9 platform specific fabric binaries
===> Downloading: https://github.com/hyperledger/fabric/releases/download/v2.4.9/hyperledger-fabric-darwin-amd64-2.4.9.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 75.4M 100 75.4M 0 0 18.7M 0 0:00:04 0:00:04 --:--:-- 32.3M
==> Done.
===> Downloading version 1.5.5 platform specific fabric-ca-client binary
===> Downloading: https://github.com/hyperledger/fabric-ca/releases/download/v1.5.5/hyperledger-fabric-ca-darwin-amd64-1.5.5.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 29.3M 100 29.3M 0 0 14.8M 0 0:00:01 0:00:01 --:--:-- 41.7M
==> Done.
Pull Hyperledger Fabric docker images
FABRIC_IMAGES: peer orderer ccenv tools baseos
===> Pulling fabric Images
====> docker.io/hyperledger/fabric-peer:2.4.9
2.4.9: Pulling from hyperledger/fabric-peer
ef5531b6e74e: Pull complete
cb6adad689bd: Pull complete
010602cca7ea: Pull complete
dadcffad5b31: Pull complete
3b71f3b82217: Pull complete
9917d15b0b5a: Pull complete
6a2c93fa3f95: Pull complete
Digest: sha256:6ff36af21eb1e0b74f09187a6090c27c42d82b33aa0404bcf94558217e1dfba2
Status: Downloaded newer image for hyperledger/fabric-peer:2.4.9
docker.io/hyperledger/fabric-peer:2.4.9
====> docker.io/hyperledger/fabric-orderer:2.4.9
2.4.9: Pulling from hyperledger/fabric-orderer
ef5531b6e74e: Already exists
cb6adad689bd: Already exists
010602cca7ea: Already exists
44d81e4543ec: Pull complete
9c0a7cb5c6af: Pull complete
275371067d0a: Pull complete
d90823f8c566: Pull complete
Digest: sha256:6ec3fe59ea55b690aaab6c69e5e23da5dc99afda2f046116ed296b395e4d47d1
Status: Downloaded newer image for hyperledger/fabric-orderer:2.4.9
docker.io/hyperledger/fabric-orderer:2.4.9
====> docker.io/hyperledger/fabric-ccenv:2.4.9
2.4.9: Pulling from hyperledger/fabric-ccenv
ca7dd9ec2225: Pull complete
c41ae7ad2b39: Pull complete
eda8cd824576: Pull complete
d71a49e0649a: Pull complete
d34b692b3ee4: Pull complete
66044e0a0724: Pull complete
d974a502e7a7: Pull complete
4fc4ce450dbd: Pull complete
Digest: sha256:b23821060701e9713c4714f337f691b0a736a9312a9360e0886f3acf1df210bc
Status: Downloaded newer image for hyperledger/fabric-ccenv:2.4.9
docker.io/hyperledger/fabric-ccenv:2.4.9
====> docker.io/hyperledger/fabric-tools:2.4.9
2.4.9: Pulling from hyperledger/fabric-tools
ca7dd9ec2225: Already exists
c41ae7ad2b39: Already exists
eda8cd824576: Already exists
d71a49e0649a: Already exists
e918dcca351a: Pull complete
8c49fb870a8c: Pull complete
aa900656510d: Pull complete
Digest: sha256:b1194f509085e0fe622355d119fbb8dfef8b2d78954eabd7d221a39fc90bb850
Status: Downloaded newer image for hyperledger/fabric-tools:2.4.9
docker.io/hyperledger/fabric-tools:2.4.9
====> docker.io/hyperledger/fabric-baseos:2.4.9
2.4.9: Pulling from hyperledger/fabric-baseos
ef5531b6e74e: Already exists
cb6adad689bd: Already exists
bed8f466ba67: Pull complete
Digest: sha256:b86dc8040a48c4dc9df5a9cb309a40ffaaf3984f5cbfe555c00ecf4d02c52ef9
Status: Downloaded newer image for hyperledger/fabric-baseos:2.4.9
docker.io/hyperledger/fabric-baseos:2.4.9
===> Pulling fabric ca Image
====> docker.io/hyperledger/fabric-ca:1.5.5
1.5.5: Pulling from hyperledger/fabric-ca
2408cc74d12b: Pull complete
979557f40538: Pull complete
b3bcd28c0311: Pull complete
Digest: sha256:f93cd9f32702c3a6b9cb305d75bed5edd884cae0674374fd7c26467bf6a0ed9b
Status: Downloaded newer image for hyperledger/fabric-ca:1.5.5
docker.io/hyperledger/fabric-ca:1.5.5
===> List out hyperledger docker images
hyperledger/fabric-tools 2.4 6997a3225d8b 13 days ago 490MB
hyperledger/fabric-tools 2.4.9 6997a3225d8b 13 days ago 490MB
hyperledger/fabric-tools latest 6997a3225d8b 13 days ago 490MB
hyperledger/fabric-peer 2.4 b1c5352410a0 13 days ago 64.2MB
hyperledger/fabric-peer 2.4.9 b1c5352410a0 13 days ago 64.2MB
hyperledger/fabric-peer latest b1c5352410a0 13 days ago 64.2MB
hyperledger/fabric-orderer 2.4 d64956fd66bb 13 days ago 36.7MB
hyperledger/fabric-orderer 2.4.9 d64956fd66bb 13 days ago 36.7MB
hyperledger/fabric-orderer latest d64956fd66bb 13 days ago 36.7MB
hyperledger/fabric-ccenv 2.4 7557f03b34a9 13 days ago 521MB
hyperledger/fabric-ccenv 2.4.9 7557f03b34a9 13 days ago 521MB
hyperledger/fabric-ccenv latest 7557f03b34a9 13 days ago 521MB
hyperledger/fabric-baseos 2.4 0792904ee001 13 days ago 6.8MB
hyperledger/fabric-baseos 2.4.9 0792904ee001 13 days ago 6.8MB
hyperledger/fabric-baseos latest 0792904ee001 13 days ago 6.8MB
hyperledger/fabric-ca 1.5 93f19fa873cb 8 months ago 76.5MB
hyperledger/fabric-ca 1.5.5 93f19fa873cb 8 months ago 76.5MB
hyperledger/fabric-ca latest 93f19fa873cb 8 months ago 76.5MB
Docker Desktop
Hyperledger Fabric Sample repo
Step 3: Add the bin
sub-directory into the PATH environment variable
The curl command executed in step 2 downloaded and executed a bash script that download and extract all of the platform-specific binaries you will need to set up your network and place them into the bin
sub-directory. There are ten binaries:
You should add the sub-directory to your PATH environment variable so that these can be picked up without fully qualifying the path to each binary. E.g.:
export PATH={Your fabric-samples repo}/bin:$PATH
Step 4: Bring up the network
Go into the test-network
sub-directory, run:
cd fabric-samples/test-network
Then, execute another command with the network.sh
script:
./network.sh up
This command creates a Fabric network that consists of two peer nodes and one ordering node. The result will be shown in both Terminal and Docker Desktop:
Terminal
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.9
DOCKER_IMAGE_VERSION=2.4.9
/Users/aerobot/Documents/Sandbox/ChainWallet/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
[+] Running 8/8
⠿ Network fabric_test Created 0.1s
⠿ Volume "compose_peer0.org2.example.com" Created 0.0s
⠿ Volume "compose_orderer.example.com" Created 0.0s
⠿ Volume "compose_peer0.org1.example.com" Created 0.0s
⠿ Container peer0.org1.example.com Started 2.7s
⠿ Container orderer.example.com Started 2.6s
⠿ Container peer0.org2.example.com Started 2.8s
⠿ Container cli Started 3.3s
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
696ec5c8f5d7 hyperledger/fabric-tools:latest "/bin/bash" 3 seconds ago Up Less than a second cli
a86559e93f4a hyperledger/fabric-orderer:latest "orderer" 4 seconds ago Up 1 second 0.0.0.0:7050->7050/tcp, 0.0.0.0:7053->7053/tcp, 0.0.0.0:9443->9443/tcp orderer.example.com
d484f2f81ad0 hyperledger/fabric-peer:latest "peer node start" 4 seconds ago Up 1 second 0.0.0.0:7051->7051/tcp, 0.0.0.0:9444->9444/tcp peer0.org1.example.com
886fa770ac6f hyperledger/fabric-peer:latest "peer node start" 4 seconds ago Up 1 second 0.0.0.0:9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp peer0.org2.example.com
Docker Desktop
Step 5: Create a channel
Channel is a private layer of communication between specific network members. Channels can be used only by organizations that are invited to the channel, and are invisible to other members of the network. Each channel has a separate blockchain ledger. Organizations that have been invited to join their peers to the channel to store the channel ledger and validate the transactions on the channel.
Now that you have peer and orderer nodes running on your machine, you can use the script to create a channel for transactions between Org1 and Org2.
Let's execute another command with the network.sh
script:
./network.sh createChannel
The channel created with the default name 'my channel' will be presented on both Terminal and Docker Desktop:
Terminal
Using docker and docker-compose
Creating channel 'mychannel'.
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 'mychannel.block'
/Users/aerobot/Documents/Sandbox/ChainWallet/fabric-samples/test-network/../bin/configtxgen
+ configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/mychannel.block -channelID mychannel
2023-03-16 12:56:26.465 HKT 0001 INFO [common.tools.configtxgen] main -> Loading configuration
2023-03-16 12:56:26.479 HKT 0002 INFO [common.tools.configtxgen.localconfig] completeInitialization -> orderer type: etcdraft
2023-03-16 12:56:26.479 HKT 0003 INFO [common.tools.configtxgen.localconfig] completeInitialization -> Orderer.EtcdRaft.Options unset, setting to tick_interval:"500ms" election_tick:10 heartbeat_tick:1 max_inflight_blocks:5 snapshot_interval_size:16777216
2023-03-16 12:56:26.479 HKT 0004 INFO [common.tools.configtxgen.localconfig] Load -> Loaded configuration: /Users/aerobot/Documents/Sandbox/ChainWallet/fabric-samples/test-network/configtx/configtx.yaml
2023-03-16 12:56:26.487 HKT 0005 INFO [common.tools.configtxgen] doOutputBlock -> Generating genesis block
2023-03-16 12:56:26.487 HKT 0006 INFO [common.tools.configtxgen] doOutputBlock -> Creating application channel genesis block
2023-03-16 12:56:26.488 HKT 0007 INFO [common.tools.configtxgen] doOutputBlock -> Writing genesis block
+ res=0
Creating channel mychannel
Using organization 1
+ osnadmin channel join --channelID mychannel --config-block ./channel-artifacts/mychannel.block -o localhost:7053 --ca-file /Users/aerobot/Documents/Sandbox/ChainWallet/fabric-samples/test-network/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem --client-cert /Users/aerobot/Documents/Sandbox/ChainWallet/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt --client-key /Users/aerobot/Documents/Sandbox/ChainWallet/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key
+ res=0
Status: 201
{
"name": "mychannel",
"url": "/participation/v1/channels/mychannel",
"consensusRelation": "consenter",
"status": "active",
"height": 1
}
Channel 'mychannel' created
Joining org1 peer to the channel...
Using organization 1
+ peer channel join -b ./channel-artifacts/mychannel.block
+ res=0
2023-03-16 12:56:33.199 HKT 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-16 12:56:33.235 HKT 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/mychannel.block
+ res=0
2023-03-16 12:56:36.322 HKT 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-16 12:56:36.356 HKT 0002 INFO [channelCmd] executeJoin -> Successfully submitted proposal to join channel
Setting anchor peer for org1...
Using organization 1
Fetching channel config for channel mychannel
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 mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
2023-03-16 04:56:36.719 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-16 04:56:36.723 UTC 0002 INFO [cli.common] readBlock -> Received block: 0
2023-03-16 04:56:36.723 UTC 0003 INFO [channelCmd] fetch -> Retrieving last config block: 0
2023-03-16 04:56:36.725 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 mychannel
+ 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 mychannel --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":"mychannel", "type":2}},"data":{"config_update":{' '"channel_id":' '"mychannel",' '"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
2023-03-16 04:56:37.029 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-16 04:56:37.048 UTC 0002 INFO [channelCmd] update -> Successfully submitted channel update
Anchor peer set for org 'Org1MSP' on channel 'mychannel'
Setting anchor peer for org2...
Using organization 2
Fetching channel config for channel mychannel
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 mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
2023-03-16 04:56:37.405 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-16 04:56:37.414 UTC 0002 INFO [cli.common] readBlock -> Received block: 1
2023-03-16 04:56:37.414 UTC 0003 INFO [channelCmd] fetch -> Retrieving last config block: 1
2023-03-16 04:56:37.417 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 mychannel
+ 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 mychannel --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":"mychannel", "type":2}},"data":{"config_update":{' '"channel_id":' '"mychannel",' '"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
2023-03-16 04:56:37.721 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2023-03-16 04:56:37.736 UTC 0002 INFO [channelCmd] update -> Successfully submitted channel update
Anchor peer set for org 'Org2MSP' on channel 'mychannel'
Channel 'mychannel' joined
Docker Desktop
Step 6: Deploy, invoke the Chaincode (Smart Contract), and Interact with the Network