Module 4: Exercises and Assessment
Practical Exercises
Exercise 1: Setting Up a Basic Fabric Network
Objective: Set up a basic Hyperledger Fabric network with two organizations, each with one peer, and a single orderer node.
Tasks:
-
Create a working directory for your network:
bash mkdir -p ~/fabric-network cd ~/fabric-network -
Create a
crypto-config.yamlfile: ```bash cat > crypto-config.yaml << EOF OrdererOrgs:- Name: Orderer
Domain: example.com
Specs:
- Hostname: orderer
- Name: Orderer
Domain: example.com
Specs:
PeerOrgs: - Name: Org1 Domain: org1.example.com EnableNodeOUs: true Template: Count: 1 Users: Count: 1
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 1
Users:
Count: 1
EOF ```
-
Create a
configtx.yamlfile: ```bash cat > configtx.yaml << EOF Organizations:-
&OrdererOrg Name: OrdererOrg ID: OrdererMSP MSPDir: crypto-config/ordererOrganizations/example.com/msp Policies: Readers: Type: Signature Rule: "OR('OrdererMSP.member')" Writers: Type: Signature Rule: "OR('OrdererMSP.member')" Admins: Type: Signature Rule: "OR('OrdererMSP.admin')"
-
&Org1 Name: Org1MSP ID: Org1MSP MSPDir: crypto-config/peerOrganizations/org1.example.com/msp Policies: Readers: Type: Signature Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" Writers: Type: Signature Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" Admins: Type: Signature Rule: "OR('Org1MSP.admin')" Endorsement: Type: Signature Rule: "OR('Org1MSP.peer')" AnchorPeers:
- Host: peer0.org1.example.com Port: 7051
-
&Org2 Name: Org2MSP ID: Org2MSP MSPDir: crypto-config/peerOrganizations/org2.example.com/msp Policies: Readers: Type: Signature Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')" Writers: Type: Signature Rule: "OR('Org2MSP.admin', 'Org2MSP.client')" Admins: Type: Signature Rule: "OR('Org2MSP.admin')" Endorsement: Type: Signature Rule: "OR('Org2MSP.peer')" AnchorPeers:
- Host: peer0.org2.example.com Port: 9051
-
Capabilities: Channel: &ChannelCapabilities V2_0: true Orderer: &OrdererCapabilities V2_0: true Application: &ApplicationCapabilities V2_0: true
Application: &ApplicationDefaults Organizations: Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" LifecycleEndorsement: Type: ImplicitMeta Rule: "MAJORITY Endorsement" Endorsement: Type: ImplicitMeta Rule: "MAJORITY Endorsement" Capabilities: <<: *ApplicationCapabilities
Orderer: &OrdererDefaults OrdererType: solo Addresses: - orderer.example.com:7050 BatchTimeout: 2s BatchSize: MaxMessageCount: 10 AbsoluteMaxBytes: 99 MB PreferredMaxBytes: 512 KB Organizations: Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" BlockValidation: Type: ImplicitMeta Rule: "ANY Writers" Capabilities: <<: *OrdererCapabilities
Channel: &ChannelDefaults Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ChannelCapabilities
Profiles: TwoOrgsOrdererGenesis: <<: ChannelDefaults Orderer: <<: OrdererDefaults Organizations: - OrdererOrg Consortiums: SampleConsortium: Organizations: - Org1 - Org2 TwoOrgsChannel: Consortium: SampleConsortium <<: ChannelDefaults Application: <<: ApplicationDefaults Organizations: - Org1 - Org2 Capabilities: <<: ApplicationCapabilities EOF ```
- Create a
docker-compose.yamlfile: ```bash cat > docker-compose.yaml << EOF version: '3.7'
networks: fabric_network:
services: orderer.example.com: container_name: orderer.example.com image: hyperledger/fabric-orderer:2.5.0 environment: - FABRIC_LOGGING_SPEC=INFO - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_LISTENPORT=7050 - ORDERER_GENERAL_GENESISMETHOD=file - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block - ORDERER_GENERAL_LOCALMSPID=OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp - ORDERER_GENERAL_TLS_ENABLED=true - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] working_dir: /opt/gopath/src/github.com/hyperledger/fabric command: orderer volumes: - ./system-genesis-block/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls:/var/hyperledger/orderer/tls ports: - 7050:7050 networks: - fabric_network
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer:2.5.0
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_network
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp
- CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:9443
- CORE_METRICS_PROVIDER=prometheus
- CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG={"peername":"peer0org1"}
- CORE_CHAINCODE_EXECUTETIMEOUT=300s
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
ports:
- 7051:7051
- 9443:9443
networks:
- fabric_network
peer0.org2.example.com:
container_name: peer0.org2.example.com
image: hyperledger/fabric-peer:2.5.0
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_network
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_ADDRESS=peer0.org2.example.com:9051
- CORE_PEER_LISTENADDRESS=0.0.0.0:9051
- CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:9052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp
- CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:9444
- CORE_METRICS_PROVIDER=prometheus
- CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG={"peername":"peer0org2"}
- CORE_CHAINCODE_EXECUTETIMEOUT=300s
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
ports:
- 9051:9051
- 9444:9444
networks:
- fabric_network
cli:
container_name: cli
image: hyperledger/fabric-tools:2.5.0
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- ./chaincode/:/opt/gopath/src/github.com/chaincode
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
networks:
- fabric_network
EOF ```
- Create a deployment script: ```bash cat > deploy-network.sh << EOF #!/bin/bash
# Create directories mkdir -p crypto-config channel-artifacts system-genesis-block chaincode
# Generate crypto material cryptogen generate --config=./crypto-config.yaml --output=./crypto-config
# Set FABRIC_CFG_PATH to the current directory export FABRIC_CFG_PATH=\${PWD}
# Generate genesis block configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block
# Generate channel transaction configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel1.tx -channelID channel1
# Generate anchor peer updates configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID channel1 -asOrg Org1MSP configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID channel1 -asOrg Org2MSP
# Start the network docker-compose up -d
# Wait for network to start sleep 5
# Create and join channel docker exec cli peer channel create -o orderer.example.com:7050 -c channel1 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channel1.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
# Join peer0.org1 to channel docker exec cli peer channel join -b channel1.block
# Join peer0.org2 to channel docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer channel join -b channel1.block
# Update anchor peers docker exec cli peer channel update -o orderer.example.com:7050 -c channel1 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/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
docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer channel update -o orderer.example.com:7050 -c channel1 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/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
echo "Network setup complete!" EOF
chmod +x deploy-network.sh ```
- Create a simple chaincode: ```bash mkdir -p chaincode/basic
cat > chaincode/basic/basic.go << EOF package main
import ( "encoding/json" "fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// SmartContract provides functions for managing assets type SmartContract struct { contractapi.Contract }
// Asset describes basic details of an asset type Asset struct { ID string `json:"id"` Color string `json:"color"` Size int `json:"size"` Owner string `json:"owner"` Value int `json:"value"` }
// InitLedger adds a base set of assets to the ledger func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error { assets := []Asset{ {ID: "asset1", Color: "blue", Size: 5, Owner: "Tom", Value: 100}, {ID: "asset2", Color: "red", Size: 10, Owner: "Jane", Value: 200}, {ID: "asset3", Color: "green", Size: 15, Owner: "Alex", Value: 300}, }
for _, asset := range assets {
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
err = ctx.GetStub().PutState(asset.ID, assetJSON)
if err != nil {
return fmt.Errorf("failed to put to world state: %v", err)
}
}
return nil
}
// CreateAsset issues a new asset to the world state with given details func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, value int) error { exists, err := s.AssetExists(ctx, id) if err != nil { return err } if exists { return fmt.Errorf("the asset %s already exists", id) }
asset := Asset{
ID: id,
Color: color,
Size: size,
Owner: owner,
Value: value,
}
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
// ReadAsset returns the asset stored in the world state with given id func (s SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (Asset, error) { assetJSON, err := ctx.GetStub().GetState(id) if err != nil { return nil, fmt.Errorf("failed to read from world state: %v", err) } if assetJSON == nil { return nil, fmt.Errorf("the asset %s does not exist", id) }
var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}
return &asset, nil
}
// AssetExists returns true when asset with given ID exists in world state func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) { assetJSON, err := ctx.GetStub().GetState(id) if err != nil { return false, fmt.Errorf("failed to read from world state: %v", err) }
return assetJSON != nil, nil
}
func main() { assetChaincode, err := contractapi.NewChaincode(&SmartContract{}) if err != nil { fmt.Printf("Error creating asset chaincode: %v\n", err) return }
if err := assetChaincode.Start(); err != nil {
fmt.Printf("Error starting asset chaincode: %v\\n", err)
}
} EOF
cat > chaincode/basic/go.mod << EOF module basic
go 1.16
require ( github.com/hyperledger/fabric-contract-api-go v1.1.1 ) EOF ```
- Create a chaincode deployment script: ```bash cat > deploy-chaincode.sh << EOF #!/bin/bash
# Package the chaincode docker exec cli peer lifecycle chaincode package basic.tar.gz --path /opt/gopath/src/github.com/chaincode/basic/ --lang golang --label basic_1.0
# Install on peer0.org1 docker exec cli peer lifecycle chaincode install basic.tar.gz
# Install on peer0.org2 docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer lifecycle chaincode install basic.tar.gz
# Get the package ID PACKAGE_ID=\$(docker exec cli peer lifecycle chaincode queryinstalled | grep basic_1.0 | awk '{print \$3}' | sed 's/,//') echo "Package ID: \$PACKAGE_ID"
# Approve for Org1 docker exec cli peer lifecycle chaincode approveformyorg -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 --channelID channel1 --name basic --version 1.0 --package-id \$PACKAGE_ID --sequence 1
# Approve for Org2 docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer lifecycle chaincode approveformyorg -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 --channelID channel1 --name basic --version 1.0 --package-id \$PACKAGE_ID --sequence 1
# Commit the chaincode definition docker exec cli peer lifecycle chaincode commit -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 --channelID channel1 --name basic --version 1.0 --sequence 1 --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
# Initialize the chaincode docker exec cli 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 channel1 -n basic --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 '{"function":"InitLedger","Args":[]}'
echo "Chaincode deployment complete!" EOF
chmod +x deploy-chaincode.sh ```
- Create a network teardown script: ```bash cat > teardown-network.sh << EOF #!/bin/bash
# Stop the network docker-compose down --volumes --remove-orphans
# Remove generated files rm -rf crypto-config channel-artifacts system-genesis-block
echo "Network teardown complete!" EOF
chmod +x teardown-network.sh ```
-
Deploy the network:
bash ./deploy-network.sh -
Deploy the chaincode:
bash ./deploy-chaincode.sh -
Test the chaincode: ```bash # Query an asset docker exec cli peer chaincode query -C channel1 -n basic -c '{"function":"ReadAsset","Args":["asset1"]}'
Create a new asset
docker exec cli 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 channel1 -n basic --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 '{"function":"CreateAsset","Args":["asset4", "yellow", "10", "Sam", "400"]}'
Query the new asset
docker exec cli peer chaincode query -C channel1 -n basic -c '{"function":"ReadAsset","Args":["asset4"]}' ```
Deliverable: A working Hyperledger Fabric network with two organizations, each with one peer, and a single orderer node. The network should have a channel with a deployed chaincode that can create and query assets.
Exercise 2: Adding a New Organization to an Existing Network
Objective: Add a third organization (Org3) to the network created in Exercise 1.
Tasks:
-
Create a directory for Org3:
bash mkdir -p ~/fabric-network/org3 cd ~/fabric-network/org3 -
Create a crypto-config.yaml file for Org3: ```bash cat > crypto-config.yaml << EOF PeerOrgs:
- Name: Org3 Domain: org3.example.com EnableNodeOUs: true Template: Count: 1 Users: Count: 1 EOF ```
-
Generate crypto material for Org3:
bash cryptogen generate --config=./crypto-config.yaml --output=./crypto-config -
Create a configtx.yaml file for Org3: ```bash cat > configtx.yaml << EOF Organizations:
- &Org3
Name: Org3MSP
ID: Org3MSP
MSPDir: crypto-config/peerOrganizations/org3.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org3MSP.admin', 'Org3MSP.peer', 'Org3MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org3MSP.admin', 'Org3MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org3MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org3MSP.peer')"
AnchorPeers:
- Host: peer0.org3.example.com Port: 11051 EOF ```
- &Org3
Name: Org3MSP
ID: Org3MSP
MSPDir: crypto-config/peerOrganizations/org3.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org3MSP.admin', 'Org3MSP.peer', 'Org3MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org3MSP.admin', 'Org3MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org3MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org3MSP.peer')"
AnchorPeers:
-
Generate the Org3 definition:
bash export FABRIC_CFG_PATH=${PWD} configtxgen -printOrg Org3MSP > org3.json -
Create a docker-compose file for Org3: ```bash cat > docker-compose-org3.yaml << EOF version: '3.7'
networks: fabric_network: external: true
services: peer0.org3.example.com: container_name: peer0.org3.example.com image: hyperledger/fabric-peer:2.5.0 environment: - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_network - FABRIC_LOGGING_SPEC=INFO - CORE_PEER_TLS_ENABLED=true - CORE_PEER_PROFILE_ENABLED=true - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt - CORE_PEER_ID=peer0.org3.example.com - CORE_PEER_ADDRESS=peer0.org3.example.com:11051 - CORE_PEER_LISTENADDRESS=0.0.0.0:11051 - CORE_PEER_CHAINCODEADDRESS=peer0.org3.example.com:11052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:11052 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org3.example.com:11051 - CORE_PEER_LOCALMSPID=Org3MSP - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:9445 - CORE_METRICS_PROVIDER=prometheus - CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG={"peername":"peer0org3"} - CORE_CHAINCODE_EXECUTETIMEOUT=300s volumes: - /var/run/docker.sock:/host/var/run/docker.sock - ./crypto-config/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/msp:/etc/hyperledger/fabric/msp - ./crypto-config/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls:/etc/hyperledger/fabric/tls working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: peer node start ports: - 11051:11051 - 9445:9445 networks: - fabric_network EOF ```
- Create a script to add Org3 to the channel: ```bash cat > add-org3.sh << EOF #!/bin/bash
cd ~/fabric-network
# Copy Org3 crypto material cp -r org3/crypto-config/peerOrganizations/org3.example.com crypto-config/peerOrganizations/
# Fetch the channel configuration docker exec cli peer channel fetch config config_block.pb -o orderer.example.com:7050 -c channel1 --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
# Copy the config block to the CLI container docker cp org3/org3.json cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/org3.json
# Update the channel configuration docker exec cli bash -c ' configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json
jq -s ".[0] * {\"channel_group\":{\"groups\":{\"Application\":{\"groups\":{\"Org3MSP\":.[1]}}}}}" config.json org3.json > modified_config.json
configtxlator proto_encode --input config.json --type common.Config --output config.pb configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_config.pb --output org3_update.pb
configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate | jq . > org3_update.json
echo "{\"payload\":{\"header\":{\"channel_header\":{\"channel_id\":\"channel1\", \"type\":2}},\"data\":{\"config_update\":\$(cat org3_update.json)}}}" | jq . > org3_update_in_envelope.json
configtxlator proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb '
# Sign the configuration update by Org1 docker exec cli peer channel signconfigtx -f org3_update_in_envelope.pb
# Sign the configuration update by Org2 docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer channel signconfigtx -f org3_update_in_envelope.pb
# Update the channel docker exec cli peer channel update -f org3_update_in_envelope.pb -c channel1 -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
# Start Org3 peer cd ~/fabric-network/org3 docker-compose -f docker-compose-org3.yaml up -d
# Join Org3 peer to the channel # First, fetch the latest block docker exec cli peer channel fetch 0 channel1.block -o orderer.example.com:7050 -c channel1 --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
# Copy the block to the Org3 peer docker cp cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel1.block . docker cp channel1.block peer0.org3.example.com:/opt/gopath/src/github.com/hyperledger/fabric/peer/
# Join Org3 peer to the channel docker exec -e CORE_PEER_LOCALMSPID=Org3MSP -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 peer0.org3.example.com peer channel join -b /opt/gopath/src/github.com/hyperledger/fabric/peer/channel1.block
# Install chaincode on Org3 peer cd ~/fabric-network docker cp cli:/opt/gopath/src/github.com/chaincode/basic org3/
docker exec -e CORE_PEER_LOCALMSPID=Org3MSP -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 peer0.org3.example.com peer lifecycle chaincode package basic.tar.gz --path /opt/gopath/src/github.com/hyperledger/fabric/peer/basic/ --lang golang --label basic_1.0
docker exec -e CORE_PEER_LOCALMSPID=Org3MSP -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 peer0.org3.example.com peer lifecycle chaincode install basic.tar.gz
# Get the package ID PACKAGE_ID=\$(docker exec cli peer lifecycle chaincode queryinstalled | grep basic_1.0 | awk '{print \$3}' | sed 's/,//')
# Approve chaincode for Org3 docker exec -e CORE_PEER_LOCALMSPID=Org3MSP -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 peer0.org3.example.com peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --tls --cafile /etc/hyperledger/fabric/tls/ca.crt --channelID channel1 --name basic --version 1.0 --package-id \$PACKAGE_ID --sequence 1
echo "Org3 has been added to the network!" EOF
chmod +x add-org3.sh ```
-
Run the script to add Org3:
bash ./add-org3.sh -
Test that Org3 can interact with the chaincode: ```bash # Query an asset from Org3 docker exec -e CORE_PEER_LOCALMSPID=Org3MSP -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 peer0.org3.example.com peer chaincode query -C channel1 -n basic -c '{"function":"ReadAsset","Args":["asset1"]}'
# Create a new asset from Org3 docker exec -e CORE_PEER_LOCALMSPID=Org3MSP -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 peer0.org3.example.com peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /etc/hyperledger/fabric/tls/ca.crt -C channel1 -n basic --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 '{"function":"CreateAsset","Args":["asset5", "purple", "15", "Mike", "500"]}' ```
Deliverable: An updated Hyperledger Fabric network with three organizations, each with one peer, and a single orderer node. The third organization should be able to participate in the channel and interact with the chaincode.
Exercise 3: Implementing Monitoring for a Fabric Network
Objective: Set up monitoring for the Hyperledger Fabric network using Prometheus and Grafana.
Tasks:
-
Create a directory for monitoring:
bash mkdir -p ~/fabric-network/monitoring cd ~/fabric-network/monitoring -
Create a Prometheus configuration file: ```bash cat > prometheus.yml << EOF global: scrape_interval: 15s evaluation_interval: 15s
scrape_configs: - job_name: 'fabric' static_configs: - targets: ['peer0.org1.example.com:9443', 'peer0.org2.example.com:9444', 'peer0.org3.example.com:9445'] EOF ```
- Create a Grafana dashboard configuration: ```bash mkdir -p grafana/dashboards
cat > grafana/dashboards/fabric.json << EOF { "annotations": { "list": [ { "builtIn": 1, "datasource": "-- Grafana --", "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "type": "dashboard" } ] }, "editable": true, "gnetId": null, "graphTooltip": 0, "id": 1, "links": [], "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", "fieldConfig": { "defaults": { "custom": {} }, "overrides": [] }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 }, "hiddenSeries": false, "id": 2, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "nullPointMode": "null", "options": { "alertThreshold": true }, "percentage": false, "pluginVersion": "7.2.0", "pointradius": 2, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(fabric_endorser_proposals_received[5m])", "interval": "", "legendFormat": "{{instance}}", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, "title": "Endorsement Rate", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", "fieldConfig": { "defaults": { "custom": {} }, "overrides": [] }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 }, "hiddenSeries": false, "id": 4, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "nullPointMode": "null", "options": { "alertThreshold": true }, "percentage": false, "pluginVersion": "7.2.0", "pointradius": 2, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "fabric_endorser_proposal_duration_seconds", "interval": "", "legendFormat": "{{instance}}", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, "title": "Endorsement Duration", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "s", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", "fieldConfig": { "defaults": { "custom": {} }, "overrides": [] }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 }, "hiddenSeries": false, "id": 6, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "nullPointMode": "null", "options": { "alertThreshold": true }, "percentage": false, "pluginVersion": "7.2.0", "pointradius": 2, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(fabric_ledger_blockchain_height[5m])", "interval": "", "legendFormat": "{{instance}}", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, "title": "Blockchain Growth Rate", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", "fieldConfig": { "defaults": { "custom": {} }, "overrides": [] }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 }, "hiddenSeries": false, "id": 8, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "nullPointMode": "null", "options": { "alertThreshold": true }, "percentage": false, "pluginVersion": "7.2.0", "pointradius": 2, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "process_resident_memory_bytes", "interval": "", "legendFormat": "{{instance}}", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, "title": "Memory Usage", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } } ], "refresh": "10s", "schemaVersion": 26, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { "from": "now-6h", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Hyperledger Fabric Metrics", "uid": "fabric", "version": 1 } EOF
cat > grafana/dashboards/dashboard.yml << EOF apiVersion: 1
providers: - name: 'Prometheus' orgId: 1 folder: '' type: file disableDeletion: false editable: true options: path: /etc/grafana/dashboards EOF
cat > grafana/datasources/prometheus.yml << EOF apiVersion: 1
datasources: - name: Prometheus type: prometheus access: proxy orgId: 1 url: http://prometheus:9090 isDefault: true editable: true EOF ```
- Create a Docker Compose file for monitoring: ```bash cat > docker-compose-monitoring.yaml << EOF version: '3.7'
networks: fabric_network: external: true
services: prometheus: image: prom/prometheus:v2.30.3 container_name: prometheus volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/usr/share/prometheus/console_libraries' - '--web.console.templates=/usr/share/prometheus/consoles' ports: - 9090:9090 networks: - fabric_network
grafana:
image: grafana/grafana:8.2.2
container_name: grafana
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/datasources:/etc/grafana/provisioning/datasources
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
ports:
- 3000:3000
networks:
- fabric_network
depends_on:
- prometheus
volumes: prometheus_data: grafana_data: EOF ```
-
Start the monitoring services:
bash docker-compose -f docker-compose-monitoring.yaml up -d -
Generate some load on the network: ```bash cd ~/fabric-network
# Create a script to generate load cat > generate-load.sh << EOF #!/bin/bash
for i in {1..20} do asset_id="load_asset_\$i" color="color_\$i" size=\$((i * 5)) owner="owner_\$i" value=\$((i * 100))
echo "Creating asset \$asset_id"
docker exec cli 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 channel1 -n basic --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 "{\"function\":\"CreateAsset\",\"Args\":[\"\$asset_id\", \"\$color\", \"\$size\", \"\$owner\", \"\$value\"]}"
sleep 2
done
for i in {1..20} do asset_id="load_asset_\$i"
echo "Reading asset \$asset_id"
docker exec cli peer chaincode query -C channel1 -n basic -c "{\"function\":\"ReadAsset\",\"Args\":[\"\$asset_id\"]}"
sleep 1
done EOF
chmod +x generate-load.sh
# Run the load generation script ./generate-load.sh ```
- Access the monitoring dashboards:
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (login with admin/admin)
Deliverable: A monitoring setup for the Hyperledger Fabric network using Prometheus and Grafana, with dashboards showing key metrics such as transaction throughput, endorsement time, and resource usage.
Assessment
Multiple Choice Questions
-
Which of the following is NOT a component of the Hyperledger Fabric network configuration? a) crypto-config.yaml b) configtx.yaml c) docker-compose.yaml d) chaincode.yaml
-
Which tool is used to generate the cryptographic material for a Hyperledger Fabric network? a) configtxgen b) cryptogen c) peer d) orderer
-
Which consensus mechanism is recommended for production Hyperledger Fabric networks? a) Solo b) Kafka c) Raft d) PBFT
-
What is the purpose of the "anchor peer" in a Hyperledger Fabric network? a) To endorse transactions b) To order transactions c) To enable cross-organization communication d) To store the ledger
-
Which of the following is NOT a valid Hyperledger Fabric peer type? a) Endorsing peer b) Committing peer c) Ordering peer d) Anchor peer
-
What is the purpose of the "channel" in Hyperledger Fabric? a) To provide a communication path between peers b) To isolate transactions and data between a specific set of participants c) To connect to external systems d) To manage the consensus mechanism
-
Which component is responsible for maintaining the order of transactions in Hyperledger Fabric? a) Peer b) Orderer c) CA d) Client
-
What is the purpose of the Membership Service Provider (MSP) in Hyperledger Fabric? a) To generate transactions b) To validate transactions c) To define the organizations and their members in the network d) To store the ledger
-
Which of the following is NOT a step in the Hyperledger Fabric chaincode lifecycle? a) Package b) Install c) Approve d) Execute
-
What is the purpose of the "private data collection" in Hyperledger Fabric? a) To store sensitive data that only specific organizations can access b) To improve transaction performance c) To implement access control d) To enable cross-channel queries
Short Answer Questions
-
Explain the difference between the "Solo" and "Raft" ordering services in Hyperledger Fabric and when you would use each.
-
Describe the process of adding a new organization to an existing Hyperledger Fabric network.
-
Explain how to implement high availability in a Hyperledger Fabric network.
-
Discuss the security considerations when deploying a Hyperledger Fabric network in production.
-
Explain how to monitor a Hyperledger Fabric network and what key metrics should be tracked.
Answers to Multiple Choice Questions
- d) chaincode.yaml
- b) cryptogen
- c) Raft
- c) To enable cross-organization communication
- c) Ordering peer
- b) To isolate transactions and data between a specific set of participants
- b) Orderer
- c) To define the organizations and their members in the network
- d) Execute
- a) To store sensitive data that only specific organizations can access