Getting Started

Note

These instructions have been verified to work against the “alpha” tagged docker images and the pre-compiled binaries within the supplied tarball file. If you run these commands with images or tools from the current master branch, you will see configuration and panic errors.

The getting started scenario provisions a sample Fabric network consisting of two organizations, each maintaining two peers, and a “solo” ordering service.

Prior to launching the network, we will demonstrate the usage of two fundamental tools:

  • cryptogen - generates the x509 certificates used to identify and authenticate the various components in the network.
  • configtxgen - generates the requisite configuration artifacts for orderer bootstrap and channel creation.

In no time we’ll have a fully-functioning transactional network with a shared ledger and digital signature verification. Let’s get going...

Prerequisites and setup

Curl the artifacts and binaries

Note

If you are running on Windows you will want to make use of your Git Bash shell for the upcoming terminal commands.

  • Download the cURL tool if not already installed.
  • Determine a location on your machine where you want to place the artifacts and binaries.
mkdir fabric-sample
cd fabric-sample

Next, execute the following command:

curl -L https://logs.hyperledger.org/sandbox/vex-yul-hyp-jenkins-2/fabric-binaries/release.tar.gz -o release.tar.gz 2> /dev/null;  tar -xvf release.tar.gz

This command pulls and extracts all of the necessary artifacts to set up your network and places them into a folder titled release. It also retrieves the two binaries - cryptogen and configtxgen - which are briefly described at the top of this page.

Pulling the docker images

Change directories into release. You should see the following:

jdoe-mbp:release johndoe$ ls
darwin-amd64  linux-amd64     linux-ppc64le   linux-s390x     samples         templates       windows-amd64

You will notice that there are platform-specific folders. Each folder contains the corresponding binaries for that platform, along with a script that we will use to download the Fabric images. Right now we’re only interested in the script. Navigate into the folder matching your machine’s OS and then into install. For example, if you were running on OSX:

cd darwin-amd64/install

Now run the shell script to download the docker images. This will take a few minutes so remember that patience is a virtue:

./get-docker-images.sh

Execute a docker images command to view your images. Assuming you had no images on your machine prior to running the script, you should see the following:

jdoe-mbp:install johndoe$ docker images
REPOSITORY                     TAG                  IMAGE ID            CREATED             SIZE
hyperledger/fabric-couchdb     x86_64-1.0.0-alpha   f3ce31e25872        5 weeks ago         1.51 GB
hyperledger/fabric-kafka       x86_64-1.0.0-alpha   589dad0b93fc        5 weeks ago         1.3 GB
hyperledger/fabric-zookeeper   x86_64-1.0.0-alpha   9a51f5be29c1        5 weeks ago         1.31 GB
hyperledger/fabric-orderer     x86_64-1.0.0-alpha   5685fd77ab7c        5 weeks ago         182 MB
hyperledger/fabric-peer        x86_64-1.0.0-alpha   784c5d41ac1d        5 weeks ago         184 MB
hyperledger/fabric-javaenv     x86_64-1.0.0-alpha   a08f85d8f0a9        5 weeks ago         1.42 GB
hyperledger/fabric-ccenv       x86_64-1.0.0-alpha   91792014b61f        5 weeks ago         1.29 GB

Look at the names for each image; these are the components that will ultimately comprise our Fabric network.

Using the cryptogen tool

First, let’s set the environment variable for our platform. This command will detect your OS and use the appropriate binaries for the subsequent steps:

# for power or z
os_arch=$(echo "$(uname -s)-$(uname -m)" | awk '{print tolower($0)}')
# for linux, osx or windows
os_arch=$(echo "$(uname -s)-amd64" | awk '{print tolower($0)}')

Check to make sure the $os_arch variable is properly set:

echo $os_arch

Ok now for the fun stuff - generating the crypto material. Pop into the e2e folder:

cd ../../samples/e2e

We are going to pass in the crypto-config.yaml file as an argument for the upcoming command. This file contains the definition/structure of our network and lists the components that we are generating certs for. If you open the file you will see that our network will consist of - one OrdererOrg and two PeerOrgs each maintaining two peers. You can easily modify this file to generate certs for a more elaborate network, however we will leave the sample configuration for the sake of simplicity. Got it? Let’s run the tool now:

# this syntax requires you to be in the e2e directory
# notice that we will pass in the $os_arch variable in order to use the correct binary
./../../$os_arch/bin/cryptogen generate --config=./crypto-config.yaml

