From 1dae950243a993b167f394a0eace0136aeee8edc Mon Sep 17 00:00:00 2001 From: ratnakar Date: Fri, 21 Apr 2017 17:08:54 -0400 Subject: [PATCH] [FAB-3322] Haskfest DC scripts for runing binaries This Includes the following artifacts * cryptogen config template to generate the certtificate material * configtx.yaml to generate the orderer block and channel configuration transaction * docker-compose files - A template file that is used to generate the docker-compose with TLS enabled (cryptogen tool generates the privatekey file name which includes hash value, hence this template) - A docker-compose file with TLS disabled * An All-In-One script to run the End-to-End flow * A shell script to run the peer commands from CLI container * Add the README * Update README, update network_setup.sh Change-Id: I09198c46923f64c0c5a5e0de702822267634a30c Signed-off-by: ratnakar Signed-off-by: Nick Gaski --- examples/dchackfest/samples/e2e/README.rst | 689 ++++++++++++++++++ .../chaincode_example02.go | 199 +++++ .../go/marbles02/marbles_chaincode.go | 627 ++++++++++++++++ examples/dchackfest/samples/e2e/configtx.yaml | 173 +++++ .../dchackfest/samples/e2e/crypto-config.yaml | 76 ++ .../samples/e2e/docker-compose-no-tls.yaml | 128 ++++ .../samples/e2e/docker-compose-template.yaml | 208 ++++++ .../samples/e2e/docker-compose.yaml | 208 ++++++ .../dchackfest/samples/e2e/network_setup.sh | 135 ++++ .../e2e/peer-base/peer-base-no-tls.yaml | 17 + .../samples/e2e/peer-base/peer-base.yaml | 22 + .../dchackfest/samples/e2e/scripts/script.sh | 209 ++++++ 12 files changed, 2691 insertions(+) create mode 100644 examples/dchackfest/samples/e2e/README.rst create mode 100644 examples/dchackfest/samples/e2e/chaincodes/go/chaincode_example02/chaincode_example02.go create mode 100644 examples/dchackfest/samples/e2e/chaincodes/go/marbles02/marbles_chaincode.go create mode 100644 examples/dchackfest/samples/e2e/configtx.yaml create mode 100644 examples/dchackfest/samples/e2e/crypto-config.yaml create mode 100644 examples/dchackfest/samples/e2e/docker-compose-no-tls.yaml create mode 100644 examples/dchackfest/samples/e2e/docker-compose-template.yaml create mode 100644 examples/dchackfest/samples/e2e/docker-compose.yaml create mode 100755 examples/dchackfest/samples/e2e/network_setup.sh create mode 100644 examples/dchackfest/samples/e2e/peer-base/peer-base-no-tls.yaml create mode 100644 examples/dchackfest/samples/e2e/peer-base/peer-base.yaml create mode 100755 examples/dchackfest/samples/e2e/scripts/script.sh diff --git a/examples/dchackfest/samples/e2e/README.rst b/examples/dchackfest/samples/e2e/README.rst new file mode 100644 index 00000000000..82e3cbbed6a --- /dev/null +++ b/examples/dchackfest/samples/e2e/README.rst @@ -0,0 +1,689 @@ +Getting Started +=============== + +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 +----------------------- + +- `Docker `__ - v1.12 or higher +- `Docker Compose `__ - v1.8 or higher +- `Docker Toolbox `__ - Windows users only +- `Go `__ - 1.7 or higher +- `Git Bash `__ - Windows users only; provides a better alternative to the Windows command prompt + +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. + +.. code:: bash + + mkdir -p /dchackfest + cd /dchackfest + +Next, execute the following command: + +.. code:: bash + + curl -L https://logs.hyperledger.org/sandbox/vex-yul-hyp-jenkins-2/fabric-verify-x86_64_1/4/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: + +.. code:: bash + + 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: + +.. code:: bash + + 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: + +.. code:: bash + + ./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: + +.. code:: bash + + 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, lets set the environment variable for our platform. This command +will detect your OS and use the appropriate binaries for the subsequent steps: + +.. code:: bash + + # 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)}') + +Ok now for the fun stuff - generating the crypto material. Pop into the ``e2e`` folder: + +.. code:: bash + + 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: + +.. code:: bash + + # 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 and peer2). 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: + +.. code:: bash + + # this command will not return a response + export ORDERER_CFG_PATH=$PWD + +Then use the tool: + +.. code:: bash + + # 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: + +.. code:: bash + + + # replace the parm with a name of your choosing + ./../../$os_arch/bin/configtxgen -profile TwoOrgs -outputCreateChannelTx channel.tx -channelID + +The channel configuration artifact - ``channel.tx`` - is output into the ``e2e`` directory. + +.. note:: Our configtx.yaml only contains one profile, therefore our channel and + our network are the same. However, this file could have multiple profiles + allowing channel creation to be scoped more granularly. + +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: + +.. code:: bash + + 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: + +.. code:: bash + + # 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= 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: + +.. code:: bash + + 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: + +.. code:: bash + + docker exec -it cli bash + +You should see the following: + +.. code:: bash + + 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 command we don't need to pass in any MSP or crypto material + attached to our peer. We do, however, need to pass in the MSP info + for our orderer. + +The following environment variables for the orderer must be passed: + +.. code:: bash + + 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= + +The syntax is as follows: + +.. code:: bash + + peer channel create -o :7050 -c -f channel.tx + +So our command in its entirety would be: + +.. code:: bash + + 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. + +.. code:: bash + + # 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 use 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: + +.. code:: bash + + peer channel join -b .block + +Remember, we need to pass the four global variables. So this command in its +entirety would be: + +.. code:: bash + + 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 on the peer's filesystem. The syntax +is as follows: + +.. code:: bash + + peer chaincode install -n -v -p + +This command in its entirety would be: + +.. code:: bash + + 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: + +.. code:: bash + + peer chaincode instantiate -o :7050 -C -n -v -c '{"Args":["init","key","value"]}' -P "OR/AND (CHAINCODE_POLICY)" + +This command in its entirety would be: + +.. code:: bash + + # 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 on 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: + +.. code:: bash + + peer chaincode query -C -n -c '{"Args":["query","key"]}' + +This command in its entirety would be: + +.. code:: bash + + 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"]}' + +Recall that we initialized our key value pairs as - "a","100","b","200" - therefore, +a query against key "a" should return the value of "100". + +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: + +.. code:: bash + + peer chaincode invoke -o :7050 -C -n -c '{"Args":["invoke","key","key","value"]}' + +.. code:: bash + + 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. + +.. code:: bash + + 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 enter the following: + +.. code:: bash + + 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 +^^^^^^^^ + +Lets clean things up before continuing. First, kill your containers: + +.. code:: bash + + 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: + +.. code:: bash + + 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: + + .. code:: bash + + docker rmi + +For example: + + .. code:: bash + + docker rmi -f 13f e27 111 + +Lastly, remove the `crypto-config`` folder and the two artifacts - ``channel.tx`` +& ``orderer.block``. + +All in one +^^^^^^^^^^ + +This script will do it all for you! From the ``e2e`` directory: + +.. code:: bash + + ./network_setup.sh up + +.. note:: If you choose not to pass a channel_name value, then the default + ``mychannel`` will be used. + +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: + +.. code:: bash + + ===================== 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. + +.. code:: bash + + # make sure you are in the fabric directory + make couchdb + +- Open the ``fabric/examples/e2e_cli/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 +``fabric/examples/chaincode/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``: + +.. code:: bash + + 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: + +.. code:: bash + + 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``): + +.. code:: bash + + peer chaincode query -C mychannel -n marbles -c '{"Args":["readMarble","marble2"]}' + +You should see the details of ``marble2``: + +.. code:: bash + + Query Result: {"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50} + +Retrieve the history of ``marble1``: + +.. code:: bash + + peer chaincode query -C mychannel -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}' + +You should see the transactions on ``marble1``: + +.. code:: bash + + 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``: + +.. code:: bash + + peer chaincode query -C mychannel -n marbles -c '{"Args":["queryMarblesByOwner","jerry"]}' + +The output should display the two marbles owned by ``jerry``: + +.. code:: bash + + 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``: + +.. code:: bash + + peer chaincode query -C mychannel -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"jerry\"}}"]}' + +The output should display: + +.. code:: bash + + 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: + +.. code:: bash + + volumes: + - /var/hyperledger/peer0:/var/hyperledger/production + + +For the CouchDB container, you may add the following two lines in the CouchDB +container specification: + +.. code:: bash + + 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. + +.. code:: bash + + 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. + +- If you see the below error: + +.. code:: bash + + 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. + +.. code:: bash + + docker rmi -f $(docker images | grep peer[0-9]-peer[0-9] | awk '{print $3}') + +- To cleanup the network, use the ``down`` option: + +.. code:: bash + + ./network_setup.sh down + +------------------------------------------------------------------------------- diff --git a/examples/dchackfest/samples/e2e/chaincodes/go/chaincode_example02/chaincode_example02.go b/examples/dchackfest/samples/e2e/chaincodes/go/chaincode_example02/chaincode_example02.go new file mode 100644 index 00000000000..129167e57ca --- /dev/null +++ b/examples/dchackfest/samples/e2e/chaincodes/go/chaincode_example02/chaincode_example02.go @@ -0,0 +1,199 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of +//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has +//to be modified as well with the new ID of chaincode_example02. +//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of +//hard-coding. + +import ( + "fmt" + "strconv" + + "github.com/hyperledger/fabric/core/chaincode/shim" + pb "github.com/hyperledger/fabric/protos/peer" +) + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("ex02 Init") + _, args := stub.GetFunctionAndParameters() + var A, B string // Entities + var Aval, Bval int // Asset holdings + var err error + + if len(args) != 4 { + return shim.Error("Incorrect number of arguments. Expecting 4") + } + + // Initialize the chaincode + A = args[0] + Aval, err = strconv.Atoi(args[1]) + if err != nil { + return shim.Error("Expecting integer value for asset holding") + } + B = args[2] + Bval, err = strconv.Atoi(args[3]) + if err != nil { + return shim.Error("Expecting integer value for asset holding") + } + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return shim.Error(err.Error()) + } + + err = stub.PutState(B, []byte(strconv.Itoa(Bval))) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(nil) +} + +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("ex02 Invoke") + function, args := stub.GetFunctionAndParameters() + if function == "invoke" { + // Make payment of X units from A to B + return t.invoke(stub, args) + } else if function == "delete" { + // Deletes an entity from its state + return t.delete(stub, args) + } else if function == "query" { + // the old "Query" is now implemtned in invoke + return t.query(stub, args) + } + + return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"") +} + +// Transaction makes payment of X units from A to B +func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var A, B string // Entities + var Aval, Bval int // Asset holdings + var X int // Transaction value + var err error + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + A = args[0] + B = args[1] + + // Get the state from the ledger + // TODO: will be nice to have a GetAllState call to ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + return shim.Error("Failed to get state") + } + if Avalbytes == nil { + return shim.Error("Entity not found") + } + Aval, _ = strconv.Atoi(string(Avalbytes)) + + Bvalbytes, err := stub.GetState(B) + if err != nil { + return shim.Error("Failed to get state") + } + if Bvalbytes == nil { + return shim.Error("Entity not found") + } + Bval, _ = strconv.Atoi(string(Bvalbytes)) + + // Perform the execution + X, err = strconv.Atoi(args[2]) + if err != nil { + return shim.Error("Invalid transaction amount, expecting a integer value") + } + Aval = Aval - X + Bval = Bval + X + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state back to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return shim.Error(err.Error()) + } + + err = stub.PutState(B, []byte(strconv.Itoa(Bval))) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(nil) +} + +// Deletes an entity from state +func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + A := args[0] + + // Delete the key from the state in ledger + err := stub.DelState(A) + if err != nil { + return shim.Error("Failed to delete state") + } + + return shim.Success(nil) +} + +// query callback representing the query of a chaincode +func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var A string // Entities + var err error + + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting name of the person to query") + } + + A = args[0] + + // Get the state from the ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" + return shim.Error(jsonResp) + } + + if Avalbytes == nil { + jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" + return shim.Error(jsonResp) + } + + jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" + fmt.Printf("Query Response:%s\n", jsonResp) + return shim.Success(Avalbytes) +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} diff --git a/examples/dchackfest/samples/e2e/chaincodes/go/marbles02/marbles_chaincode.go b/examples/dchackfest/samples/e2e/chaincodes/go/marbles02/marbles_chaincode.go new file mode 100644 index 00000000000..4ea4654adf4 --- /dev/null +++ b/examples/dchackfest/samples/e2e/chaincodes/go/marbles02/marbles_chaincode.go @@ -0,0 +1,627 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +// ====CHAINCODE EXECUTION SAMPLES (CLI) ================== + +// ==== Invoke marbles ==== +// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}' +// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}' +// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}' +// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarble","marble2","jerry"]}' +// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}' +// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["delete","marble1"]}' + +// ==== Query marbles ==== +// peer chaincode query -C myc1 -n marbles -c '{"Args":["readMarble","marble1"]}' +// peer chaincode query -C myc1 -n marbles -c '{"Args":["getMarblesByRange","marble1","marble3"]}' +// peer chaincode query -C myc1 -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}' + +// Rich Query (Only supported if CouchDB is used as state database): +// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesByOwner","tom"]}' +// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}' + +//The following examples demonstrate creating indexes on CouchDB +//Example hostname:port configurations +// +//Docker or vagrant environments: +// http://couchdb:5984/ +// +//Inside couchdb docker container +// http://127.0.0.1:5984/ + +// Index for chaincodeid, docType, owner. +// Note that docType and owner fields must be prefixed with the "data" wrapper +// chaincodeid must be added for all queries +// +// Definition for use with Fauxton interface +// {"index":{"fields":["chaincodeid","data.docType","data.owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"} +// +// example curl definition for use with command line +// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"chaincodeid\",\"data.docType\",\"data.owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1/_index +// + +// Index for chaincodeid, docType, owner, size (descending order). +// Note that docType, owner and size fields must be prefixed with the "data" wrapper +// chaincodeid must be added for all queries +// +// Definition for use with Fauxton interface +// {"index":{"fields":[{"data.size":"desc"},{"chaincodeid":"desc"},{"data.docType":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortDesc","type":"json"} +// +// example curl definition for use with command line +// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"data.size\":\"desc\"},{\"chaincodeid\":\"desc\"},{\"data.docType\":\"desc\"},{\"data.owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1/_index + +// Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database): +// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}' + +// Rich Query with index design doc specified only (Only supported if CouchDB is used as state database): +// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":{\"$eq\":\"marble\"},\"owner\":{\"$eq\":\"tom\"},\"size\":{\"$gt\":0}},\"fields\":[\"docType\",\"owner\",\"size\"],\"sort\":[{\"size\":\"desc\"}],\"use_index\":\"_design/indexSizeSortDoc\"}"]}' + +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + "github.com/hyperledger/fabric/core/chaincode/shim" + pb "github.com/hyperledger/fabric/protos/peer" +) + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + +type marble struct { + ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database + Name string `json:"name"` //the fieldtags are needed to keep case from bouncing around + Color string `json:"color"` + Size int `json:"size"` + Owner string `json:"owner"` +} + +// =================================================================================== +// Main +// =================================================================================== +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} + +// Init initializes chaincode +// =========================== +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + return shim.Success(nil) +} + +// Invoke - Our entry point for Invocations +// ======================================== +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { + function, args := stub.GetFunctionAndParameters() + fmt.Println("invoke is running " + function) + + // Handle different functions + if function == "initMarble" { //create a new marble + return t.initMarble(stub, args) + } else if function == "transferMarble" { //change owner of a specific marble + return t.transferMarble(stub, args) + } else if function == "transferMarblesBasedOnColor" { //transfer all marbles of a certain color + return t.transferMarblesBasedOnColor(stub, args) + } else if function == "delete" { //delete a marble + return t.delete(stub, args) + } else if function == "readMarble" { //read a marble + return t.readMarble(stub, args) + } else if function == "queryMarblesByOwner" { //find marbles for owner X using rich query + return t.queryMarblesByOwner(stub, args) + } else if function == "queryMarbles" { //find marbles based on an ad hoc rich query + return t.queryMarbles(stub, args) + } else if function == "getHistoryForMarble" { //get history of values for a marble + return t.getHistoryForMarble(stub, args) + } else if function == "getMarblesByRange" { //get marbles based on range query + return t.getMarblesByRange(stub, args) + } + + fmt.Println("invoke did not find func: " + function) //error + return shim.Error("Received unknown function invocation") +} + +// ============================================================ +// initMarble - create a new marble, store into chaincode state +// ============================================================ +func (t *SimpleChaincode) initMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + + // 0 1 2 3 + // "asdf", "blue", "35", "bob" + if len(args) != 4 { + return shim.Error("Incorrect number of arguments. Expecting 4") + } + + // ==== Input sanitation ==== + fmt.Println("- start init marble") + if len(args[0]) <= 0 { + return shim.Error("1st argument must be a non-empty string") + } + if len(args[1]) <= 0 { + return shim.Error("2nd argument must be a non-empty string") + } + if len(args[2]) <= 0 { + return shim.Error("3rd argument must be a non-empty string") + } + if len(args[3]) <= 0 { + return shim.Error("4th argument must be a non-empty string") + } + marbleName := args[0] + color := strings.ToLower(args[1]) + owner := strings.ToLower(args[3]) + size, err := strconv.Atoi(args[2]) + if err != nil { + return shim.Error("3rd argument must be a numeric string") + } + + // ==== Check if marble already exists ==== + marbleAsBytes, err := stub.GetState(marbleName) + if err != nil { + return shim.Error("Failed to get marble: " + err.Error()) + } else if marbleAsBytes != nil { + fmt.Println("This marble already exists: " + marbleName) + return shim.Error("This marble already exists: " + marbleName) + } + + // ==== Create marble object and marshal to JSON ==== + objectType := "marble" + marble := &marble{objectType, marbleName, color, size, owner} + marbleJSONasBytes, err := json.Marshal(marble) + if err != nil { + return shim.Error(err.Error()) + } + //Alternatively, build the marble json string manually if you don't want to use struct marshalling + //marbleJSONasString := `{"docType":"Marble", "name": "` + marbleName + `", "color": "` + color + `", "size": ` + strconv.Itoa(size) + `, "owner": "` + owner + `"}` + //marbleJSONasBytes := []byte(str) + + // === Save marble to state === + err = stub.PutState(marbleName, marbleJSONasBytes) + if err != nil { + return shim.Error(err.Error()) + } + + // ==== Index the marble to enable color-based range queries, e.g. return all blue marbles ==== + // An 'index' is a normal key/value entry in state. + // The key is a composite key, with the elements that you want to range query on listed first. + // In our case, the composite key is based on indexName~color~name. + // This will enable very efficient state range queries based on composite keys matching indexName~color~* + indexName := "color~name" + colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marble.Color, marble.Name}) + if err != nil { + return shim.Error(err.Error()) + } + // Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble. + // Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value + value := []byte{0x00} + stub.PutState(colorNameIndexKey, value) + + // ==== Marble saved and indexed. Return success ==== + fmt.Println("- end init marble") + return shim.Success(nil) +} + +// =============================================== +// readMarble - read a marble from chaincode state +// =============================================== +func (t *SimpleChaincode) readMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var name, jsonResp string + var err error + + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting name of the marble to query") + } + + name = args[0] + valAsbytes, err := stub.GetState(name) //get the marble from chaincode state + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"Marble does not exist: " + name + "\"}" + return shim.Error(jsonResp) + } + + return shim.Success(valAsbytes) +} + +// ================================================== +// delete - remove a marble key/value pair from state +// ================================================== +func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var jsonResp string + var marbleJSON marble + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + marbleName := args[0] + + // to maintain the color~name index, we need to read the marble first and get its color + valAsbytes, err := stub.GetState(marbleName) //get the marble from chaincode state + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + marbleName + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"Marble does not exist: " + marbleName + "\"}" + return shim.Error(jsonResp) + } + + err = json.Unmarshal([]byte(valAsbytes), &marbleJSON) + if err != nil { + jsonResp = "{\"Error\":\"Failed to decode JSON of: " + marbleName + "\"}" + return shim.Error(jsonResp) + } + + err = stub.DelState(marbleName) //remove the marble from chaincode state + if err != nil { + return shim.Error("Failed to delete state:" + err.Error()) + } + + // maintain the index + indexName := "color~name" + colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marbleJSON.Color, marbleJSON.Name}) + if err != nil { + return shim.Error(err.Error()) + } + + // Delete index entry to state. + err = stub.DelState(colorNameIndexKey) + if err != nil { + return shim.Error("Failed to delete state:" + err.Error()) + } + return shim.Success(nil) +} + +// =========================================================== +// transfer a marble by setting a new owner name on the marble +// =========================================================== +func (t *SimpleChaincode) transferMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // 0 1 + // "name", "bob" + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + marbleName := args[0] + newOwner := strings.ToLower(args[1]) + fmt.Println("- start transferMarble ", marbleName, newOwner) + + marbleAsBytes, err := stub.GetState(marbleName) + if err != nil { + return shim.Error("Failed to get marble:" + err.Error()) + } else if marbleAsBytes == nil { + return shim.Error("Marble does not exist") + } + + marbleToTransfer := marble{} + err = json.Unmarshal(marbleAsBytes, &marbleToTransfer) //unmarshal it aka JSON.parse() + if err != nil { + return shim.Error(err.Error()) + } + marbleToTransfer.Owner = newOwner //change the owner + + marbleJSONasBytes, _ := json.Marshal(marbleToTransfer) + err = stub.PutState(marbleName, marbleJSONasBytes) //rewrite the marble + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end transferMarble (success)") + return shim.Success(nil) +} + +// =========================================================================================== +// getMarblesByRange performs a range query based on the start and end keys provided. + +// Read-only function results are not typically submitted to ordering. If the read-only +// results are submitted to ordering, or if the query is used in an update transaction +// and submitted to ordering, then the committing peers will re-execute to guarantee that +// result sets are stable between endorsement time and commit time. The transaction is +// invalidated by the committing peers if the result set has changed between endorsement +// time and commit time. +// Therefore, range queries are a safe option for performing update transactions based on query results. +// =========================================================================================== +func (t *SimpleChaincode) getMarblesByRange(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + startKey := args[0] + endKey := args[1] + + resultsIterator, err := stub.GetStateByRange(startKey, endKey) + if err != nil { + return shim.Error(err.Error()) + } + defer resultsIterator.Close() + + // buffer is a JSON array containing QueryResults + var buffer bytes.Buffer + buffer.WriteString("[") + + bArrayMemberAlreadyWritten := false + for resultsIterator.HasNext() { + queryResponse, err := resultsIterator.Next() + if err != nil { + return shim.Error(err.Error()) + } + // Add a comma before array members, suppress it for the first array member + if bArrayMemberAlreadyWritten == true { + buffer.WriteString(",") + } + buffer.WriteString("{\"Key\":") + buffer.WriteString("\"") + buffer.WriteString(queryResponse.Key) + buffer.WriteString("\"") + + buffer.WriteString(", \"Record\":") + // Record is a JSON object, so we write as-is + buffer.WriteString(string(queryResponse.Value)) + buffer.WriteString("}") + bArrayMemberAlreadyWritten = true + } + buffer.WriteString("]") + + fmt.Printf("- getMarblesByRange queryResult:\n%s\n", buffer.String()) + + return shim.Success(buffer.Bytes()) +} + +// ==== Example: GetStateByPartialCompositeKey/RangeQuery ========================================= +// transferMarblesBasedOnColor will transfer marbles of a given color to a certain new owner. +// Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'. +// Committing peers will re-execute range queries to guarantee that result sets are stable +// between endorsement time and commit time. The transaction is invalidated by the +// committing peers if the result set has changed between endorsement time and commit time. +// Therefore, range queries are a safe option for performing update transactions based on query results. +// =========================================================================================== +func (t *SimpleChaincode) transferMarblesBasedOnColor(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // 0 1 + // "color", "bob" + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + color := args[0] + newOwner := strings.ToLower(args[1]) + fmt.Println("- start transferMarblesBasedOnColor ", color, newOwner) + + // Query the color~name index by color + // This will execute a key range query on all keys starting with 'color' + coloredMarbleResultsIterator, err := stub.GetStateByPartialCompositeKey("color~name", []string{color}) + if err != nil { + return shim.Error(err.Error()) + } + defer coloredMarbleResultsIterator.Close() + + // Iterate through result set and for each marble found, transfer to newOwner + var i int + for i = 0; coloredMarbleResultsIterator.HasNext(); i++ { + // Note that we don't get the value (2nd return variable), we'll just get the marble name from the composite key + responseRange, err := coloredMarbleResultsIterator.Next() + if err != nil { + return shim.Error(err.Error()) + } + + // get the color and name from color~name composite key + objectType, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key) + if err != nil { + return shim.Error(err.Error()) + } + returnedColor := compositeKeyParts[0] + returnedMarbleName := compositeKeyParts[1] + fmt.Printf("- found a marble from index:%s color:%s name:%s\n", objectType, returnedColor, returnedMarbleName) + + // Now call the transfer function for the found marble. + // Re-use the same function that is used to transfer individual marbles + response := t.transferMarble(stub, []string{returnedMarbleName, newOwner}) + // if the transfer failed break out of loop and return error + if response.Status != shim.OK { + return shim.Error("Transfer failed: " + response.Message) + } + } + + responsePayload := fmt.Sprintf("Transferred %d %s marbles to %s", i, color, newOwner) + fmt.Println("- end transferMarblesBasedOnColor: " + responsePayload) + return shim.Success([]byte(responsePayload)) +} + +// =======Rich queries ========================================================================= +// Two examples of rich queries are provided below (parameterized query and ad hoc query). +// Rich queries pass a query string to the state database. +// Rich queries are only supported by state database implementations +// that support rich query (e.g. CouchDB). +// The query string is in the syntax of the underlying state database. +// With rich queries there is no guarantee that the result set hasn't changed between +// endorsement time and commit time, aka 'phantom reads'. +// Therefore, rich queries should not be used in update transactions, unless the +// application handles the possibility of result set changes between endorsement and commit time. +// Rich queries can be used for point-in-time queries against a peer. +// ============================================================================================ + +// ===== Example: Parameterized rich query ================================================= +// queryMarblesByOwner queries for marbles based on a passed in owner. +// This is an example of a parameterized query where the query logic is baked into the chaincode, +// and accepting a single query parameter (owner). +// Only available on state databases that support rich query (e.g. CouchDB) +// ========================================================================================= +func (t *SimpleChaincode) queryMarblesByOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // 0 + // "bob" + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + owner := strings.ToLower(args[0]) + + queryString := fmt.Sprintf("{\"selector\":{\"docType\":\"marble\",\"owner\":\"%s\"}}", owner) + + queryResults, err := getQueryResultForQueryString(stub, queryString) + if err != nil { + return shim.Error(err.Error()) + } + return shim.Success(queryResults) +} + +// ===== Example: Ad hoc rich query ======================================================== +// queryMarbles uses a query string to perform a query for marbles. +// Query string matching state database syntax is passed in and executed as is. +// Supports ad hoc queries that can be defined at runtime by the client. +// If this is not desired, follow the queryMarblesForOwner example for parameterized queries. +// Only available on state databases that support rich query (e.g. CouchDB) +// ========================================================================================= +func (t *SimpleChaincode) queryMarbles(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // 0 + // "queryString" + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + queryString := args[0] + + queryResults, err := getQueryResultForQueryString(stub, queryString) + if err != nil { + return shim.Error(err.Error()) + } + return shim.Success(queryResults) +} + +// ========================================================================================= +// getQueryResultForQueryString executes the passed in query string. +// Result set is built and returned as a byte array containing the JSON results. +// ========================================================================================= +func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) { + + fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString) + + resultsIterator, err := stub.GetQueryResult(queryString) + if err != nil { + return nil, err + } + defer resultsIterator.Close() + + // buffer is a JSON array containing QueryRecords + var buffer bytes.Buffer + buffer.WriteString("[") + + bArrayMemberAlreadyWritten := false + for resultsIterator.HasNext() { + queryResponse, err := resultsIterator.Next() + if err != nil { + return nil, err + } + // Add a comma before array members, suppress it for the first array member + if bArrayMemberAlreadyWritten == true { + buffer.WriteString(",") + } + buffer.WriteString("{\"Key\":") + buffer.WriteString("\"") + buffer.WriteString(queryResponse.Key) + buffer.WriteString("\"") + + buffer.WriteString(", \"Record\":") + // Record is a JSON object, so we write as-is + buffer.WriteString(string(queryResponse.Value)) + buffer.WriteString("}") + bArrayMemberAlreadyWritten = true + } + buffer.WriteString("]") + + fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String()) + + return buffer.Bytes(), nil +} + +func (t *SimpleChaincode) getHistoryForMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + marbleName := args[0] + + fmt.Printf("- start getHistoryForMarble: %s\n", marbleName) + + resultsIterator, err := stub.GetHistoryForKey(marbleName) + if err != nil { + return shim.Error(err.Error()) + } + defer resultsIterator.Close() + + // buffer is a JSON array containing historic values for the marble + var buffer bytes.Buffer + buffer.WriteString("[") + + bArrayMemberAlreadyWritten := false + for resultsIterator.HasNext() { + response, err := resultsIterator.Next() + if err != nil { + return shim.Error(err.Error()) + } + // Add a comma before array members, suppress it for the first array member + if bArrayMemberAlreadyWritten == true { + buffer.WriteString(",") + } + buffer.WriteString("{\"TxId\":") + buffer.WriteString("\"") + buffer.WriteString(response.TxId) + buffer.WriteString("\"") + + buffer.WriteString(", \"Value\":") + // if it was a delete operation on given key, then we need to set the + //corresponding value null. Else, we will write the response.Value + //as-is (as the Value itself a JSON marble) + if response.IsDelete { + buffer.WriteString("null") + } else { + buffer.WriteString(string(response.Value)) + } + + buffer.WriteString(", \"Timestamp\":") + buffer.WriteString("\"") + buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String()) + buffer.WriteString("\"") + + buffer.WriteString(", \"IsDelete\":") + buffer.WriteString("\"") + buffer.WriteString(strconv.FormatBool(response.IsDelete)) + buffer.WriteString("\"") + + buffer.WriteString("}") + bArrayMemberAlreadyWritten = true + } + buffer.WriteString("]") + + fmt.Printf("- getHistoryForMarble returning:\n%s\n", buffer.String()) + + return shim.Success(buffer.Bytes()) +} diff --git a/examples/dchackfest/samples/e2e/configtx.yaml b/examples/dchackfest/samples/e2e/configtx.yaml new file mode 100644 index 00000000000..f3657e2437b --- /dev/null +++ b/examples/dchackfest/samples/e2e/configtx.yaml @@ -0,0 +1,173 @@ +--- +################################################################################ +# +# Profile +# +# - Different configuration profiles may be encoded here to be specified +# as parameters to the configtxgen tool +# +################################################################################ +Profiles: + + TwoOrgs: + Orderer: + <<: *OrdererDefaults + Organizations: + - *OrdererOrg + Application: + <<: *ApplicationDefaults + Organizations: + - *Org0 + - *Org1 + +################################################################################ +# +# Section: Organizations +# +# - This section defines the different organizational identities which will +# be referenced later in the configuration. +# +################################################################################ +Organizations: + + # SampleOrg defines an MSP using the sampleconfig. It should never be used + # in production but may be used as a template for other definitions + - &OrdererOrg + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: OrdererOrg + + # ID to load the MSP definition as + ID: OrdererMSP + + # MSPDir is the filesystem path which contains the MSP configuration + MSPDir: crypto-config/ordererOrganizations/example.com/msp + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + SW: + Hash: SHA2 + Security: 256 + # Location of Key Store. If this is unset, a location will + # be chosen using 'MSPDir'/keystore + FileKeyStore: + KeyStore: + + - &Org0 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org0MSP + + # ID to load the MSP definition as + ID: Org0MSP + + MSPDir: crypto-config/peerOrganizations/org1.example.com/msp + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + SW: + Hash: SHA2 + Security: 256 + # Location of Key Store. If this is unset, a location will + # be chosen using 'MSPDir'/keystore + FileKeyStore: + KeyStore: + + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: peer0.org1.example.com + Port: 7051 + + - &Org1 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org1MSP + + # ID to load the MSP definition as + ID: Org1MSP + + MSPDir: crypto-config/peerOrganizations/org2.example.com/msp + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + SW: + Hash: SHA2 + Security: 256 + # Location of Key Store. If this is unset, a location will + # be chosen using 'MSPDir'/keystore + FileKeyStore: + KeyStore: + + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: peer0.org2.example.com + Port: 7051 + +################################################################################ +# +# SECTION: Orderer +# +# - This section defines the values to encode into a config transaction or +# genesis block for orderer related parameters +# +################################################################################ +Orderer: &OrdererDefaults + + # Orderer Type: The orderer implementation to start + # Available types are "solo" and "kafka" + OrdererType: solo + + Addresses: + - orderer.example.com:7050 + + # Batch Timeout: The amount of time to wait before creating a batch + BatchTimeout: 2s + + # Batch Size: Controls the number of messages batched into a block + BatchSize: + + # Max Message Count: The maximum number of messages to permit in a batch + MaxMessageCount: 10 + + # Absolute Max Bytes: The absolute maximum number of bytes allowed for + # the serialized messages in a batch. + AbsoluteMaxBytes: 99 MB + + # Preferred Max Bytes: The preferred maximum number of bytes allowed for + # the serialized messages in a batch. A message larger than the preferred + # max bytes will result in a batch larger than preferred max bytes. + PreferredMaxBytes: 512 KB + + Kafka: + # Brokers: A list of Kafka brokers to which the orderer connects + # NOTE: Use IP:port notation + Brokers: + - 127.0.0.1:9092 + + # Organizations is the list of orgs which are defined as participants on + # the orderer side of the network + Organizations: + +################################################################################ +# +# SECTION: Application +# +# - This section defines the values to encode into a config transaction or +# genesis block for application related parameters +# +################################################################################ +Application: &ApplicationDefaults + + # Organizations is the list of orgs which are defined as participants on + # the application side of the network + Organizations: diff --git a/examples/dchackfest/samples/e2e/crypto-config.yaml b/examples/dchackfest/samples/e2e/crypto-config.yaml new file mode 100644 index 00000000000..9c9c30bce95 --- /dev/null +++ b/examples/dchackfest/samples/e2e/crypto-config.yaml @@ -0,0 +1,76 @@ +# --------------------------------------------------------------------------- +# "OrdererOrgs" - Definition of organizations managing orderer nodes +# --------------------------------------------------------------------------- +OrdererOrgs: + # --------------------------------------------------------------------------- + # Orderer + # --------------------------------------------------------------------------- + - Name: Orderer + Domain: example.com + # --------------------------------------------------------------------------- + # "Specs" - See PeerOrgs below for complete description + # --------------------------------------------------------------------------- + Specs: + - Hostname: orderer +# --------------------------------------------------------------------------- +# "PeerOrgs" - Definition of organizations managing peer nodes +# --------------------------------------------------------------------------- +PeerOrgs: + # --------------------------------------------------------------------------- + # Org1 + # --------------------------------------------------------------------------- + - Name: Org1 + Domain: org1.example.com + # --------------------------------------------------------------------------- + # "Specs" + # --------------------------------------------------------------------------- + # Uncomment this section to enable the explicit definition of hosts in your + # configuration. Most users will want to use Template, below + # + # Specs is an array of Spec entries. Each Spec entry consists of two fields: + # - Hostname: (Required) The desired hostname, sans the domain. + # - CommonName: (Optional) Specifies the template or explicit override for + # the CN. By default, this is the template: + # + # "{{.Hostname}}.{{.Domain}}" + # + # which obtains its values from the Spec.Hostname and + # Org.Domain, respectively. + # --------------------------------------------------------------------------- + # Specs: + # - Hostname: foo # implicitly "foo.org1.example.com" + # CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above + # - Hostname: bar + # - Hostname: baz + # --------------------------------------------------------------------------- + # "Template" + # --------------------------------------------------------------------------- + # Allows for the definition of 1 or more hosts that are created sequentially + # from a template. By default, this looks like "peer%d" from 0 to Count-1. + # You may override the number of nodes (Count), the starting index (Start) + # or the template used to construct the name (Hostname). + # + # Note: Template and Specs are not mutually exclusive. You may define both + # sections and the aggregate nodes will be created for you. Take care with + # name collisions + # --------------------------------------------------------------------------- + Template: + Count: 2 + # Start: 5 + # Hostname: {{.Prefix}}{{.Index}} # default + # --------------------------------------------------------------------------- + # "Users" + # --------------------------------------------------------------------------- + # Count: The number of user accounts _in addition_ to Admin + # --------------------------------------------------------------------------- + Users: + Count: 1 + # --------------------------------------------------------------------------- + # Org2: See "Org1" for full specification + # --------------------------------------------------------------------------- + - Name: Org2 + Domain: org2.example.com + Template: + Count: 2 + Users: + Count: 1 diff --git a/examples/dchackfest/samples/e2e/docker-compose-no-tls.yaml b/examples/dchackfest/samples/e2e/docker-compose-no-tls.yaml new file mode 100644 index 00000000000..2f70d2b9551 --- /dev/null +++ b/examples/dchackfest/samples/e2e/docker-compose-no-tls.yaml @@ -0,0 +1,128 @@ +version: '2' + +services: + + orderer.example.com: + container_name: orderer.example.com + image: hyperledger/fabric-orderer:${ARCH_TAG}-1.0.0-alpha + environment: + - ORDERER_GENERAL_LOGLEVEL=debug + - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 + - ORDERER_GENERAL_GENESISMETHOD=file + - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.block + - ORDERER_GENERAL_LOCALMSPID=OrdererMSP + - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp + working_dir: /opt/gopath/src/github.com/hyperledger/fabric + command: orderer + volumes: + - ./orderer.block:/var/hyperledger/orderer/orderer.block + - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com:/var/hyperledger/orderer/msp + ports: + - 7050:7050 + + peer0.org1.example.com: + container_name: peer0.org1.example.com + extends: + file: peer-base/peer-base-no-tls.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer0.org1.example.com + - CORE_PEER_LOCALMSPID=Org0MSP + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 7051:7051 + - 7053:7053 + depends_on: + - orderer.example.com + + peer1.org1.example.com: + container_name: peer1.org1.example.com + extends: + file: peer-base/peer-base-no-tls.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer1.org1.example.com + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0:7051 + - CORE_PEER_LOCALMSPID=Org0MSP + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 8051:7051 + - 8053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + + peer0.org2.example.com: + container_name: peer0.org2.example.com + extends: + file: peer-base/peer-base-no-tls.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer0.org2.example.com + #- CORE_PEER_GOSSIP_BOOTSTRAP=peer2:7051 + - CORE_PEER_LOCALMSPID=Org1MSP + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 9051:7051 + - 9053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + # - couchdb2 + + peer1.org2.example.com: + container_name: peer1.org2.example.com + extends: + file: peer-base/peer-base-no-tls.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer1.org2.example.com + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051 + - CORE_PEER_LOCALMSPID=Org1MSP + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 10051:7051 + - 10053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + - peer0.org2.example.com + + cli: + container_name: cli + image: hyperledger/fabric-peer:${ARCH_TAG}-1.0.0-alpha + tty: true + environment: + - GOPATH=/opt/gopath + - CORE_PEER_ADDRESSAUTODETECT=true + - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock + - CORE_LOGGING_LEVEL=DEBUG + - CORE_PEER_ID=cli + - CORE_PEER_ENDORSER_ENABLED=true + - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 + - CORE_PEER_GOSSIP_IGNORESECURITY=true + - CORE_PEER_LOCALMSPID=Org0MSP + working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer + command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; ' + volumes: + - /var/run/:/host/var/run/ + - ./chaincodes:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode + - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ + - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ + - ./channel.tx:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel.tx + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + - peer0.org2.example.com + - peer1.org2.example.com diff --git a/examples/dchackfest/samples/e2e/docker-compose-template.yaml b/examples/dchackfest/samples/e2e/docker-compose-template.yaml new file mode 100644 index 00000000000..dbcfe5e4903 --- /dev/null +++ b/examples/dchackfest/samples/e2e/docker-compose-template.yaml @@ -0,0 +1,208 @@ +version: '2' + +services: + + orderer.example.com: + container_name: orderer.example.com + image: hyperledger/fabric-orderer:${ARCH_TAG}-1.0.0-alpha + environment: + - ORDERER_GENERAL_LOGLEVEL=debug + - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 + - ORDERER_GENERAL_GENESISMETHOD=file + - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.block + - ORDERER_GENERAL_LOCALMSPID=OrdererMSP + - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp + # enabled TLS + - ORDERER_GENERAL_TLS_ENABLED=true + - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/msp/keystore/ORDERER_PRIVATE_KEY + - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/msp/signcerts/orderer.example.com-cert.pem + - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/msp/cacerts/example.com-cert.pem] + working_dir: /opt/gopath/src/github.com/hyperledger/fabric + command: orderer + volumes: + - ./orderer.block:/var/hyperledger/orderer/orderer.block + - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com:/var/hyperledger/orderer/msp + ports: + - 7050:7050 + +## To enable CouchDB as state database, uncomment the following sections of this file: +## 1) couchdb containers +## 2) peer environment variables CORE_LEDGER_STATE_STATEDATABASE and +## CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS +## 3) couch container names in "depends_on" section + +# couchdb0: +# container_name: couchdb0 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "5984:5984" + + peer0.org1.example.com: + container_name: peer0.org1.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer0.org1.example.com + - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 + - CORE_PEER_LOCALMSPID=Org0MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer0.org1.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER0_ORG1_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org1.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 7051:7051 + - 7053:7053 + depends_on: + - orderer.example.com + # - couchdb0 + +# couchdb1: +# container_name: couchdb1 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "6984:5984" + + peer1.org1.example.com: + container_name: peer1.org1.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer1.org1.example.com + - CORE_PEER_ADDRESS=peer1.org1.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0:7051 + - CORE_PEER_LOCALMSPID=Org0MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer1.org1.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER1_ORG1_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org1.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 8051:7051 + - 8053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + # - couchdb1 + +# couchdb2: +# container_name: couchdb2 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "7984:5984" + + peer0.org2.example.com: + container_name: peer0.org2.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer0.org2.example.com + - CORE_PEER_ADDRESS=peer0.org2.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051 + - CORE_PEER_LOCALMSPID=Org1MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer0.org2.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER0_ORG2_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org2.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb2:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 9051:7051 + - 9053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + # - couchdb2 + +# couchdb3: +# container_name: couchdb3 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "8984:5984" + + peer1.org2.example.com: + container_name: peer1.org2.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer1.org2.example.com + - CORE_PEER_ADDRESS=peer1.org2.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:7051 + - CORE_PEER_LOCALMSPID=Org1MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer1.org2.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER1_ORG2_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org2.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb3:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 10051:7051 + - 10053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + - peer0.org2.example.com + # - couchdb3 + + cli: + container_name: cli + image: hyperledger/fabric-peer:${ARCH_TAG}-1.0.0-alpha + tty: true + environment: + - GOPATH=/opt/gopath + - CORE_PEER_ADDRESSAUTODETECT=true + - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock + - CORE_LOGGING_LEVEL=DEBUG + - CORE_NEXT=true + - CORE_PEER_ID=cli + - CORE_PEER_ENDORSER_ENABLED=true + - CORE_PEER_ADDRESS=peer0:7051 + - CORE_PEER_LOCALMSPID=Org0MSP + - 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/signcerts/peer0.org1.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/keystore/PEER0_ORG1_PRIVATE_KEY + - 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 + - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com + + working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer + command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; ' + volumes: + - /var/run/:/host/var/run/ + - ./chaincodes:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode + - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ + - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ + - ./channel.tx:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel.tx + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + - peer0.org2.example.com + - peer1.org2.example.com diff --git a/examples/dchackfest/samples/e2e/docker-compose.yaml b/examples/dchackfest/samples/e2e/docker-compose.yaml new file mode 100644 index 00000000000..dbcfe5e4903 --- /dev/null +++ b/examples/dchackfest/samples/e2e/docker-compose.yaml @@ -0,0 +1,208 @@ +version: '2' + +services: + + orderer.example.com: + container_name: orderer.example.com + image: hyperledger/fabric-orderer:${ARCH_TAG}-1.0.0-alpha + environment: + - ORDERER_GENERAL_LOGLEVEL=debug + - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 + - ORDERER_GENERAL_GENESISMETHOD=file + - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.block + - ORDERER_GENERAL_LOCALMSPID=OrdererMSP + - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp + # enabled TLS + - ORDERER_GENERAL_TLS_ENABLED=true + - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/msp/keystore/ORDERER_PRIVATE_KEY + - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/msp/signcerts/orderer.example.com-cert.pem + - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/msp/cacerts/example.com-cert.pem] + working_dir: /opt/gopath/src/github.com/hyperledger/fabric + command: orderer + volumes: + - ./orderer.block:/var/hyperledger/orderer/orderer.block + - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com:/var/hyperledger/orderer/msp + ports: + - 7050:7050 + +## To enable CouchDB as state database, uncomment the following sections of this file: +## 1) couchdb containers +## 2) peer environment variables CORE_LEDGER_STATE_STATEDATABASE and +## CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS +## 3) couch container names in "depends_on" section + +# couchdb0: +# container_name: couchdb0 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "5984:5984" + + peer0.org1.example.com: + container_name: peer0.org1.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer0.org1.example.com + - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 + - CORE_PEER_LOCALMSPID=Org0MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer0.org1.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER0_ORG1_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org1.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 7051:7051 + - 7053:7053 + depends_on: + - orderer.example.com + # - couchdb0 + +# couchdb1: +# container_name: couchdb1 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "6984:5984" + + peer1.org1.example.com: + container_name: peer1.org1.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer1.org1.example.com + - CORE_PEER_ADDRESS=peer1.org1.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0:7051 + - CORE_PEER_LOCALMSPID=Org0MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer1.org1.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER1_ORG1_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org1.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 8051:7051 + - 8053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + # - couchdb1 + +# couchdb2: +# container_name: couchdb2 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "7984:5984" + + peer0.org2.example.com: + container_name: peer0.org2.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer0.org2.example.com + - CORE_PEER_ADDRESS=peer0.org2.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051 + - CORE_PEER_LOCALMSPID=Org1MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer0.org2.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER0_ORG2_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org2.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb2:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 9051:7051 + - 9053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + # - couchdb2 + +# couchdb3: +# container_name: couchdb3 +# image: hyperledger/fabric-couchdb +## Uncomment the port mapping if you want to expose the CouchDB service, +## for example to utilize Fauxton User Interface in dev environments. +# ports: +# - "8984:5984" + + peer1.org2.example.com: + container_name: peer1.org2.example.com + extends: + file: peer-base/peer-base.yaml + service: peer-base + environment: + - CORE_PEER_ID=peer1.org2.example.com + - CORE_PEER_ADDRESS=peer1.org2.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:7051 + - CORE_PEER_LOCALMSPID=Org1MSP + - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/signcerts/peer1.org2.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/msp/sampleconfig/keystore/PEER1_ORG2_PRIVATE_KEY + - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/msp/sampleconfig/cacerts/org2.example.com-cert.pem + # - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + # - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb3:5984 + volumes: + - /var/run/:/host/var/run/ + - ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com:/etc/hyperledger/fabric/msp/sampleconfig + ports: + - 10051:7051 + - 10053:7053 + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + - peer0.org2.example.com + # - couchdb3 + + cli: + container_name: cli + image: hyperledger/fabric-peer:${ARCH_TAG}-1.0.0-alpha + tty: true + environment: + - GOPATH=/opt/gopath + - CORE_PEER_ADDRESSAUTODETECT=true + - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock + - CORE_LOGGING_LEVEL=DEBUG + - CORE_NEXT=true + - CORE_PEER_ID=cli + - CORE_PEER_ENDORSER_ENABLED=true + - CORE_PEER_ADDRESS=peer0:7051 + - CORE_PEER_LOCALMSPID=Org0MSP + - 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/signcerts/peer0.org1.example.com-cert.pem + - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/keystore/PEER0_ORG1_PRIVATE_KEY + - 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 + - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com + + working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer + command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; ' + volumes: + - /var/run/:/host/var/run/ + - ./chaincodes:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode + - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ + - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ + - ./channel.tx:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel.tx + depends_on: + - orderer.example.com + - peer0.org1.example.com + - peer1.org1.example.com + - peer0.org2.example.com + - peer1.org2.example.com diff --git a/examples/dchackfest/samples/e2e/network_setup.sh b/examples/dchackfest/samples/e2e/network_setup.sh new file mode 100755 index 00000000000..a71dbfe578d --- /dev/null +++ b/examples/dchackfest/samples/e2e/network_setup.sh @@ -0,0 +1,135 @@ +#!/bin/bash + +UP_DOWN=$1 +CH_NAME=$2 + +COMPOSE_FILE=docker-compose.yaml +#COMPOSE_FILE=docker-compose-no-tls.yaml + +function printHelp () { + echo "Usage: ./network_setup " +} + +function validateArgs () { + if [ -z "${UP_DOWN}" ]; then + echo "Option up / down / restart not mentioned" + printHelp + exit 1 + fi + if [ -z "${CH_NAME}" ]; then + echo "setting to default channel 'mychannel'" + CH_NAME=mychannel + fi +} + +function clearContainers () { + CONTAINER_IDS=$(docker ps -aq) + if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" = " " ]; then + echo "---- No containers available for deletion ----" + else + docker rm -f $CONTAINER_IDS + fi +} + +function removeUnwantedImages() { + DOCKER_IMAGE_IDS=$(docker images | grep "dev\|none\|test-vp\|peer[0-9]-" | awk '{print $3}') + if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" = " " ]; then + echo "---- No images available for deletion ----" + else + docker rmi -f $DOCKER_IMAGE_IDS + fi +} + +function replacePrivateKey () { + ARCH=`uname -s | grep Darwin` + if [ "$ARCH" == "Darwin" ] + then + OPTS="-it" + else + OPTS="-i" + fi + + cp docker-compose-template.yaml docker-compose.yaml + PRIV_KEY=$(ls crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/keystore/) + sed $OPTS "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 $OPTS "s/PEER0_ORG1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml + PRIV_KEY=$(ls crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/keystore/) + sed $OPTS "s/PEER1_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 $OPTS "s/PEER0_ORG2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml + PRIV_KEY=$(ls crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/keystore/) + sed $OPTS "s/PEER1_ORG2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose.yaml +} + +function generateArtifacts () { + os_arch=$(echo "$(uname -s)-$(uname -m)" | awk '{print tolower($0)}') + if [ "$(uname -m)" = "x86_64" ]; then + os_arch=$(echo "$(uname -s)-amd64" | awk '{print tolower($0)}') + fi + + echo "OS_ARCH "$os_arch + echo + echo "##########################################################" + echo "############## Generate certificates #####################" + echo "##########################################################" + ./../../$os_arch/bin/cryptogen generate --config=./crypto-config.yaml + echo + echo + + replacePrivateKey + + echo "##########################################################" + echo "######### Generating Orderer Genesis block ##############" + echo "##########################################################" + export ORDERER_CFG_PATH=$PWD + ./../../$os_arch/bin/configtxgen -profile TwoOrgs -outputBlock orderer.block + echo + echo + + echo "#################################################################" + echo "### Generating channel configuration transaction 'channel.tx' ###" + echo "#################################################################" + ./../../$os_arch/bin/configtxgen -profile TwoOrgs -outputCreateChannelTx channel.tx -channelID $CH_NAME + echo + echo + +} + +function networkUp () { + #Lets generate all the artifacts which includes org certs, orderer.block, + # channel configuration transaction and Also generate a docker-compose file + generateArtifacts + export ARCH_TAG=$(uname -m) + CHANNEL_NAME=$CH_NAME docker-compose -f $COMPOSE_FILE up -d 2>&1 + if [ $? -ne 0 ]; then + echo "ERROR !!!! Unable to pull the images " + exit 1 + fi + docker logs -f cli +} + +function networkDown () { + docker-compose -f $COMPOSE_FILE down + #Cleanup the chaincode containers + clearContainers + #Cleanup images + removeUnwantedImages + # remove orderer block and channel transaction + rm -rf orderer.block channel.tx crypto-config +} + +validateArgs + +#Create the network using docker compose +if [ "${UP_DOWN}" == "up" ]; then + networkUp +elif [ "${UP_DOWN}" == "down" ]; then ## Clear the network + networkDown +elif [ "${UP_DOWN}" == "restart" ]; then ## Restart the network + networkDown + networkUp +else + printHelp + exit 1 +fi diff --git a/examples/dchackfest/samples/e2e/peer-base/peer-base-no-tls.yaml b/examples/dchackfest/samples/e2e/peer-base/peer-base-no-tls.yaml new file mode 100644 index 00000000000..a1f24db4340 --- /dev/null +++ b/examples/dchackfest/samples/e2e/peer-base/peer-base-no-tls.yaml @@ -0,0 +1,17 @@ +version: '2' +services: + peer-base: + image: hyperledger/fabric-peer:${ARCH_TAG}-1.0.0-alpha + environment: + - CORE_PEER_ADDRESSAUTODETECT=true + - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock + - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=e2e_default + - CORE_LOGGING_LEVEL=ERROR + #- CORE_LOGGING_LEVEL=DEBUG + - CORE_PEER_TLS_ENABLED=false + - CORE_PEER_ENDORSER_ENABLED=true + - CORE_PEER_GOSSIP_ORGLEADER=false + - CORE_PEER_GOSSIP_USELEADERELECTION=true + - CORE_PEER_PROFILE_ENABLED=true + working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer + command: peer node start --peer-defaultchain=false diff --git a/examples/dchackfest/samples/e2e/peer-base/peer-base.yaml b/examples/dchackfest/samples/e2e/peer-base/peer-base.yaml new file mode 100644 index 00000000000..bacd8b05cf1 --- /dev/null +++ b/examples/dchackfest/samples/e2e/peer-base/peer-base.yaml @@ -0,0 +1,22 @@ +version: '2' +services: + peer-base: + image: hyperledger/fabric-peer:${ARCH_TAG}-1.0.0-alpha + environment: + - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock + # the following setting starts chaincode containers on the same + # bridge network as the peers + # https://docs.docker.com/compose/networking/ + - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=e2e_default + #- CORE_LOGGING_LEVEL=ERROR + - CORE_LOGGING_LEVEL=DEBUG + - CORE_PEER_TLS_ENABLED=true + - CORE_PEER_ENDORSER_ENABLED=true + - CORE_PEER_GOSSIP_USELEADERELECTION=true + - CORE_PEER_GOSSIP_ORGLEADER=false + # The following setting skips the gossip handshake since we are + # are not doing mutual TLS + - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true + - CORE_PEER_PROFILE_ENABLED=true + working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer + command: peer node start --peer-defaultchain=false diff --git a/examples/dchackfest/samples/e2e/scripts/script.sh b/examples/dchackfest/samples/e2e/scripts/script.sh new file mode 100755 index 00000000000..a47a878d058 --- /dev/null +++ b/examples/dchackfest/samples/e2e/scripts/script.sh @@ -0,0 +1,209 @@ +#!/bin/bash + +CHANNEL_NAME="$1" +: ${CHANNEL_NAME:="mychannel"} +: ${TIMEOUT:="60"} +COUNTER=0 +MAX_RETRY=5 +ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/cacerts/example.com-cert.pem + +echo "Channel name : "$CHANNEL_NAME + + +verifyResult () { + if [ $1 -ne 0 ] ; then + echo "!!!!!!!!!!!!!!! "$2" !!!!!!!!!!!!!!!!" + echo "================== ERROR !!! FAILED to execute End-2-End Scenario ==================" + echo + exit 1 + fi +} + +setGlobals () { + + if [ $1 -eq 0 -o $1 -eq 1 ] ; then + CORE_PEER_LOCALMSPID="Org0MSP" + if [ $1 -eq 0 ]; then + CORE_PEER_ADDRESS=peer0.org1.example.com:7051 + 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 + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com + else + CORE_PEER_ADDRESS=peer1.org1.example.com:7051 + CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/cacerts/org1.example.com-cert.pem + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com + fi + else + CORE_PEER_LOCALMSPID="Org1MSP" + if [ $1 -eq 2 ]; then + CORE_PEER_ADDRESS=peer0.org2.example.com:7051 + CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/cacerts/org2.example.com-cert.pem + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com + else + CORE_PEER_ADDRESS=peer1.org2.example.com:7051 + CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/cacerts/org2.example.com-cert.pem + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com + fi + + fi + env |grep CORE +} + +createChannel() { + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com + CORE_PEER_LOCALMSPID="OrdererMSP" + env |grep CORE + + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f channel.tx >&log.txt + else + peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt + fi + res=$? + cat log.txt + verifyResult $res "Channel creation failed" + echo "===================== Channel \"$CHANNEL_NAME\" is created successfully ===================== " + echo +} + +## Sometimes Join takes time hence RETRY atleast for 5 times +joinWithRetry () { + peer channel join -b $CHANNEL_NAME.block >&log.txt + res=$? + cat log.txt + if [ $res -ne 0 -a $COUNTER -lt $MAX_RETRY ]; then + COUNTER=` expr $COUNTER + 1` + echo "PEER$1 failed to join the channel, Retry after 2 seconds" + sleep 2 + joinWithRetry $1 + else + COUNTER=0 + fi + verifyResult $res "After $MAX_RETRY attempts, PEER$ch has failed to Join the Channel" +} + +joinChannel () { + for ch in 0 1 2 3; do + setGlobals $ch + joinWithRetry $ch + echo "===================== PEER$ch joined on the channel \"$CHANNEL_NAME\" ===================== " + sleep 2 + echo + done +} + +installChaincode () { + PEER=$1 + setGlobals $PEER + peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 >&log.txt + res=$? + cat log.txt + verifyResult $res "Chaincode installation on remote peer PEER$PEER has Failed" + echo "===================== Chaincode is installed on remote peer PEER$PEER ===================== " + echo +} + +instantiateChaincode () { + PEER=$1 + setGlobals $PEER + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org0MSP.member','Org1MSP.member')" >&log.txt + else + peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org0MSP.member','Org1MSP.member')" >&log.txt + fi + res=$? + cat log.txt + verifyResult $res "Chaincode instantiation on PEER$PEER on channel '$CHANNEL_NAME' failed" + echo "===================== Chaincode Instantiation on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== " + echo +} + +chaincodeQuery () { + PEER=$1 + echo "===================== Querying on PEER$PEER on channel '$CHANNEL_NAME'... ===================== " + setGlobals $PEER + local rc=1 + local starttime=$(date +%s) + + # continue to poll + # we either get a successful response, or reach TIMEOUT + while test "$(($(date +%s)-starttime))" -lt "$TIMEOUT" -a $rc -ne 0 + do + sleep 3 + echo "Attempting to Query PEER$PEER ...$(($(date +%s)-starttime)) secs" + peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt + test $? -eq 0 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}') + test "$VALUE" = "$2" && let rc=0 + done + echo + cat log.txt + if test $rc -eq 0 ; then + echo "===================== Query on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== " + else + echo "!!!!!!!!!!!!!!! Query result on PEER$PEER is INVALID !!!!!!!!!!!!!!!!" + echo "================== ERROR !!! FAILED to execute End-2-End Scenario ==================" + echo + exit 1 + fi +} + +chaincodeInvoke () { + PEER=$1 + setGlobals $PEER + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt + else + peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt + fi + res=$? + cat log.txt + verifyResult $res "Invoke execution on PEER$PEER failed " + echo "===================== Invoke transaction on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== " + echo +} + +#downloadChaincodes () { +# CURRENT_DIR=$PWD +# mkdir -p /opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02/ +# cd /opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02/ +# wget https://raw.githubusercontent.com/hyperledger/fabric/master/examples/chaincode/go/chaincode_example02/chaincode_example02.go + +# mkdir -p /opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go/marbles02/ +# cd /opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go/marbles02/ +# wget https://raw.githubusercontent.com/hyperledger/fabric/master/examples/chaincode/go/marbles02/marbles_chaincode.go +# cd $CURRENT_DIR +#} + +#downloadChaincodes + +## Create channel +createChannel + +## Join all the peers to the channel +joinChannel + + +## Install chaincode on Peer0/Org0 and Peer2/Org1 +installChaincode 0 +installChaincode 2 + +#Instantiate chaincode on Peer2/Org1 +echo "Instantiating chaincode on Peer2/Org1 ..." +instantiateChaincode 2 + +#Query on chaincode on Peer0/Org0 +chaincodeQuery 0 100 + +#Invoke on chaincode on Peer0/Org0 +echo "send Invoke transaction on Peer0/Org0 ..." +chaincodeInvoke 0 + +## Install chaincode on Peer3/Org1 +installChaincode 3 + +#Query on chaincode on Peer3/Org1, check if the result is 90 +chaincodeQuery 3 90 + +echo +echo "===================== All GOOD, End-2-End execution completed ===================== " +echo +exit 0