Ledger Snapshot in Hyperledger Fabric v2.3

KC Tam
7 min readJan 12, 2021


Ledger snapshot is one of the two features introduced in Fabric v2.3, which was released November last year. The snapshot gives us an alternative way to join new peers into a fabric network. In this article we will give highlights on the ledger snapshot, and walk through a demonstration on how things work.


For those who are familiarized with the process of adding new peers in a running fabric network, either in existing peer organization or in a new organization, we use the peer channel join with the channel genesis block file, and the new peer will then obtain the whole ledger from other peers in the channel. After going through all the transactions in the block, the world state gets updated. It would take time and effort before the full ledger is ready for use.

Here is a quick summary on how things work.

Join new peer with channel genesis block (prior to v2.3)

In Hyperledger Fabric v2.3 there is another way. Instead of beginning at a channel genesis block, now we can take ledger snapshot on a given block of a running fabric network. This snapshot provides all the required information such that it is the starting point for newly added peers in the network. New blocks will be committed in the new peer just as those existing peers.

Join new peer by snapshot (v2.3)

More detail about ledger snapshot can be seen in the official documentation.

Demonstration Overview

Our demonstration is to use ledger snapshot from a peer of a live fabric network to join a new peer. After that we will show the peer works normally, and make some observations on this new peer.

We are using Test Network to bring up a two-peer-org fabric network with one peer in each organization. We use -ca option as we need the organization CA to generate crypto material for the new peer. Then we deploy the simple asset chaincode (SACC) in this network and check everything works fine.

Then we start working on the new peer, peer1.org1.example.com. I have another article about adding a new peer on Test Network, and you can refer to it for more detail. In this article I just put the minimum information about how to add peer1 to org1. We will bring up the peer1.org1.example.com container.

Now we start the process of joining peer1 to mychannel through ledger snapshot. We will show the whole process and make observations when we work on this new peer by installing SACC to this peer. We will show the chaincode invoke and query, and finally fetch blocks and see what it happens.


Step 1: Bring Up Test Network

We first bring up the Test Network with -ca option. We also create mychannel and let both peers join the channel.

Note: I have included the required environment variables such that the peer command can be issued directly. You can refer here for more detail. My variables point to peer0.org1.example.com with Org1MSP details.

cd test-network
./network.sh up createChannel -ca

When we inspect the ledger, the blockchain height is 3.

Here are the details in each block after mychannel is created.

Step 2: Deploy SACC and Invoking Chaincode Function

We deploy SACC for testing.

./network.sh deployCC -ccn mycc -ccp ../chaincode/sacc -ccl go

After the chaincode deployment, we inspect the ledger and now the blockchain height is 6.

Here are the details in each block after SACC is deployed.

We then invoke the chaincode function set in SACC, which is to write an asset key/value to the ledger. Upon success, we will see the blockchain height is increased (now height 7).

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C mychannel -n mycc --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 '{"Args":["set","name","Peter"]}'

And we can query the asset.

Step 3: Bring Up New Peer

We follow the same process of bringing up peer1.org1.example.com. Details can be found here.

Bring up the crypto material for peer1.org1.example.com. The material is kept in organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/

export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/fabric-ca-client register --caname ca-org1 --id.name peer1 --id.secret peer1pw --id.type peer --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pemmkdir -p organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.comfabric-ca-client enroll -u https://peer1:peer1pw@localhost:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp --csr.hosts peer1.org1.example.com --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pemcp ${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp/config.yamlfabric-ca-client enroll -u https://peer1:peer1pw@localhost:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls --enrollment.profile tls --csr.hosts peer1.org1.example.com --csr.hosts localhost --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pemcp ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crtcp ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/signcerts/* ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.crtcp ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/keystore/* ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.key

And we prepare the docker/docker-compose-peer1org1.yaml for peer1.org1.example.com.

Now we can bring up the container

docker-compose -f docker/docker-compose-peer1org1.yaml up -d

After peer1.org1.example.com is running, we can check that at this moment peer1.org1.example.com has not joined mychannel yet.

Note: Our environment variable targets peer0.org1.example.com. To target it to peer1.org1.example.com, we include CORE_PEER_ADDRESS=localhost:8051 to our peer command.

# peer0.org1
peer channel list
# peer1.org1
CORE_PEER_ADDRESS=localhost:8051 peer channel list

Step 4: Join New Peer with Ledger Snapshot

We first take a snapshot in peer0.org1.example.com. Note here we specify -b 0, which means the snapshot is taken immediately after this command. You can schedule a snapshot on a future block. See documentation for more detail.

peer snapshot submitrequest -c mychannel -b 0 --peerAddress localhost:7051 --tlsRootCertFile ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

The result is placed in /var/hyperledger/production/snapshots/completed/mychannel/ of peer0.org1.example.com. We see directory 6/, which corresponds the block we have taken snapshot (block #6 as the blockchain height is 7).

Content of a snapshot

This directory is the ledger snapshot. We copy this directory to peer1.org1.example.com (or if you are using volume, you can map it correctly).

docker cp peer0.org1.example.com:/var/hyperledger/production/snapshots/completed/mychannel/6/ snapshotdocker cp snapshot/ peer1.org1.example.com:/opt/gopath/src/github.com/hyperledger/fabric/peer

Now we can join peer1.org1.example.com with this snapshot.

CORE_PEER_ADDRESS=localhost:8051 peer channel joinbysnapshot --snapshotpath /opt/gopath/src/github.com/hyperledger/fabric/peer/snapshot/

Now we can check if peer1.org1.example.com already joined mychannel, and check ledger information.

CORE_PEER_ADDRESS=localhost:8051 peer channel listCORE_PEER_ADDRESS=localhost:8051 peer channel getinfo -c mychannel

The blockchain information is identical to peer0.org1.example.com (see step 2). Besides, it also provides bootstrapping snapshot information.

Now peer1.org1.example.com is part of mychannel. We will start testing this peer.

Step 5: Testing Chaincode in New Peer

We first install the chaincode package to peer1.org1.example.com. This brings up the chaincode container for peer1.org1.example.com to handle chaincode operation.

CORE_PEER_ADDRESS=localhost:8051 peer lifecycle chaincode install mycc.tar.gz

After installation, we first query the chaincode.

CORE_PEER_ADDRESS=localhost:8051 peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'

The state is correct.

Now we invoke chaincode function, with peer1.org1.example.com as endorser for org1.

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C mychannel -n mycc --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.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 '{"Args":["set","name","Mary"]}'

The newly added peer1.org1.example.com (localhost:8051) can endorse our transaction proposal. Everything is working fine.

Step 6: Fetching Blocks

As we know, peer1.org1.example.com does not have those blocks before the snapshot. Here we can see the result.

Fetching block prior to snapshot (say #3)

In fact even the block #6 cannot be fetched.

And block #7, which is the block keeping transaction after peer1.org1.example.com came alive, is available.

Therefore, in peer1.org1.example.com, we can only fetch the blocks after the snapshot.

Step 7: Clean Up

To tear down the network

./network.sh down

And don’t forget to remove the volume of peer1.org1.example.com, which is not removed by the script.

docker volume prune


We have seen the new feature ledger snapshot in Fabric v2.3, and see how we can use the snapshot to bring up new peers joining a fabric network. Note the limitation shown in the documentation and see whether snapshot is something you can consider in future.