If the tool runs successfully, you will see the various KeyStores churn out in your terminal. The certs are then parked into a crypto-config folder that is generated when you run the tool.

Using the configtxgen tool

We will now use our second tool - configtxgen - to create our ordering service genesis block and a channel configuration artifact. As the abbreviation suggests, this tool is a configuration transaction generator. More info on the configtxgen tool can be found here However, at this stage (and for the sake of brevity) we will simply make use of the tool to generate our two artifacts.

Note

The configtx.yaml file contains the definitions for our sample network and presents the topology of the network components - three members (OrdererOrg, Org0 & Org1), and the anchor peers for each PeerOrg (peer0.org1 and peer0.org2). You will notice that it is structured similarly to the crypto-config.yaml that we just passed to generate our certs. The main difference is that we can now point to the locations of those certs. You’ll recall that in the previous step we created a new folder called crypto-config and parked the certs there. The configtx.yaml points to that directory and allows us to bundle the root certs for the Orgs constituting our network into the genesis block. This is a critical concept. Now any network entity communicating with the ordering service can have its digital signature verified.

Generate the orderer genesis block

From your e2e folder first execute the following:

# this command will not return a response
export FABRIC_CFG_PATH=$PWD

Then use the tool:

# notice at the top of configtx.yaml we define the profile as TwoOrgs
./../../$os_arch/bin/configtxgen -profile TwoOrgs -outputBlock orderer.block
# for example, if you are running OSX then the binary from darwin-amd64 would have been used

The orderer genesis block - orderer.block - is output into the e2e directory.

Generate the channel configuration artifact

When we call the createChannel API, and send the proposal to the ordering service, we need to pass a channel configuration artifact along with this call. We will once again leverage the configtx.yaml and use the same profile definition - TwoOrgs - that we used to create the orderer genesis block. In other words, this channel we are creating is a network-wide channel. All Orgs are included.

Still in your e2e folder execute the following:

# replace the <CHANNEL_NAME> parm with a name of your choosing
./../../$os_arch/bin/configtxgen -profile TwoOrgs -outputCreateChannelTx channel.tx -channelID <CHANNEL_NAME>

The channel configuration artifact - channel.tx - is output into the e2e directory.

Start the network (No TLS)

We will leverage a docker-compose script to spin up our network. The docker-compose points to the images that we have already downloaded, and bootstraps the orderer with our previously generated orderer.block. Before launching the network, open the docker-compose file and comment out the script.sh in the CLI container. Your docker-compose should look like this:

working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
#command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; '
volumes:

If left uncommented, the script will exercise all of the CLI commands when the network is started. However, we want to go through the commands manually in order to expose the syntax and functionality of each call.

Start your network:

# this sets our OS
export ARCH_TAG=$(uname -m)
# this starts the network in "detached" mode; enter the appropriate value for the CHANNEL_NAME parm
CHANNEL_NAME=<CHANNEL_NAME> docker-compose -f docker-compose-no-tls.yaml up -d

If you’d like to see the realtime logs for the components, then remove the -d flag:

CHANNEL_NAME=<CHANNEL_NAME> docker-compose -f docker-compose-no-tls.yaml up

Now open another terminal and navigate back to release/samples/e2e.

Create & Join Channel

Go into the cli container:

docker exec -it cli bash

You should see the following:

root@bb5e894d9668:/opt/gopath/src/github.com/hyperledger/fabric/peer#

Create Channel

Recall that we used the configtxgen tool to generate a channel configuration artifact - channel.tx. We are going to pass in this artifact to the orderer as part of the create channel request.

Note

For this to work, we must pass in the path of the orderer’s local MSP in order to sign this create channel call. Recall that we bootstrapped the orderer with the root certificates (ca certs) for all the members of our network. As a result, the orderer can verify the digital signature of the submitting client. This call will also work if we pass in the local MSP for Org0 or Org1.

The following environment variables for the orderer must be passed:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com
CORE_PEER_LOCALMSPID="OrdererMSP"
CHANNEL_NAME=<YOUR_CHANNEL_NAME>

The syntax is as follows:

peer channel create -o <ORDERER_NAME>:7050 -c <CHANNEL_NAME> -f channel.tx

So our command in its entirety would be:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com CORE_PEER_LOCALMSPID="OrdererMSP" peer channel create -o orderer.example.com:7050 -c mychannel -f channel.tx

This command returns a genesis block - mychannel.block - which we will use to join the channel.

Environment variables

You can see the syntax for all commands by inspecting the script.sh file in the scripts directory.

For the following cli commands against PEER0 to work, we need to set the values for the four global environment variables given below. Please make sure to override the values accordingly when calling commands against other peers and the orderer.

# Environment variables for PEER0
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org0MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/cacerts/org1.example.com-cert.pem

These environment variables for each peer are defined in the supplied docker-compose file.

Note

In these examples, we are using the default mychannel for all CHANNEL_NAME arguments. If you elect to create a uniquely named channel, be conscious to modify your strings accordingly.

Join channel

Now let’s join PEER0 to the channel by passing in the genesis block that was just returned to us upon the create channel command.

The syntax is as follows:

peer channel join -b <CHANNEL_NAME>.block

Remember, we need to pass the four global variables. So this command in its entirety would be:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com CORE_PEER_ADDRESS=peer0.org1.example.com:7051 CORE_PEER_LOCALMSPID="Org0MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/cacerts/org1.example.com-cert.pem peer channel join -b mychannel.block

Install

Now we will install the chaincode source onto the peer’s filesystem. The syntax is as follows:

peer chaincode install -n <CHAINCODE_NAME> -v <CHAINCODE_VERSION> -p <CHAINCODE_PATH>

This command in its entirety would be:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com CORE_PEER_ADDRESS=peer0.org1.example.com:7051 CORE_PEER_LOCALMSPID="Org0MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/cacerts/org1.example.com-cert.pem peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 >&log.txt

Instantiate

Now we start the chaincode container and initialize our key value pairs. The syntax for instantiate is as follows:

peer chaincode instantiate -o <ORDERER_NAME>:7050 -C <CHANNEL_NAME> -n <CHAINCODE_NAME> -v <VERSION> -c '{"Args":["init","key","value"]}' -P "OR/AND (CHAINCODE_POLICY)"

Take note of the -P argument. This is our policy where we specify the required level of endorsement for a transaction against this chaincode to be validated. In the command below you’ll notice that we specify our policy as -P "OR ('Org0MSP.member','Org1MSP.member')". This means that we need “endorsement” from a peer belonging to Org0 OR Org1 (i.e. only one endorsement). If we changed the syntax to AND then we would need two endorsements.

This command in its entirety would be:

# we instantiate with the following key value pairs: "a","100","b","200"
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com CORE_PEER_ADDRESS=peer0.org1.example.com:7051 CORE_PEER_LOCALMSPID="Org0MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/cacerts/org1.example.com-cert.pem peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org0MSP.member','Org1MSP.member')"

Note

The above command will only start a single chaincode container. If you want to interact with different peers, you must first install the source code onto that peer’s filesystem. You can then send an invoke or query to the peer. You needn’t instantiate twice, this command will propagate to the entire channel.

Query

Lets query for the value of “a” to make sure the chaincode was properly instantiated and the state DB was populated. The syntax for query is as follows:

peer chaincode query -C <CHANNEL_NAME> -n <CHAINCODE_NAME> -c '{"Args":["query","key"]}'

This command in its entirety would be:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com CORE_PEER_ADDRESS=peer0.org1.example.com:7051 CORE_PEER_LOCALMSPID="Org0MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/cacerts/org1.example.com-cert.pem peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'

Invoke

Lastly we will move “10” from “a” to “b”. This transaction will cut a new block and update the state DB. The syntax for invoke is as follows:

peer chaincode invoke -o <ORDERER_NAME>:7050 -C <CHANNEL_NAME> -n <CHAINCODE_NAME> -c '{"Args":["invoke","key","key","value"]}'

This command in its entirety would be:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com CORE_PEER_ADDRESS=peer0.org1.example.com:7051 CORE_PEER_LOCALMSPID="Org0MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/cacerts/org1.example.com-cert.pem peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'

Query

Lets confirm that our previous invocation executed properly. We initialized the key “a” with a value of “100”. Therefore, removing “10” should return a value of “90” when we query “a”. The syntax for query is outlined above.

This query command in its entirety would be:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com CORE_PEER_ADDRESS=peer0.org1.example.com:7051 CORE_PEER_LOCALMSPID="Org0MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/cacerts/org1.example.com-cert.pem peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'

Start the network (TLS enabled)

Use the script.sh to see the exact syntax for TLS-enabled CLI commands.

Before starting, we need to modify our docker-compose file to reflect the appropriate private keys for the orderer and peers.

From your e2e directory execute the following:

PRIV_KEY=$(ls crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/keystore/) sed -i "s/ORDERER_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml
PRIV_KEY=$(ls crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/keystore/) sed -i "s/PEER0_ORG1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml
PRIV_KEY=$(ls crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/keystore/) sed -i "s/PEER0_ORG2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml
PRIV_KEY=$(ls crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/keystore/) sed -i "s/PEER1_ORG1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml
PRIV_KEY=$(ls crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/keystore/) sed -i "s/PEER1_ORG2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml

These commands will modify the TLS_KEY_FILE variables in your docker-compose. Once you have executed all five commands, spin the network back up and begin by creating your channel.

Scripts

We exposed the verbosity of the commands in order to provide some edification on the underlying flow and the appropriate syntax. Entering the commands manually through the CLI is quite onerous, therefore we provide a few scripts to do the entirety of the heavy lifting.

Clean up

Let’s clean things up before continuing. This command will remove both the active and exited containers:

docker rm -f $(docker ps -aq)

Next, execute a docker images command in your terminal to view the chaincode images. They will look similar to the following:

REPOSITORY                     TAG                  IMAGE ID            CREATED             SIZE
dev-peer3-mycc-1.0             latest               13f6c8b042c6        5 minutes ago       176 MB
dev-peer0-mycc-1.0             latest               e27456b2bd92        5 minutes ago       176 MB
dev-peer2-mycc-1.0             latest               111098a7c98c        5 minutes ago       176 MB

Remove these images:

docker rmi <IMAGE ID> <IMAGE ID> <IMAGE ID>

For example:

docker rmi -f 13f e27 111

Lastly, remove the crypto-config` folder and the two artifacts - channel.tx & orderer.block.

# from the e2e directory
rm -rf channel.tx orderer.block crypto-config

All in one

This script will do it all for you! From the e2e directory:

./network_setup.sh up <channel_name>

Note

If you choose not to pass a channel_name value, then the default mychannel will be used.

Now shut down your network and remove the chaincode images and artifacts:

./network_setup.sh down

If you want to restart:

./network_setup.sh restart

APIs only

The other option is to manually generate your crypto material and configuration artifacts, and then use the embedded script.sh in the docker-compose files to drive your network. Make sure this script is not commented out in your CLI container.

When the scripts complete successfully, you should see the following message in your terminal:

===================== Query on PEER3 on channel 'mychannel' is successful =====================

===================== All GOOD, End-2-End execution completed =====================

Using CouchDB

The state database can be switched from the default (goleveldb) to CouchDB. The same chaincode functions are available with CouchDB, however, there is the added ability to perform rich and complex queries against the state database data content contingent upon the chaincode data being modeled as JSON.

To use CouchDB instead of the default database (goleveldb), follow the same procedure in the Prerequisites section, and additionally perform the following two steps to enable the CouchDB containers and associate each peer container with a CouchDB container:

  • Make the CouchDB image.
# make sure you are in the fabric directory
make couchdb
  • Open the release/samples/e2e/docker-compose.yaml and un-comment all commented statements relating to CouchDB containers and peer container use of CouchDB. These instructions are are also outlined in the same docker-compose.yaml file. Search the file for ‘couchdb’ (case insensitive) references.

chaincode_example02 should now work using CouchDB underneath.

Note

If you choose to implement mapping of the fabric-couchdb container port to a host port, please make sure you are aware of the security implications. Mapping of the port in a development environment allows the visualization of the database via the CouchDB web interface (Fauxton). Production environments would likely refrain from implementing port mapping in order to restrict outside access to the CouchDB containers.

You can use chaincode_example02 chaincode against the CouchDB state database using the steps outlined above, however in order to exercise the query capabilities you will need to use a chaincode that has data modeled as JSON, (e.g. marbles02). You can locate the marbles02 chaincode in the release/samples/chaincodes/go directory.

Install, instantiate, invoke, and query marbles02 chaincode by following the same general steps outlined above for chaincode_example02 in the Manually execute transactions section. After the Join channel step, use the following commands to interact with the marbles02 chaincode:

  • Install and instantiate the chaincode on PEER0:
peer chaincode install -o orderer0:7050 -n marbles -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/marbles02
peer chaincode instantiate -o orderer0:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/orderer/localMspConfig/cacerts/ordererOrg0.pem -C mychannel -n marbles -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/marbles02 -c '{"Args":["init"]}' -P "OR ('Org0MSP.member','Org1MSP.member')"
  • Create some marbles and move them around:
peer chaincode invoke -o orderer0:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/orderer/localMspConfig/cacerts/ordererOrg0.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}'
peer chaincode invoke -o orderer0:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/orderer/localMspConfig/cacerts/ordererOrg0.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}'
peer chaincode invoke -o orderer0:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/orderer/localMspConfig/cacerts/ordererOrg0.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}'
peer chaincode invoke -o orderer0:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/orderer/localMspConfig/cacerts/ordererOrg0.pem -C mychannel -n marbles -c '{"Args":["transferMarble","marble2","jerry"]}'
peer chaincode invoke -o orderer0:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/orderer/localMspConfig/cacerts/ordererOrg0.pem -C mychannel -n marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}'
peer chaincode invoke -o orderer0:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/orderer/localMspConfig/cacerts/ordererOrg0.pem -C mychannel -n marbles -c '{"Args":["delete","marble1"]}'
  • If you chose to activate port mapping, you can now view the state database through the CouchDB web interface (Fauxton) by opening a browser and navigating to one of the two URLs below.

    For containers running in a vagrant environment:

    http://localhost:15984/_utils

    For non-vagrant environment, use the port address that was mapped in CouchDB container specification:

    http://localhost:5984/_utils

    You should see a database named mychannel and the documents inside it.

  • You can run regular queries from the cli (e.g. reading marble2):

peer chaincode query -C mychannel -n marbles -c '{"Args":["readMarble","marble2"]}'

You should see the details of marble2:

Query Result: {"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}

Retrieve the history of marble1:

peer chaincode query -C mychannel -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'

You should see the transactions on marble1:

Query Result: [{"TxId":"1c3d3caf124c89f91a4c0f353723ac736c58155325f02890adebaa15e16e6464", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}},{"TxId":"755d55c281889eaeebf405586f9e25d71d36eb3d35420af833a20a2f53a3eefd", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"jerry"}},{"TxId":"819451032d813dde6247f85e56a89262555e04f14788ee33e28b232eef36d98f", "Value":}]

You can also perform rich queries on the data content, such as querying marble fields by owner jerry:

peer chaincode query -C mychannel -n marbles -c '{"Args":["queryMarblesByOwner","jerry"]}'

The output should display the two marbles owned by jerry:

Query Result: [{"Key":"marble2", "Record":{"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}},{"Key":"marble3", "Record":{"color":"blue","docType":"marble","name":"marble3","owner":"jerry","size":70}}]

Query by field owner where the value is jerry:

peer chaincode query -C mychannel -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"jerry\"}}"]}'

The output should display:

Query Result: [{"Key":"marble2", "Record":{"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}},{"Key":"marble3", "Record":{"color":"blue","docType":"marble","name":"marble3","owner":"jerry","size":70}}]

A Note on Data Persistence

If data persistence is desired on the peer container or the CouchDB container, one option is to mount a directory in the docker-host into a relevant directory in the container. For example, you may add the following two lines in the peer container specification in the docker-compose.yaml file:

volumes:
 - /var/hyperledger/peer0:/var/hyperledger/production

For the CouchDB container, you may add the following two lines in the CouchDB container specification:

volumes:
 - /var/hyperledger/couchdb0:/opt/couchdb/data

Troubleshooting

  • Ensure you clear the file system after each run.
  • If you see docker errors, remove your containers and start again.
docker rm -f $(docker ps -aq)
  • If you elect to run the “All in one” option, be sure you have deleted your crypto directory and the two artifacts. This can be achieved with the following command:
./network_setup.sh down
  • If you see the below error:
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)

You likely have chaincode images (e.g. dev-peer0-mycc-1.0 or dev-peer1-mycc-1.0) from prior runs. Remove them and try again.

docker rmi -f $(docker images | grep peer[0-9]-peer[0-9] | awk '{print $3}')
  • If you see connectivity or communication errors, try restarting your Docker process.
  • If you see something similar to the following:
Error connecting: rpc error: code = 14 desc = grpc: RPC failed fast due to transport failure
Error: rpc error: code = 14 desc = grpc: RPC failed fast due to transport failure

Make sure you are using the supplied binaries in the tarball file, and running your backend against “alpha” images.

If you see the below error:

[configtx/tool/localconfig] Load -> CRIT 002 Error reading configuration: Unsupported Config Type ""
panic: Error reading configuration: Unsupported Config Type ""

Then you have an environment variable - ORDERER_CFG_PATH that is no longer in use. You can manually change this value in the scripts, or re-download the tarball file.

  • If you continue to see errors, share your logs on the # fabric-questions

channel on Hyperledger Rocket Chat.