mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-19 00:15:08 +00:00
Merge f65f493b98 into f05a132586
This commit is contained in:
commit
190a1b7173
55 changed files with 1355 additions and 321 deletions
23
.gitignore
vendored
23
.gitignore
vendored
|
|
@ -6,27 +6,6 @@
|
|||
.*.sw*
|
||||
# installed platform-specific binaries
|
||||
/bin
|
||||
/config
|
||||
.DS_Store
|
||||
.project
|
||||
|
||||
first-network/channel-artifacts/*.tx
|
||||
first-network/channel-artifacts/*.block
|
||||
first-network/crypto-config/*
|
||||
first-network/docker-compose-e2e.yaml
|
||||
first-network/ledgers
|
||||
first-network/ledgers-backup
|
||||
|
||||
chaincode-docker-devmode/myc.block
|
||||
chaincode-docker-devmode/chaincode/sacc/sacc
|
||||
chaincode-docker-devmode/chaincode/chaincode_example02/chaincode_example02
|
||||
|
||||
# fabric sdk node modules
|
||||
fabcar/node_modules/
|
||||
fabcar/package-lock.json
|
||||
fabcar/hfc-key-store/
|
||||
|
||||
# balance transfer sample
|
||||
balance-transfer/.DS_Store
|
||||
balance-transfer/node_modules/*
|
||||
balance-transfer/package-lock.json
|
||||
balance-transfer/fabric-client-kv-org*
|
||||
|
|
|
|||
5
.gitreview
Normal file
5
.gitreview
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
[gerrit]
|
||||
host=gerrit.hyperledger.org
|
||||
port=29418
|
||||
project=fabric-samples
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
## Hyperledger Fabric Samples
|
||||
Code of Conduct Guidelines
|
||||
==========================
|
||||
|
||||
fabric-preload.sh will preload all of the requisite docker images for Hyperledger Fabric and tag them
|
||||
with the 'latest' tag. Optionally, specify a specific version (e.g. 1.0.1). Default version is 1.0.0.
|
||||
Please review the Hyperledger [Code of
|
||||
Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct)
|
||||
before participating. It is important that we keep things civil.
|
||||
|
||||
```bash
|
||||
./fabric-preload.sh [version]
|
||||
```
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
|
||||
18
CONTRIBUTING.md
Normal file
18
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
## Contributing
|
||||
|
||||
We welcome contributions to the Hyperledger Fabric Project in many forms, and
|
||||
there's always plenty to do!
|
||||
|
||||
Please visit the
|
||||
[contributors guide](http://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html) in the
|
||||
docs to learn how to make contributions to this exciting project.
|
||||
|
||||
## Code of Conduct Guidelines <a name="conduct"></a>
|
||||
|
||||
See our [Code of Conduct Guidelines](../blob/master/CODE_OF_CONDUCT.md).
|
||||
|
||||
## Maintainers <a name="maintainers"></a>
|
||||
|
||||
Should you have any questions or concerns, please reach out to one of the project's [Maintainers](../blob/master/MAINTAINERS.md).
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
|
||||
24
README.md
24
README.md
|
|
@ -1,7 +1,27 @@
|
|||
[//]: # (SPDX-License-Identifier: CC-BY-4.0)
|
||||
|
||||
## Hyperledger Fabric Samples
|
||||
|
||||
Please visit the [installation instructions](http://hyperledger-fabric.readthedocs.io/en/latest/samples.html).
|
||||
Please visit the [installation instructions](http://hyperledger-fabric.readthedocs.io/en/latest/install.html)
|
||||
to ensure you have the correct prerequisites installed. Please use the
|
||||
version of the documentation that matches the version of the software you
|
||||
intend to use to ensure alignment.
|
||||
|
||||
## Download Binaries and Docker Images
|
||||
|
||||
The [`scripts/bootstrap.sh`](https://github.com/hyperledger/fabric-samples/blob/release-1.1/scripts/bootstrap.sh)
|
||||
script will preload all of the requisite docker
|
||||
images for Hyperledger Fabric and tag them with the 'latest' tag. Optionally,
|
||||
specify a version for fabric, fabric-ca and thirdparty images. Default versions
|
||||
are 1.1.0, 1.1.0 and 0.4.7 respectively.
|
||||
|
||||
```bash
|
||||
./scripts/bootstrap.sh [version] [ca version] [thirdparty_version]
|
||||
```
|
||||
|
||||
## License <a name="license"></a>
|
||||
|
||||
Hyperledger Project source code files are made available under the Apache License, Version 2.0 (Apache-2.0), located in the [LICENSE](LICENSE) file. Hyperledger Project documentation files are made available under the Creative Commons Attribution 4.0 International License (CC-BY-4.0), available at http://creativecommons.org/licenses/by/4.0/.
|
||||
Hyperledger Project source code files are made available under the Apache
|
||||
License, Version 2.0 (Apache-2.0), located in the [LICENSE](LICENSE) file.
|
||||
Hyperledger Project documentation files are made available under the Creative
|
||||
Commons Attribution 4.0 International License (CC-BY-4.0), available at http://creativecommons.org/licenses/by/4.0/.
|
||||
|
|
|
|||
3
balance-transfer/.gitignore
vendored
Normal file
3
balance-transfer/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/node_modules/*
|
||||
/package-lock.json
|
||||
/fabric-client-kv-org*
|
||||
|
|
@ -4,34 +4,6 @@
|
|||
#
|
||||
|
||||
---
|
||||
################################################################################
|
||||
#
|
||||
# Profile
|
||||
#
|
||||
# - Different configuration profiles may be encoded here to be specified
|
||||
# as parameters to the configtxgen tool
|
||||
#
|
||||
################################################################################
|
||||
Profiles:
|
||||
|
||||
TwoOrgsOrdererGenesis:
|
||||
Orderer:
|
||||
<<: *OrdererDefaults
|
||||
Organizations:
|
||||
- *OrdererOrg
|
||||
Consortiums:
|
||||
SampleConsortium:
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
TwoOrgsChannel:
|
||||
Consortium: SampleConsortium
|
||||
Application:
|
||||
<<: *ApplicationDefaults
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Section: Organizations
|
||||
|
|
@ -89,6 +61,20 @@ Organizations:
|
|||
- Host: peer0.org2.example.com
|
||||
Port: 7051
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# 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:
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Orderer
|
||||
|
|
@ -136,14 +122,28 @@ Orderer: &OrdererDefaults
|
|||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Application
|
||||
# Profile
|
||||
#
|
||||
# - This section defines the values to encode into a config transaction or
|
||||
# genesis block for application related parameters
|
||||
# - Different configuration profiles may be encoded here to be specified
|
||||
# as parameters to the configtxgen tool
|
||||
#
|
||||
################################################################################
|
||||
Application: &ApplicationDefaults
|
||||
Profiles:
|
||||
|
||||
# Organizations is the list of orgs which are defined as participants on
|
||||
# the application side of the network
|
||||
Organizations:
|
||||
TwoOrgsOrdererGenesis:
|
||||
Orderer:
|
||||
<<: *OrdererDefaults
|
||||
Organizations:
|
||||
- *OrdererOrg
|
||||
Consortiums:
|
||||
SampleConsortium:
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
TwoOrgsChannel:
|
||||
Consortium: SampleConsortium
|
||||
Application:
|
||||
<<: *ApplicationDefaults
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ orderers:
|
|||
# they will be passed in as-is to gRPC client constructor
|
||||
grpcOptions:
|
||||
ssl-target-name-override: orderer.example.com
|
||||
grpc-max-send-message-length: 15
|
||||
|
||||
tlsCACerts:
|
||||
path: artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ orderers:
|
|||
# they will be passed in as-is to gRPC client constructor
|
||||
grpcOptions:
|
||||
ssl-target-name-override: orderer.example.com
|
||||
grpc-max-send-message-length: 15
|
||||
|
||||
tlsCACerts:
|
||||
path: artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ TRX_ID=$(curl -s -X POST \
|
|||
"fcn":"move",
|
||||
"args":["a","b","10"]
|
||||
}')
|
||||
echo "Transacton ID is $TRX_ID"
|
||||
echo "Transaction ID is $TRX_ID"
|
||||
echo
|
||||
echo
|
||||
|
||||
|
|
|
|||
2
balance-transfer/typescript/.gitignore
vendored
2
balance-transfer/typescript/.gitignore
vendored
|
|
@ -1,4 +1,4 @@
|
|||
node_modules
|
||||
package-lock.json
|
||||
dist
|
||||
types/fabric-client
|
||||
types/fabric-client
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ TRX_ID=$(curl -s -X POST \
|
|||
"fcn":"move",
|
||||
"args":["a","b","10"]
|
||||
}')
|
||||
echo "Transacton ID is $TRX_ID"
|
||||
echo "Transaction ID is $TRX_ID"
|
||||
echo
|
||||
echo
|
||||
|
||||
|
|
|
|||
|
|
@ -4,32 +4,6 @@
|
|||
#
|
||||
|
||||
---
|
||||
################################################################################
|
||||
#
|
||||
# Profile
|
||||
#
|
||||
# - Different configuration profiles may be encoded here to be specified
|
||||
# as parameters to the configtxgen tool
|
||||
#
|
||||
################################################################################
|
||||
Profiles:
|
||||
|
||||
OneOrgOrdererGenesis:
|
||||
Orderer:
|
||||
<<: *OrdererDefaults
|
||||
Organizations:
|
||||
- *OrdererOrg
|
||||
Consortiums:
|
||||
SampleConsortium:
|
||||
Organizations:
|
||||
- *Org1
|
||||
OneOrgChannel:
|
||||
Consortium: SampleConsortium
|
||||
Application:
|
||||
<<: *ApplicationDefaults
|
||||
Organizations:
|
||||
- *Org1
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Section: Organizations
|
||||
|
|
@ -70,6 +44,20 @@ Organizations:
|
|||
- Host: peer0.org1.example.com
|
||||
Port: 7051
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# 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:
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Orderer
|
||||
|
|
@ -117,14 +105,27 @@ Orderer: &OrdererDefaults
|
|||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Application
|
||||
# Profile
|
||||
#
|
||||
# - This section defines the values to encode into a config transaction or
|
||||
# genesis block for application related parameters
|
||||
# - Different configuration profiles may be encoded here to be specified
|
||||
# as parameters to the configtxgen tool
|
||||
#
|
||||
################################################################################
|
||||
Application: &ApplicationDefaults
|
||||
Profiles:
|
||||
|
||||
OneOrgOrdererGenesis:
|
||||
Orderer:
|
||||
<<: *OrdererDefaults
|
||||
Organizations:
|
||||
- *OrdererOrg
|
||||
Consortiums:
|
||||
SampleConsortium:
|
||||
Organizations:
|
||||
- *Org1
|
||||
OneOrgChannel:
|
||||
Consortium: SampleConsortium
|
||||
Application:
|
||||
<<: *ApplicationDefaults
|
||||
Organizations:
|
||||
- *Org1
|
||||
|
||||
# Organizations is the list of orgs which are defined as participants on
|
||||
# the application side of the network
|
||||
Organizations:
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ services:
|
|||
- FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/4239aa0dcd76daeeb8ba0cda701851d14504d31aad1b2ddddbac6a57365e497c_sk
|
||||
ports:
|
||||
- "7054:7054"
|
||||
command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
|
||||
command: sh -c 'fabric-ca-server start -b admin:adminpw'
|
||||
volumes:
|
||||
- ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
|
||||
container_name: ca.example.com
|
||||
|
|
@ -29,7 +29,7 @@ services:
|
|||
container_name: orderer.example.com
|
||||
image: hyperledger/fabric-orderer
|
||||
environment:
|
||||
- ORDERER_GENERAL_LOGLEVEL=debug
|
||||
- ORDERER_GENERAL_LOGLEVEL=info
|
||||
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
|
||||
- ORDERER_GENERAL_GENESISMETHOD=file
|
||||
- ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block
|
||||
|
|
@ -52,8 +52,8 @@ services:
|
|||
environment:
|
||||
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
|
||||
- CORE_PEER_ID=peer0.org1.example.com
|
||||
- CORE_LOGGING_PEER=debug
|
||||
- CORE_CHAINCODE_LOGGING_LEVEL=DEBUG
|
||||
- CORE_LOGGING_PEER=info
|
||||
- CORE_CHAINCODE_LOGGING_LEVEL=info
|
||||
- CORE_PEER_LOCALMSPID=Org1MSP
|
||||
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
|
||||
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
|
||||
|
|
@ -105,7 +105,7 @@ services:
|
|||
environment:
|
||||
- GOPATH=/opt/gopath
|
||||
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
|
||||
- CORE_LOGGING_LEVEL=DEBUG
|
||||
- CORE_LOGGING_LEVEL=info
|
||||
- CORE_PEER_ID=cli
|
||||
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
|
||||
- CORE_PEER_LOCALMSPID=Org1MSP
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@ rm -rf ~/.hfc-key-store/*
|
|||
|
||||
# copy peer admin credentials into the keyValStore
|
||||
mkdir -p ~/.hfc-key-store
|
||||
cp creds/* ~/.hfc-key-store
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ docker-compose -f docker-compose.yml kill && docker-compose -f docker-compose.ym
|
|||
rm -f ~/.hfc-key-store/*
|
||||
|
||||
# remove chaincode docker images
|
||||
docker rm $(docker ps -aq)
|
||||
docker rmi $(docker images dev-* -q)
|
||||
|
||||
# Your system is now clean
|
||||
|
|
|
|||
3
chaincode-docker-devmode/.gitignore
vendored
Normal file
3
chaincode-docker-devmode/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/myc.block
|
||||
/chaincode/sacc/sacc
|
||||
/chaincode/chaincode_example02/chaincode_example02
|
||||
|
|
@ -13,7 +13,7 @@ of compiling chaincode and driving calls.
|
|||
Install Fabric Samples
|
||||
----------------------
|
||||
|
||||
If you haven't already done so, please install the doc [samples](http://hyperledger-fabric.readthedocs.io/en/latest/samples.html).
|
||||
If you haven't already done so, please `install samples <http://hyperledger-fabric.readthedocs.io/en/latest/install.html>`_.
|
||||
|
||||
Navigate to the ``chaincode-docker-devmode`` directory of the ``fabric-samples``
|
||||
clone:
|
||||
|
|
@ -27,7 +27,7 @@ Download docker images
|
|||
|
||||
We need four docker images in order for "dev mode" to run against the supplied
|
||||
docker compose script. If you installed the ``fabric-samples`` repo clone and
|
||||
followed the instructions to [download-platform-specific-binaries](http://hyperledger-fabric.readthedocs.io/en/latest/samples.html#download-platform-specific-binaries), then
|
||||
followed the instructions to `install samples, binaries and docker images <http://hyperledger-fabric.readthedocs.io/en/latest/install.html>`_, then
|
||||
you should have the necessary Docker images installed locally.
|
||||
|
||||
.. note:: If you choose to manually pull the images then you must retag them as
|
||||
|
|
@ -49,7 +49,7 @@ should see something similar to following:
|
|||
hyperledger/fabric-ccenv latest 82489d1c11e8 9 days ago 1.35 GB
|
||||
hyperledger/fabric-ccenv x86_64-1.1.0-preview 82489d1c11e8 9 days ago 1.35 GB
|
||||
|
||||
.. note:: If you retrieved the images through the [download-platform-specific-binaries](http://hyperledger-fabric.readthedocs.io/en/latest/samples.html#download-platform-specific-binaries),
|
||||
.. note:: If you retrieved the images through the `install samples, binaries and docker images <http://hyperledger-fabric.readthedocs.io/en/latest/install.html>`_,
|
||||
then you will see additional images listed. However, we are only concerned with
|
||||
these four.
|
||||
|
||||
|
|
|
|||
16
chaincode/marbles02_private/collections_config.json
Normal file
16
chaincode/marbles02_private/collections_config.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"name": "collectionMarbles",
|
||||
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
|
||||
"requiredPeerCount": 0,
|
||||
"maxPeerCount": 3,
|
||||
"blockToLive":1000000
|
||||
},
|
||||
{
|
||||
"name": "collectionMarblePrivateDetails",
|
||||
"policy": "OR('Org1MSP.member')",
|
||||
"requiredPeerCount": 0,
|
||||
"maxPeerCount": 3,
|
||||
"blockToLive":3
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
|
||||
634
chaincode/marbles02_private/go/marbles_chaincode_private.go
Normal file
634
chaincode/marbles02_private/go/marbles_chaincode_private.go
Normal file
|
|
@ -0,0 +1,634 @@
|
|||
/*
|
||||
Copyright IBM Corp. All Rights Reserved.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// ====CHAINCODE EXECUTION SAMPLES (CLI) ==================
|
||||
|
||||
// ==== Invoke marbles ====
|
||||
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble","marble1","blue","35","tom","99"]}'
|
||||
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble","marble2","red","50","tom","102"]}'
|
||||
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble","marble3","blue","70","tom","103"]}'
|
||||
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["transferMarble","marble2","jerry"]}'
|
||||
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["delete","marble1"]}'
|
||||
|
||||
// ==== Query marbles ====
|
||||
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarble","marble1"]}'
|
||||
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
|
||||
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["getMarblesByRange","marble1","marble3"]}'
|
||||
|
||||
// Rich Query (Only supported if CouchDB is used as state database):
|
||||
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["queryMarblesByOwner","tom"]}'
|
||||
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}'
|
||||
|
||||
// INDEXES TO SUPPORT COUCHDB RICH QUERIES
|
||||
//
|
||||
// Indexes in CouchDB are required in order to make JSON queries efficient and are required for
|
||||
// any JSON query with a sort. As of Hyperledger Fabric 1.1, indexes may be packaged alongside
|
||||
// chaincode in a META-INF/statedb/couchdb/indexes directory. Or for indexes on private data
|
||||
// collections, in a META-INF/statedb/couchdb/collections/<collection_name>/indexes directory.
|
||||
// Each index must be defined in its own text file with extension *.json with the index
|
||||
// definition formatted in JSON following the CouchDB index JSON syntax as documented at:
|
||||
// http://docs.couchdb.org/en/2.1.1/api/database/find.html#db-index
|
||||
//
|
||||
// This marbles02_private example chaincode demonstrates a packaged index which you
|
||||
// can find in META-INF/statedb/couchdb/collection/collectionMarbles/indexes/indexOwner.json.
|
||||
// For deployment of chaincode to production environments, it is recommended
|
||||
// to define any indexes alongside chaincode so that the chaincode and supporting indexes
|
||||
// are deployed automatically as a unit, once the chaincode has been installed on a peer and
|
||||
// instantiated on a channel. See Hyperledger Fabric documentation for more details.
|
||||
//
|
||||
// If you have access to the your peer's CouchDB state database in a development environment,
|
||||
// you may want to iteratively test various indexes in support of your chaincode queries. You
|
||||
// can use the CouchDB Fauxton interface or a command line curl utility to create and update
|
||||
// indexes. Then once you finalize an index, include the index definition alongside your
|
||||
// chaincode in the META-INF/statedb/couchdb/indexes directory or
|
||||
// META-INF/statedb/couchdb/collections/<collection_name>/indexes directory, for packaging
|
||||
// and deployment to managed environments.
|
||||
//
|
||||
// In the examples below you can find index definitions that support marbles02_private
|
||||
// chaincode queries, along with the syntax that you can use in development environments
|
||||
// to create the indexes in the CouchDB Fauxton interface.
|
||||
//
|
||||
|
||||
//Example hostname:port configurations to access CouchDB.
|
||||
//
|
||||
//To access CouchDB docker container from within another docker container or from vagrant environments:
|
||||
// http://couchdb:5984/
|
||||
//
|
||||
//Inside couchdb docker container
|
||||
// http://127.0.0.1:5984/
|
||||
|
||||
// Index for docType, owner.
|
||||
// Note that docType and owner fields must be prefixed with the "data" wrapper
|
||||
//
|
||||
// Index definition for use with Fauxton interface
|
||||
// {"index":{"fields":["data.docType","data.owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
|
||||
|
||||
// Index for docType, owner, size (descending order).
|
||||
// Note that docType, owner and size fields must be prefixed with the "data" wrapper
|
||||
//
|
||||
// Index definition for use with Fauxton interface
|
||||
// {"index":{"fields":[{"data.size":"desc"},{"data.docType":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortDesc","type":"json"}
|
||||
|
||||
// Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database):
|
||||
// peer chaincode query -C mychannel -n marblesp -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 mychannel -n marblesp -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"
|
||||
|
||||
"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"`
|
||||
}
|
||||
|
||||
type marblePrivateDetails 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
|
||||
Price int `json:"price"`
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// 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
|
||||
switch function {
|
||||
case "initMarble":
|
||||
//create a new marble
|
||||
return t.initMarble(stub, args)
|
||||
case "readMarble":
|
||||
//read a marble
|
||||
return t.readMarble(stub, args)
|
||||
case "readMarblePrivateDetails":
|
||||
//read a marble private details
|
||||
return t.readMarblePrivateDetails(stub, args)
|
||||
case "transferMarble":
|
||||
//change owner of a specific marble
|
||||
return t.transferMarble(stub, args)
|
||||
case "transferMarblesBasedOnColor":
|
||||
//transfer all marbles of a certain color
|
||||
return t.transferMarblesBasedOnColor(stub, args)
|
||||
case "delete":
|
||||
//delete a marble
|
||||
return t.delete(stub, args)
|
||||
case "queryMarblesByOwner":
|
||||
//find marbles for owner X using rich query
|
||||
return t.queryMarblesByOwner(stub, args)
|
||||
case "queryMarbles":
|
||||
//find marbles based on an ad hoc rich query
|
||||
return t.queryMarbles(stub, args)
|
||||
case "getMarblesByRange":
|
||||
//get marbles based on range query
|
||||
return t.getMarblesByRange(stub, args)
|
||||
default:
|
||||
//error
|
||||
fmt.Println("invoke did not find func: " + function)
|
||||
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-name 1-color 2-size 3-owner 4-price
|
||||
// "asdf", "blue", "35", "bob", "99"
|
||||
if len(args) != 5 {
|
||||
return shim.Error("Incorrect number of arguments. Expecting 5")
|
||||
}
|
||||
|
||||
// ==== 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")
|
||||
}
|
||||
if len(args[4]) == 0 {
|
||||
return shim.Error("5th 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")
|
||||
}
|
||||
price, err := strconv.Atoi(args[4])
|
||||
if err != nil {
|
||||
return shim.Error("5th argument must be a numeric string")
|
||||
}
|
||||
|
||||
// ==== Check if marble already exists ====
|
||||
marbleAsBytes, err := stub.GetPrivateData("collectionMarbles", 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.PutPrivateData("collectionMarbles", marbleName, marbleJSONasBytes)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
// ==== Save marble private details ====
|
||||
objectType = "marblePrivateDetails"
|
||||
marblePrivateDetails := &marblePrivateDetails{objectType, marbleName, price}
|
||||
marblePrivateDetailsBytes, err := json.Marshal(marblePrivateDetails)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = stub.PutPrivateData("collectionMarblePrivateDetails", marbleName, marblePrivateDetailsBytes)
|
||||
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.PutPrivateData("collectionMarbles", 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.GetPrivateData("collectionMarbles", 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)
|
||||
}
|
||||
|
||||
// ===============================================
|
||||
// readMarblereadMarblePrivateDetails - read a marble private details from chaincode state
|
||||
// ===============================================
|
||||
func (t *SimpleChaincode) readMarblePrivateDetails(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.GetPrivateData("collectionMarblePrivateDetails", name) //get the marble private details from chaincode state
|
||||
if err != nil {
|
||||
jsonResp = "{\"Error\":\"Failed to get private details for " + name + ": " + err.Error() + "\"}"
|
||||
return shim.Error(jsonResp)
|
||||
} else if valAsbytes == nil {
|
||||
jsonResp = "{\"Error\":\"Marble private details 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.GetPrivateData("collectionMarbles", 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.DelPrivateData("collectionMarbles", 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.DelPrivateData("collectionMarbles", colorNameIndexKey)
|
||||
if err != nil {
|
||||
return shim.Error("Failed to delete state:" + err.Error())
|
||||
}
|
||||
|
||||
// Delete private details of marble
|
||||
err = stub.DelPrivateData("collectionMarblePrivateDetails", marbleName)
|
||||
if err != nil {
|
||||
return shim.Error(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.GetPrivateData("collectionMarbles", 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.PutPrivateData("collectionMarbles", 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.GetPrivateDataByRange("collectionMarbles", 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.GetPrivateDataByPartialCompositeKey("collectionMarbles", "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.GetPrivateDataQueryResult("collectionMarbles", 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
|
||||
}
|
||||
3
fabcar/.gitignore
vendored
Normal file
3
fabcar/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/node_modules/
|
||||
/package-lock.json
|
||||
/hfc-key-store/
|
||||
|
|
@ -148,7 +148,7 @@ Fabric_Client.newDefaultKeyValueStore({ path: store_path
|
|||
if (results && results[0] && results[0].status === 'SUCCESS') {
|
||||
console.log('Successfully sent transaction to the orderer.');
|
||||
} else {
|
||||
console.error('Failed to order the transaction. Error code: ' + response.status);
|
||||
console.error('Failed to order the transaction. Error code: ' + results[0].status);
|
||||
}
|
||||
|
||||
if(results && results[1] && results[1].event_status === 'VALID') {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ Fabric_Client.newDefaultKeyValueStore({ path: store_path
|
|||
|
||||
return fabric_client.setUserContext(member_user);
|
||||
}).then(()=>{
|
||||
console.log('User1 was successfully registered and enrolled and is ready to intreact with the fabric network');
|
||||
console.log('User1 was successfully registered and enrolled and is ready to interact with the fabric network');
|
||||
|
||||
}).catch((err) => {
|
||||
console.error('Failed to register: ' + err);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ with a value of "true". Note further that the chaincode used by this sample
|
|||
requires this attribute be included in the certificate of the identity that
|
||||
invokes its Init function. See the chaincode at *fabric-samples/chaincode/abac/abac.go*).
|
||||
For more information on Attribute-Based Access Control (ABAC), see
|
||||
https://github.com/hyperledger/fabric/tree/release/core/chaincode/lib/cid/README.md.
|
||||
https://github.com/hyperledger/fabric/blob/master/core/chaincode/lib/cid/README.md.
|
||||
|
||||
4. The orderer and peer containers are started. The naming of these containers
|
||||
is straight-forward as is their log files in the *data/logs* directory.
|
||||
|
|
|
|||
|
|
@ -157,6 +157,14 @@ function chaincodeQuery {
|
|||
logr "Query of channel '$CHANNEL_NAME' on peer '$PEER_HOST' was successful"
|
||||
set -e
|
||||
return 0
|
||||
else
|
||||
# removed the string "Query Result" from peer chaincode query command result, as a result, have to support both options until the change is merged.
|
||||
VALUE=$(cat log.txt | egrep '^[0-9]+$')
|
||||
if [ $? -eq 0 -a "$VALUE" = "$1" ]; then
|
||||
logr "Query of channel '$CHANNEL_NAME' on peer '$PEER_HOST' was successful"
|
||||
set -e
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
echo -n "."
|
||||
done
|
||||
|
|
@ -238,8 +246,8 @@ function createConfigUpdatePayloadWithCRL {
|
|||
jq .data.data[0].payload.data.config config_block.json > config.json
|
||||
|
||||
# Update crl in the config json
|
||||
crl=$(cat $CORE_PEER_MSPCONFIGPATH/crls/crl*.pem | base64 | tr -d '\n')
|
||||
cat config.json | jq '.channel_group.groups.Application.groups.'"${ORG}"'.values.MSP.value.config.revocation_list = ["'"${crl}"'"]' > updated_config.json
|
||||
CRL=$(cat $CORE_PEER_MSPCONFIGPATH/crls/crl*.pem | base64 | tr -d '\n')
|
||||
cat config.json | jq --arg org "$ORG" --arg crl "$CRL" '.channel_group.groups.Application.groups[$org].values.MSP.value.config.revocation_list = [$crl]' > updated_config.json
|
||||
|
||||
# Create the config diff protobuf
|
||||
curl -X POST --data-binary @config.json $CTLURL/protolator/encode/common.Config > config.pb
|
||||
|
|
@ -266,6 +274,7 @@ function finish {
|
|||
else
|
||||
logr "Tests did not complete successfully; see $RUN_LOGFILE for more details"
|
||||
touch /$RUN_FAIL_FILE
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
6
first-network/.gitignore
vendored
Normal file
6
first-network/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/channel-artifacts/*.tx
|
||||
/channel-artifacts/*.block
|
||||
/crypto-config/*
|
||||
/docker-compose-e2e.yaml
|
||||
/ledgers
|
||||
/ledgers-backup
|
||||
|
|
@ -30,13 +30,13 @@
|
|||
# this may be commented out to resolve installed version of tools if desired
|
||||
export PATH=${PWD}/../bin:${PWD}:$PATH
|
||||
export FABRIC_CFG_PATH=${PWD}
|
||||
export VERBOSE=false
|
||||
|
||||
# Print the usage message
|
||||
function printHelp () {
|
||||
echo "Usage: "
|
||||
echo " byfn.sh up|down|restart|generate|upgrade [-c <channel name>] [-t <timeout>] [-d <delay>] [-f <docker-compose-file>] [-s <dbtype>] [-i <imagetag>]"
|
||||
echo " byfn.sh -h|--help (print this message)"
|
||||
echo " <mode> - one of 'up', 'down', 'restart' or 'generate'"
|
||||
echo " byfn.sh <mode> [-c <channel name>] [-t <timeout>] [-d <delay>] [-f <docker-compose-file>] [-s <dbtype>] [-l <language>] [-i <imagetag>] [-v]"
|
||||
echo " <mode> - one of 'up', 'down', 'restart', 'generate' or 'upgrade'"
|
||||
echo " - 'up' - bring up the network with docker-compose up"
|
||||
echo " - 'down' - clear the network with docker-compose down"
|
||||
echo " - 'restart' - restart the network"
|
||||
|
|
@ -49,6 +49,8 @@ function printHelp () {
|
|||
echo " -s <dbtype> - the database backend to use: goleveldb (default) or couchdb"
|
||||
echo " -l <language> - the chaincode language: golang (default) or node"
|
||||
echo " -i <imagetag> - the tag to be used to launch the network (defaults to \"latest\")"
|
||||
echo " -v - verbose mode"
|
||||
echo " byfn.sh -h (print this message)"
|
||||
echo
|
||||
echo "Typically, one would first generate the required certificates and "
|
||||
echo "genesis block, then bring up the network. e.g.:"
|
||||
|
|
@ -87,7 +89,7 @@ function askProceed () {
|
|||
# Obtain CONTAINER_IDS and remove them
|
||||
# TODO Might want to make this optional - could clear other containers
|
||||
function clearContainers () {
|
||||
CONTAINER_IDS=$(docker ps -aq)
|
||||
CONTAINER_IDS=$(docker ps -a |awk '($2 ~ /dev-peer.*.mycc.*/) {print $1}')
|
||||
if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" == " " ]; then
|
||||
echo "---- No containers available for deletion ----"
|
||||
else
|
||||
|
|
@ -99,7 +101,7 @@ function clearContainers () {
|
|||
# specifically the following images are often left behind:
|
||||
# TODO list generated image naming patterns
|
||||
function removeUnwantedImages() {
|
||||
DOCKER_IMAGE_IDS=$(docker images | grep "dev\|none\|test-vp\|peer[0-9]-" | awk '{print $3}')
|
||||
DOCKER_IMAGE_IDS=$(docker images|awk '($1 ~ /dev-peer.*.mycc.*/) {print $3}')
|
||||
if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then
|
||||
echo "---- No images available for deletion ----"
|
||||
else
|
||||
|
|
@ -163,7 +165,7 @@ function networkUp () {
|
|||
exit 1
|
||||
fi
|
||||
# now run the end to end script
|
||||
docker exec cli scripts/script.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT
|
||||
docker exec cli scripts/script.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Test failed"
|
||||
exit 1
|
||||
|
|
@ -222,7 +224,7 @@ function upgradeNetwork () {
|
|||
docker-compose $COMPOSE_FILES up -d --no-deps $PEER
|
||||
done
|
||||
|
||||
docker exec cli scripts/upgrade_to_v11.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT
|
||||
docker exec cli scripts/upgrade_to_v11.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Test failed"
|
||||
exit 1
|
||||
|
|
@ -232,8 +234,9 @@ function upgradeNetwork () {
|
|||
|
||||
# Tear down running network
|
||||
function networkDown () {
|
||||
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH down --volumes
|
||||
docker-compose -f $COMPOSE_FILE down --volumes
|
||||
# stop org3 containers also in addition to org1 and org2, in case we were running sample to add org3
|
||||
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH -f $COMPOSE_FILE_ORG3 down --volumes --remove-orphans
|
||||
|
||||
# Don't remove the generated artifacts -- note, the ledgers are always removed
|
||||
if [ "$MODE" != "restart" ]; then
|
||||
# Bring down the network, deleting the volumes
|
||||
|
|
@ -440,6 +443,9 @@ CHANNEL_NAME="mychannel"
|
|||
COMPOSE_FILE=docker-compose-cli.yaml
|
||||
#
|
||||
COMPOSE_FILE_COUCH=docker-compose-couch.yaml
|
||||
# org3 docker compose file
|
||||
COMPOSE_FILE_ORG3=docker-compose-org3.yaml
|
||||
#
|
||||
# use golang as the default language for chaincode
|
||||
LANGUAGE=golang
|
||||
# default image tag
|
||||
|
|
@ -449,7 +455,7 @@ if [ "$1" = "-m" ];then # supports old usage, muscle memory is powerful!
|
|||
shift
|
||||
fi
|
||||
MODE=$1;shift
|
||||
# Determine whether starting, stopping, restarting or generating for announce
|
||||
# Determine whether starting, stopping, restarting, generating or upgrading
|
||||
if [ "$MODE" == "up" ]; then
|
||||
EXPMODE="Starting"
|
||||
elif [ "$MODE" == "down" ]; then
|
||||
|
|
@ -465,7 +471,7 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
while getopts "h?m:c:t:d:f:s:l:i:" opt; do
|
||||
while getopts "h?c:t:d:f:s:l:i:v" opt; do
|
||||
case "$opt" in
|
||||
h|\?)
|
||||
printHelp
|
||||
|
|
@ -485,6 +491,8 @@ while getopts "h?m:c:t:d:f:s:l:i:" opt; do
|
|||
;;
|
||||
i) IMAGETAG=`uname -m`"-"$OPTARG
|
||||
;;
|
||||
v) VERBOSE=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
|
|
|||
|
|
@ -4,40 +4,6 @@
|
|||
#
|
||||
|
||||
---
|
||||
################################################################################
|
||||
#
|
||||
# Profile
|
||||
#
|
||||
# - Different configuration profiles may be encoded here to be specified
|
||||
# as parameters to the configtxgen tool
|
||||
#
|
||||
################################################################################
|
||||
Profiles:
|
||||
|
||||
TwoOrgsOrdererGenesis:
|
||||
Capabilities:
|
||||
<<: *ChannelCapabilities
|
||||
Orderer:
|
||||
<<: *OrdererDefaults
|
||||
Organizations:
|
||||
- *OrdererOrg
|
||||
Capabilities:
|
||||
<<: *OrdererCapabilities
|
||||
Consortiums:
|
||||
SampleConsortium:
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
TwoOrgsChannel:
|
||||
Consortium: SampleConsortium
|
||||
Application:
|
||||
<<: *ApplicationDefaults
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
Capabilities:
|
||||
<<: *ApplicationCapabilities
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Section: Organizations
|
||||
|
|
@ -95,6 +61,69 @@ Organizations:
|
|||
- Host: peer0.org2.example.com
|
||||
Port: 7051
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Capabilities
|
||||
#
|
||||
# - This section defines the capabilities of fabric network. This is a new
|
||||
# concept as of v1.1.0 and should not be utilized in mixed networks with
|
||||
# v1.0.x peers and orderers. Capabilities define features which must be
|
||||
# present in a fabric binary for that binary to safely participate in the
|
||||
# fabric network. For instance, if a new MSP type is added, newer binaries
|
||||
# might recognize and validate the signatures from this type, while older
|
||||
# binaries without this support would be unable to validate those
|
||||
# transactions. This could lead to different versions of the fabric binaries
|
||||
# having different world states. Instead, defining a capability for a channel
|
||||
# informs those binaries without this capability that they must cease
|
||||
# processing transactions until they have been upgraded. For v1.0.x if any
|
||||
# capabilities are defined (including a map with all capabilities turned off)
|
||||
# then the v1.0.x peer will deliberately crash.
|
||||
#
|
||||
################################################################################
|
||||
Capabilities:
|
||||
# Channel capabilities apply to both the orderers and the peers and must be
|
||||
# supported by both. Set the value of the capability to true to require it.
|
||||
Global: &ChannelCapabilities
|
||||
# V1.1 for Global is a catchall flag for behavior which has been
|
||||
# determined to be desired for all orderers and peers running v1.0.x,
|
||||
# but the modification of which would cause incompatibilities. Users
|
||||
# should leave this flag set to true.
|
||||
V1_1: true
|
||||
|
||||
# Orderer capabilities apply only to the orderers, and may be safely
|
||||
# manipulated without concern for upgrading peers. Set the value of the
|
||||
# capability to true to require it.
|
||||
Orderer: &OrdererCapabilities
|
||||
# V1.1 for Order is a catchall flag for behavior which has been
|
||||
# determined to be desired for all orderers running v1.0.x, but the
|
||||
# modification of which would cause incompatibilities. Users should
|
||||
# leave this flag set to true.
|
||||
V1_1: true
|
||||
|
||||
# Application capabilities apply only to the peer network, and may be safely
|
||||
# manipulated without concern for upgrading orderers. Set the value of the
|
||||
# capability to true to require it.
|
||||
Application: &ApplicationCapabilities
|
||||
# V1.2 for Application is a catchall flag for behavior which has been
|
||||
# determined to be desired for all peers running v1.0.x, but the
|
||||
# modification of which would cause incompatibilities. Users should
|
||||
# leave this flag set to true.
|
||||
V1_2: true
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# 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:
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Orderer
|
||||
|
|
@ -142,63 +171,34 @@ Orderer: &OrdererDefaults
|
|||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Application
|
||||
# Profile
|
||||
#
|
||||
# - This section defines the values to encode into a config transaction or
|
||||
# genesis block for application related parameters
|
||||
# - Different configuration profiles may be encoded here to be specified
|
||||
# as parameters to the configtxgen tool
|
||||
#
|
||||
################################################################################
|
||||
Application: &ApplicationDefaults
|
||||
Profiles:
|
||||
|
||||
# Organizations is the list of orgs which are defined as participants on
|
||||
# the application side of the network
|
||||
Organizations:
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# SECTION: Capabilities
|
||||
#
|
||||
# - This section defines the capabilities of fabric network. This is a new
|
||||
# concept as of v1.1.0 and should not be utilized in mixed networks with
|
||||
# v1.0.x peers and orderers. Capabilities define features which must be
|
||||
# present in a fabric binary for that binary to safely participate in the
|
||||
# fabric network. For instance, if a new MSP type is added, newer binaries
|
||||
# might recognize and validate the signatures from this type, while older
|
||||
# binaries without this support would be unable to validate those
|
||||
# transactions. This could lead to different versions of the fabric binaries
|
||||
# having different world states. Instead, defining a capability for a channel
|
||||
# informs those binaries without this capability that they must cease
|
||||
# processing transactions until they have been upgraded. For v1.0.x if any
|
||||
# capabilities are defined (including a map with all capabilities turned off)
|
||||
# then the v1.0.x peer will deliberately crash.
|
||||
#
|
||||
################################################################################
|
||||
Capabilities:
|
||||
# Channel capabilities apply to both the orderers and the peers and must be
|
||||
# supported by both. Set the value of the capability to true to require it.
|
||||
Global: &ChannelCapabilities
|
||||
# V1.1 for Global is a catchall flag for behavior which has been
|
||||
# determined to be desired for all orderers and peers running v1.0.x,
|
||||
# but the modification of which would cause incompatibilities. Users
|
||||
# should leave this flag set to true.
|
||||
V1_1: true
|
||||
|
||||
# Orderer capabilities apply only to the orderers, and may be safely
|
||||
# manipulated without concern for upgrading peers. Set the value of the
|
||||
# capability to true to require it.
|
||||
Orderer: &OrdererCapabilities
|
||||
# V1.1 for Order is a catchall flag for behavior which has been
|
||||
# determined to be desired for all orderers running v1.0.x, but the
|
||||
# modification of which would cause incompatibilities. Users should
|
||||
# leave this flag set to true.
|
||||
V1_1: true
|
||||
|
||||
# Application capabilities apply only to the peer network, and may be safely
|
||||
# manipulated without concern for upgrading orderers. Set the value of the
|
||||
# capability to true to require it.
|
||||
Application: &ApplicationCapabilities
|
||||
# V1.1 for Application is a catchall flag for behavior which has been
|
||||
# determined to be desired for all peers running v1.0.x, but the
|
||||
# modification of which would cause incompatibilities. Users should
|
||||
# leave this flag set to true.
|
||||
V1_1: true
|
||||
TwoOrgsOrdererGenesis:
|
||||
Capabilities:
|
||||
<<: *ChannelCapabilities
|
||||
Orderer:
|
||||
<<: *OrdererDefaults
|
||||
Organizations:
|
||||
- *OrdererOrg
|
||||
Capabilities:
|
||||
<<: *OrdererCapabilities
|
||||
Consortiums:
|
||||
SampleConsortium:
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
TwoOrgsChannel:
|
||||
Consortium: SampleConsortium
|
||||
Application:
|
||||
<<: *ApplicationDefaults
|
||||
Organizations:
|
||||
- *Org1
|
||||
- *Org2
|
||||
Capabilities:
|
||||
<<: *ApplicationCapabilities
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ services:
|
|||
- /var/run/:/host/var/run/
|
||||
- ./../chaincode/:/opt/gopath/src/github.com/chaincode
|
||||
- ./org3-artifacts/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
|
||||
- ./crypto-config/peerOrganizations/org1.example.com:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com
|
||||
- ./crypto-config/peerOrganizations/org2.example.com:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com
|
||||
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
|
||||
depends_on:
|
||||
- peer0.org3.example.com
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
# this may be commented out to resolve installed version of tools if desired
|
||||
export PATH=${PWD}/../bin:${PWD}:$PATH
|
||||
export FABRIC_CFG_PATH=${PWD}
|
||||
export VERBOSE=false
|
||||
|
||||
# Print the usage message
|
||||
function printHelp () {
|
||||
|
|
@ -32,6 +33,7 @@ function printHelp () {
|
|||
echo " -s <dbtype> - the database backend to use: goleveldb (default) or couchdb"
|
||||
echo " -l <language> - the chaincode language: golang (default) or node"
|
||||
echo " -i <imagetag> - the tag to be used to launch the network (defaults to \"latest\")"
|
||||
echo " -v - verbose mode"
|
||||
echo
|
||||
echo "Typically, one would first generate the required certificates and "
|
||||
echo "genesis block, then bring up the network. e.g.:"
|
||||
|
|
@ -80,7 +82,7 @@ function clearContainers () {
|
|||
# specifically the following images are often left behind:
|
||||
# TODO list generated image naming patterns
|
||||
function removeUnwantedImages() {
|
||||
DOCKER_IMAGE_IDS=$(docker images | grep "dev\|none\|test-vp\|peer[0-9]-" | awk '{print $3}')
|
||||
DOCKER_IMAGE_IDS=$(docker images|awk '($1 ~ /dev-peer.*.mycc.*/) {print $3}')
|
||||
if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then
|
||||
echo "---- No images available for deletion ----"
|
||||
else
|
||||
|
|
@ -110,7 +112,7 @@ function networkUp () {
|
|||
echo "###############################################################"
|
||||
echo "############### Have Org3 peers join network ##################"
|
||||
echo "###############################################################"
|
||||
docker exec Org3cli ./scripts/step2org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT
|
||||
docker exec Org3cli ./scripts/step2org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Unable to have Org3 peers join network"
|
||||
exit 1
|
||||
|
|
@ -119,13 +121,13 @@ function networkUp () {
|
|||
echo "###############################################################"
|
||||
echo "##### Upgrade chaincode to have Org3 peers on the network #####"
|
||||
echo "###############################################################"
|
||||
docker exec cli ./scripts/step3org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT
|
||||
docker exec cli ./scripts/step3org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Unable to add Org3 peers on network"
|
||||
exit 1
|
||||
fi
|
||||
# finish by running the test
|
||||
docker exec Org3cli ./scripts/testorg3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT
|
||||
docker exec Org3cli ./scripts/testorg3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Unable to run test"
|
||||
exit 1
|
||||
|
|
@ -134,8 +136,7 @@ function networkUp () {
|
|||
|
||||
# Tear down running network
|
||||
function networkDown () {
|
||||
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_ORG3 down --volumes
|
||||
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_ORG3 -f $COMPOSE_FILE_COUCH down --volumes
|
||||
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_ORG3 -f $COMPOSE_FILE_COUCH down --volumes --remove-orphans
|
||||
# Don't remove containers, images, etc if restarting
|
||||
if [ "$MODE" != "restart" ]; then
|
||||
#Cleanup the chaincode containers
|
||||
|
|
@ -147,10 +148,6 @@ function networkDown () {
|
|||
# remove the docker-compose yaml file that was customized to the example
|
||||
rm -f docker-compose-e2e.yaml
|
||||
fi
|
||||
|
||||
# For some black-magic reason the first docker-compose down does not actually cleanup the volumes
|
||||
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_ORG3 down --volumes
|
||||
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_ORG3 -f $COMPOSE_FILE_COUCH down --volumes
|
||||
}
|
||||
|
||||
# Use the CLI container to create the configuration transaction needed to add
|
||||
|
|
@ -160,7 +157,7 @@ function createConfigTx () {
|
|||
echo "###############################################################"
|
||||
echo "####### Generate and submit config tx to add Org3 #############"
|
||||
echo "###############################################################"
|
||||
docker exec cli scripts/step1org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT
|
||||
docker exec cli scripts/step1org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Unable to create config tx"
|
||||
exit 1
|
||||
|
|
@ -271,7 +268,7 @@ else
|
|||
printHelp
|
||||
exit 1
|
||||
fi
|
||||
while getopts "h?c:t:d:f:s:l:i:" opt; do
|
||||
while getopts "h?c:t:d:f:s:l:i:v" opt; do
|
||||
case "$opt" in
|
||||
h|\?)
|
||||
printHelp
|
||||
|
|
@ -291,6 +288,8 @@ while getopts "h?c:t:d:f:s:l:i:" opt; do
|
|||
;;
|
||||
i) IMAGETAG=$OPTARG
|
||||
;;
|
||||
v) VERBOSE=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@ CHANNEL_NAME="$1"
|
|||
DELAY="$2"
|
||||
LANGUAGE="$3"
|
||||
TIMEOUT="$4"
|
||||
VERBOSE="$5"
|
||||
: ${CHANNEL_NAME:="mychannel"}
|
||||
: ${DELAY:="3"}
|
||||
: ${LANGUAGE:="golang"}
|
||||
: ${TIMEOUT:="10"}
|
||||
: ${VERBOSE:="false"}
|
||||
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
|
||||
COUNTER=1
|
||||
MAX_RETRY=5
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
|
||||
CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/"
|
||||
if [ "$LANGUAGE" = "node" ]; then
|
||||
|
|
@ -48,7 +49,7 @@ createChannel() {
|
|||
fi
|
||||
cat log.txt
|
||||
verifyResult $res "Channel creation failed"
|
||||
echo "===================== Channel \"$CHANNEL_NAME\" is created successfully ===================== "
|
||||
echo "===================== Channel '$CHANNEL_NAME' created ===================== "
|
||||
echo
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +57,7 @@ joinChannel () {
|
|||
for org in 1 2; do
|
||||
for peer in 0 1; do
|
||||
joinChannelWithRetry $peer $org
|
||||
echo "===================== peer${peer}.org${org} joined on the channel \"$CHANNEL_NAME\" ===================== "
|
||||
echo "===================== peer${peer}.org${org} joined channel '$CHANNEL_NAME' ===================== "
|
||||
sleep $DELAY
|
||||
echo
|
||||
done
|
||||
|
|
@ -91,9 +92,9 @@ instantiateChaincode 0 2
|
|||
echo "Querying chaincode on peer0.org1..."
|
||||
chaincodeQuery 0 1 100
|
||||
|
||||
# Invoke chaincode on peer0.org1
|
||||
echo "Sending invoke transaction on peer0.org1..."
|
||||
chaincodeInvoke 0 1
|
||||
# Invoke chaincode on peer0.org1 and peer0.org2
|
||||
echo "Sending invoke transaction on peer0.org1 peer0.org2..."
|
||||
chaincodeInvoke 0 1 0 2
|
||||
|
||||
## Install chaincode on peer1.org2
|
||||
echo "Installing chaincode on peer1.org2..."
|
||||
|
|
|
|||
|
|
@ -15,14 +15,15 @@ CHANNEL_NAME="$1"
|
|||
DELAY="$2"
|
||||
LANGUAGE="$3"
|
||||
TIMEOUT="$4"
|
||||
VERBOSE="$5"
|
||||
: ${CHANNEL_NAME:="mychannel"}
|
||||
: ${DELAY:="3"}
|
||||
: ${LANGUAGE:="golang"}
|
||||
: ${TIMEOUT:="10"}
|
||||
: ${VERBOSE:="false"}
|
||||
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
|
||||
COUNTER=1
|
||||
MAX_RETRY=5
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
|
||||
CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/"
|
||||
if [ "$LANGUAGE" = "node" ]; then
|
||||
|
|
|
|||
|
|
@ -18,14 +18,15 @@ CHANNEL_NAME="$1"
|
|||
DELAY="$2"
|
||||
LANGUAGE="$3"
|
||||
TIMEOUT="$4"
|
||||
VERBOSE="$5"
|
||||
: ${CHANNEL_NAME:="mychannel"}
|
||||
: ${DELAY:="3"}
|
||||
: ${LANGUAGE:="golang"}
|
||||
: ${TIMEOUT:="10"}
|
||||
: ${VERBOSE:="false"}
|
||||
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
|
||||
COUNTER=1
|
||||
MAX_RETRY=5
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
|
||||
CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/"
|
||||
if [ "$LANGUAGE" = "node" ]; then
|
||||
|
|
@ -43,17 +44,15 @@ set +x
|
|||
cat log.txt
|
||||
verifyResult $res "Fetching config block from orderer has Failed"
|
||||
|
||||
echo "===================== Having peer0.org3 join the channel ===================== "
|
||||
joinChannelWithRetry 0 3
|
||||
echo "===================== peer0.org3 joined the channel \"$CHANNEL_NAME\" ===================== "
|
||||
echo "===================== Having peer1.org3 join the channel ===================== "
|
||||
echo "===================== peer0.org3 joined channel '$CHANNEL_NAME' ===================== "
|
||||
joinChannelWithRetry 1 3
|
||||
echo "===================== peer1.org3 joined the channel \"$CHANNEL_NAME\" ===================== "
|
||||
echo "===================== peer1.org3 joined channel '$CHANNEL_NAME' ===================== "
|
||||
echo "Installing chaincode 2.0 on peer0.org3..."
|
||||
installChaincode 0 3 2.0
|
||||
|
||||
echo
|
||||
echo "========= Got Org3 halfway onto your first network ========= "
|
||||
echo "========= Org3 is now halfway onto your first network ========= "
|
||||
echo
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@ CHANNEL_NAME="$1"
|
|||
DELAY="$2"
|
||||
LANGUAGE="$3"
|
||||
TIMEOUT="$4"
|
||||
VERBOSE="$5"
|
||||
: ${CHANNEL_NAME:="mychannel"}
|
||||
: ${DELAY:="3"}
|
||||
: ${LANGUAGE:="golang"}
|
||||
: ${TIMEOUT:="10"}
|
||||
: ${VERBOSE:="false"}
|
||||
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
|
||||
COUNTER=1
|
||||
MAX_RETRY=5
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
|
||||
CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/"
|
||||
if [ "$LANGUAGE" = "node" ]; then
|
||||
|
|
|
|||
|
|
@ -24,13 +24,14 @@ CHANNEL_NAME="$1"
|
|||
DELAY="$2"
|
||||
LANGUAGE="$3"
|
||||
TIMEOUT="$4"
|
||||
VERBOSE="$5"
|
||||
: ${CHANNEL_NAME:="mychannel"}
|
||||
: ${TIMEOUT:="10"}
|
||||
: ${LANGUAGE:="golang"}
|
||||
: ${VERBOSE:="false"}
|
||||
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
|
||||
COUNTER=1
|
||||
MAX_RETRY=5
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
|
||||
CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/"
|
||||
if [ "$LANGUAGE" = "node" ]; then
|
||||
|
|
@ -42,10 +43,27 @@ echo "Channel name : "$CHANNEL_NAME
|
|||
# import functions
|
||||
. scripts/utils.sh
|
||||
|
||||
# Query chaincode on peer0.org3, check if the result is 90
|
||||
echo "Querying chaincode on peer0.org3..."
|
||||
chaincodeQuery 0 3 90
|
||||
chaincodeInvoke 0 3
|
||||
|
||||
# Invoke chaincode on peer0.org1, peer0.org2, and peer0.org3
|
||||
echo "Sending invoke transaction on peer0.org1 peer0.org2 peer0.org3..."
|
||||
chaincodeInvoke 0 1 0 2 0 3
|
||||
|
||||
# Query on chaincode on peer0.org3, peer0.org2, peer0.org1 check if the result is 80
|
||||
# We query a peer in each organization, to ensure peers from all organizations are in sync
|
||||
# and there is no state fork between organizations.
|
||||
echo "Querying chaincode on peer0.org3..."
|
||||
chaincodeQuery 0 3 80
|
||||
|
||||
echo "Querying chaincode on peer0.org2..."
|
||||
chaincodeQuery 0 2 80
|
||||
|
||||
echo "Querying chaincode on peer0.org1..."
|
||||
chaincodeQuery 0 1 80
|
||||
|
||||
|
||||
echo
|
||||
echo "========= All GOOD, EYFN test execution completed =========== "
|
||||
echo
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@ CHANNEL_NAME="$1"
|
|||
DELAY="$2"
|
||||
LANGUAGE="$3"
|
||||
TIMEOUT="$4"
|
||||
VERBOSE="$5"
|
||||
: ${CHANNEL_NAME:="mychannel"}
|
||||
: ${DELAY:="5"}
|
||||
: ${LANGUAGE:="golang"}
|
||||
: ${TIMEOUT:="10"}
|
||||
: ${VERBOSE:="false"}
|
||||
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
|
||||
COUNTER=1
|
||||
MAX_RETRY=5
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
|
||||
CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/"
|
||||
if [ "$LANGUAGE" = "node" ]; then
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
# This is a collection of bash functions used by different scripts
|
||||
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
|
||||
PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
|
||||
PEER0_ORG3_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
|
||||
|
||||
# verify the result of the end-to-end test
|
||||
verifyResult () {
|
||||
|
|
@ -29,7 +33,7 @@ setGlobals () {
|
|||
ORG=$2
|
||||
if [ $ORG -eq 1 ] ; then
|
||||
CORE_PEER_LOCALMSPID="Org1MSP"
|
||||
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
|
||||
CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
|
||||
if [ $PEER -eq 0 ]; then
|
||||
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
|
||||
|
|
@ -38,7 +42,7 @@ setGlobals () {
|
|||
fi
|
||||
elif [ $ORG -eq 2 ] ; then
|
||||
CORE_PEER_LOCALMSPID="Org2MSP"
|
||||
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
|
||||
CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
|
||||
if [ $PEER -eq 0 ]; then
|
||||
CORE_PEER_ADDRESS=peer0.org2.example.com:7051
|
||||
|
|
@ -48,7 +52,7 @@ setGlobals () {
|
|||
|
||||
elif [ $ORG -eq 3 ] ; then
|
||||
CORE_PEER_LOCALMSPID="Org3MSP"
|
||||
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
|
||||
CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG3_CA
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
|
||||
if [ $PEER -eq 0 ]; then
|
||||
CORE_PEER_ADDRESS=peer0.org3.example.com:7051
|
||||
|
|
@ -59,7 +63,9 @@ setGlobals () {
|
|||
echo "================== ERROR !!! ORG Unknown =================="
|
||||
fi
|
||||
|
||||
env |grep CORE
|
||||
if [ "$VERBOSE" == "true" ]; then
|
||||
env |grep CORE
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -81,12 +87,12 @@ updateAnchorPeers() {
|
|||
fi
|
||||
cat log.txt
|
||||
verifyResult $res "Anchor peer update failed"
|
||||
echo "===================== Anchor peers for org \"$CORE_PEER_LOCALMSPID\" on \"$CHANNEL_NAME\" is updated successfully ===================== "
|
||||
echo "===================== Anchor peers updated for org '$CORE_PEER_LOCALMSPID' on channel '$CHANNEL_NAME' ===================== "
|
||||
sleep $DELAY
|
||||
echo
|
||||
}
|
||||
|
||||
## Sometimes Join takes time hence RETRY at least for 5 times
|
||||
## Sometimes Join takes time hence RETRY at least 5 times
|
||||
joinChannelWithRetry () {
|
||||
PEER=$1
|
||||
ORG=$2
|
||||
|
|
@ -105,7 +111,7 @@ joinChannelWithRetry () {
|
|||
else
|
||||
COUNTER=1
|
||||
fi
|
||||
verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to Join the Channel"
|
||||
verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to join channel '$CHANNEL_NAME' "
|
||||
}
|
||||
|
||||
installChaincode () {
|
||||
|
|
@ -118,7 +124,7 @@ installChaincode () {
|
|||
res=$?
|
||||
set +x
|
||||
cat log.txt
|
||||
verifyResult $res "Chaincode installation on peer${PEER}.org${ORG} has Failed"
|
||||
verifyResult $res "Chaincode installation on peer${PEER}.org${ORG} has failed"
|
||||
echo "===================== Chaincode is installed on peer${PEER}.org${ORG} ===================== "
|
||||
echo
|
||||
}
|
||||
|
|
@ -129,22 +135,23 @@ instantiateChaincode () {
|
|||
setGlobals $PEER $ORG
|
||||
VERSION=${3:-1.0}
|
||||
|
||||
# while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
|
||||
# lets supply it directly as we know it using the "-o" option
|
||||
# while 'peer chaincode' command can get the orderer endpoint from the peer
|
||||
# (if join was successful), let's supply it directly as we know it using
|
||||
# the "-o" option
|
||||
if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
|
||||
set -x
|
||||
peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
|
||||
peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
|
||||
res=$?
|
||||
set +x
|
||||
else
|
||||
set -x
|
||||
peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
|
||||
peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
|
||||
res=$?
|
||||
set +x
|
||||
fi
|
||||
cat log.txt
|
||||
verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed"
|
||||
echo "===================== Chaincode Instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== "
|
||||
echo "===================== Chaincode is instantiated on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== "
|
||||
echo
|
||||
}
|
||||
|
||||
|
|
@ -154,12 +161,12 @@ upgradeChaincode () {
|
|||
setGlobals $PEER $ORG
|
||||
|
||||
set -x
|
||||
peer chaincode upgrade -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 2.0 -c '{"Args":["init","a","90","b","210"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')"
|
||||
peer chaincode upgrade -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 2.0 -c '{"Args":["init","a","90","b","210"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')"
|
||||
res=$?
|
||||
set +x
|
||||
cat log.txt
|
||||
verifyResult $res "Chaincode upgrade on org${ORG} peer${PEER} has Failed"
|
||||
echo "===================== Chaincode is upgraded on org${ORG} peer${PEER} ===================== "
|
||||
verifyResult $res "Chaincode upgrade on peer${PEER}.org${ORG} has failed"
|
||||
echo "===================== Chaincode is upgraded on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== "
|
||||
echo
|
||||
}
|
||||
|
||||
|
|
@ -184,11 +191,16 @@ chaincodeQuery () {
|
|||
set +x
|
||||
test $res -eq 0 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}')
|
||||
test "$VALUE" = "$EXPECTED_RESULT" && let rc=0
|
||||
# removed the string "Query Result" from peer chaincode query command
|
||||
# result. as a result, have to support both options until the change
|
||||
# is merged.
|
||||
test $rc -ne 0 && VALUE=$(cat log.txt | egrep '^[0-9]+$')
|
||||
test "$VALUE" = "$EXPECTED_RESULT" && let rc=0
|
||||
done
|
||||
echo
|
||||
cat log.txt
|
||||
if test $rc -eq 0 ; then
|
||||
echo "===================== Query on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== "
|
||||
echo "===================== Query successful on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== "
|
||||
else
|
||||
echo "!!!!!!!!!!!!!!! Query result on peer${PEER}.org${ORG} is INVALID !!!!!!!!!!!!!!!!"
|
||||
echo "================== ERROR !!! FAILED to execute End-2-End Scenario =================="
|
||||
|
|
@ -234,7 +246,8 @@ signConfigtxAsPeerOrg() {
|
|||
}
|
||||
|
||||
# createConfigUpdate <channel_id> <original_config.json> <modified_config.json> <output.pb>
|
||||
# Takes an original and modified config, and produces the config update tx which transitions between the two
|
||||
# Takes an original and modified config, and produces the config update tx
|
||||
# which transitions between the two
|
||||
createConfigUpdate() {
|
||||
CHANNEL=$1
|
||||
ORIGINAL=$2
|
||||
|
|
@ -251,25 +264,56 @@ createConfigUpdate() {
|
|||
set +x
|
||||
}
|
||||
|
||||
# parsePeerConnectionParameters $@
|
||||
# Helper function that takes the parameters from a chaincode operation
|
||||
# (e.g. invoke, query, instantiate) and checks for an even number of
|
||||
# peers and associated org, then sets $PEER_CONN_PARMS and $PEERS
|
||||
parsePeerConnectionParameters() {
|
||||
# check for uneven number of peer and org parameters
|
||||
if [ $(( $# % 2 )) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PEER_CONN_PARMS=""
|
||||
PEERS=""
|
||||
while [ "$#" -gt 0 ]; do
|
||||
PEER="peer$1.org$2"
|
||||
PEERS="$PEERS $PEER"
|
||||
PEER_CONN_PARMS="$PEER_CONN_PARMS --peerAddresses $PEER.example.com:7051"
|
||||
if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "true" ]; then
|
||||
TLSINFO=$(eval echo "--tlsRootCertFiles \$PEER$1_ORG$2_CA")
|
||||
PEER_CONN_PARMS="$PEER_CONN_PARMS $TLSINFO"
|
||||
fi
|
||||
# shift by two to get the next pair of peer/org parameters
|
||||
shift; shift
|
||||
done
|
||||
# remove leading space for output
|
||||
PEERS="$(echo -e "$PEERS" | sed -e 's/^[[:space:]]*//')"
|
||||
}
|
||||
|
||||
# chaincodeInvoke <peer> <org> ...
|
||||
# Accepts as many peer/org pairs as desired and requests endorsement from each
|
||||
chaincodeInvoke () {
|
||||
PEER=$1
|
||||
ORG=$2
|
||||
setGlobals $PEER $ORG
|
||||
# while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
|
||||
# lets supply it directly as we know it using the "-o" option
|
||||
parsePeerConnectionParameters $@
|
||||
res=$?
|
||||
verifyResult $res "Invoke transaction failed on channel '$CHANNEL_NAME' due to uneven number of peer and org parameters "
|
||||
|
||||
# while 'peer chaincode' command can get the orderer endpoint from the
|
||||
# peer (if join was successful), let's supply it directly as we know
|
||||
# it using the "-o" option
|
||||
if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
|
||||
set -x
|
||||
peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt
|
||||
peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt
|
||||
res=$?
|
||||
set +x
|
||||
else
|
||||
set -x
|
||||
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
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt
|
||||
res=$?
|
||||
set +x
|
||||
fi
|
||||
cat log.txt
|
||||
verifyResult $res "Invoke execution on peer${PEER}.org${ORG} failed "
|
||||
echo "===================== Invoke transaction on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== "
|
||||
verifyResult $res "Invoke execution on $PEERS failed "
|
||||
echo "===================== Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME' ===================== "
|
||||
echo
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
<!--
|
||||
Copyright IBM Corp All Rights Reserved
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
# High-Throughput Network
|
||||
|
||||
## Purpose
|
||||
|
|
@ -106,9 +112,9 @@ and run some invocations are provided below.
|
|||
`./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/` -->
|
||||
`./../high-throughput/scripts/:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/`
|
||||
|
||||
* Finally, comment out the `command` section by placing a `#` before it, e.g.
|
||||
|
||||
`#command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT'`
|
||||
* Finally, comment out the `docker exec cli scripts/script.sh` command from the `byfn.sh` script by placing a `#` before it so that the standard BYFN end to end script doesn't run, e.g.
|
||||
|
||||
`# docker exec cli scripts/script.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE`
|
||||
|
||||
3. We can now bring our network up by typing in `./byfn.sh -m up -c mychannel`
|
||||
4. Open a new terminal window and enter the CLI container using `docker exec -it cli bash`, all operations on the network will happen within
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* Copyright IBM Corp All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Demonstrates how to handle data in an application with a high transaction volume where the transactions
|
||||
* all attempt to change the same key-value pair in the ledger. Such an application will have trouble
|
||||
* as multiple transactions may read a value at a certain version, which will then be invalid when the first
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
|
||||
|
||||
# Channel creation
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["delete","'$1'"]}'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["get","'$1'"]}'
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,7 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["getstandard","'$1'"]}'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
echo "========== Installing chaincode on peer0.org1 =========="
|
||||
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
|
||||
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
echo "========== Instantiating chaincode v$1 =========="
|
||||
peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args": []}' -v $1 -P "OR ('Org1MSP.member','Org2MSP.member')"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
for (( i = 0; i < 1000; ++i ))
|
||||
do
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["putstandard","'$1'","'$i'"]}'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
for (( i = 0; i < 1000; ++i ))
|
||||
do
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["update","'$1'","'$2'","'$3'"]}' &
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["prunefast","'$1'"]}'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["prunesafe","'$1'"]}'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
export CHANNEL_NAME=mychannel
|
||||
export CC_NAME=bigdatacc
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args":["update","'$1'","'$2'","'$3'"]}'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
echo "========== Upgrade chaincode to version $1 =========="
|
||||
peer chaincode upgrade -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n $CC_NAME -c '{"Args": []}' -v $1 -P "OR ('Org1MSP.member','Org2MSP.member')"
|
||||
|
||||
|
|
|
|||
220
scripts/bootstrap.sh
Executable file
220
scripts/bootstrap.sh
Executable file
|
|
@ -0,0 +1,220 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright IBM Corp. All Rights Reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# if version not passed in, default to latest released version
|
||||
export VERSION=1.1.0
|
||||
# if ca version not passed in, default to latest released version
|
||||
export CA_VERSION=$VERSION
|
||||
# current version of thirdparty images (couchdb, kafka and zookeeper) released
|
||||
export THIRDPARTY_IMAGE_VERSION=0.4.7
|
||||
export ARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')")
|
||||
export MARCH=$(uname -m)
|
||||
|
||||
# ensure we're in the fabric-samples directory
|
||||
dir=`basename $PWD`
|
||||
if [ "${dir}" == "scripts" ]; then
|
||||
cd ..
|
||||
fi
|
||||
|
||||
dir=`basename $PWD`
|
||||
if [ "${dir}" != "fabric-samples" ]; then
|
||||
echo "You should run this script from the fabric-samples root directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printHelp() {
|
||||
echo "Usage: bootstrap.sh [<version>] [<ca_version>] [<thirdparty_version>][-d -b]"
|
||||
echo
|
||||
echo "-d - bypass docker image download"
|
||||
echo "-b - bypass download of platform-specific binaries"
|
||||
echo
|
||||
echo "e.g. bootstrap.sh 1.1.1"
|
||||
echo "would download docker images and binaries for version 1.1.1"
|
||||
}
|
||||
|
||||
dockerFabricPull() {
|
||||
local FABRIC_TAG=$1
|
||||
for IMAGES in peer orderer ccenv tools; do
|
||||
echo "==> FABRIC IMAGE: $IMAGES"
|
||||
echo
|
||||
docker pull hyperledger/fabric-$IMAGES:$FABRIC_TAG
|
||||
docker tag hyperledger/fabric-$IMAGES:$FABRIC_TAG hyperledger/fabric-$IMAGES
|
||||
done
|
||||
}
|
||||
|
||||
dockerThirdPartyImagesPull() {
|
||||
local THIRDPARTY_TAG=$1
|
||||
for IMAGES in couchdb kafka zookeeper; do
|
||||
echo "==> THIRDPARTY DOCKER IMAGE: $IMAGES"
|
||||
echo
|
||||
docker pull hyperledger/fabric-$IMAGES:$THIRDPARTY_TAG
|
||||
docker tag hyperledger/fabric-$IMAGES:$THIRDPARTY_TAG hyperledger/fabric-$IMAGES
|
||||
done
|
||||
}
|
||||
|
||||
dockerCaPull() {
|
||||
local CA_TAG=$1
|
||||
echo "==> FABRIC CA IMAGE"
|
||||
echo
|
||||
docker pull hyperledger/fabric-ca:$CA_TAG
|
||||
docker tag hyperledger/fabric-ca:$CA_TAG hyperledger/fabric-ca
|
||||
}
|
||||
|
||||
# Incrementally downloads the .tar.gz file locally first, only decompressing it
|
||||
# after the download is complete. This is slower than binaryDownload() but
|
||||
# allows the download to be resumed.
|
||||
binaryIncrementalDownload() {
|
||||
local BINARY_FILE=$1
|
||||
local URL=$2
|
||||
curl -f -s -C - ${URL} -o ${BINARY_FILE} || rc=$?
|
||||
# Due to limitations in the current Nexus repo:
|
||||
# curl returns 33 when there's a resume attempt with no more bytes to download
|
||||
# curl returns 2 after finishing a resumed download
|
||||
# with -f curl returns 22 on a 404
|
||||
if [ "$rc" = 22 ]; then
|
||||
# looks like the requested file doesn't actually exist so stop here
|
||||
return 22
|
||||
fi
|
||||
if [ -z "$rc" ] || [ $rc -eq 33 ] || [ $rc -eq 2 ]; then
|
||||
# The checksum validates that RC 33 or 2 are not real failures
|
||||
echo "==> File downloaded. Verifying the md5sum..."
|
||||
localMd5sum=$(md5sum ${BINARY_FILE} | awk '{print $1}')
|
||||
remoteMd5sum=$(curl -s ${URL}.md5)
|
||||
if [ "$localMd5sum" == "$remoteMd5sum" ]; then
|
||||
echo "==> Extracting ${BINARY_FILE}..."
|
||||
tar xzf ./${BINARY_FILE} --overwrite
|
||||
echo "==> Done."
|
||||
rm -f ${BINARY_FILE} ${BINARY_FILE}.md5
|
||||
else
|
||||
echo "Download failed: the local md5sum is different from the remote md5sum. Please try again."
|
||||
rm -f ${BINARY_FILE} ${BINARY_FILE}.md5
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Failure downloading binaries (curl RC=$rc). Please try again and the download will resume from where it stopped."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# This will attempt to download the .tar.gz all at once, but will trigger the
|
||||
# binaryIncrementalDownload() function upon a failure, allowing for resume
|
||||
# if there are network failures.
|
||||
binaryDownload() {
|
||||
local BINARY_FILE=$1
|
||||
local URL=$2
|
||||
echo "===> Downloading: " ${URL}
|
||||
# Check if a previous failure occurred and the file was partially downloaded
|
||||
if [ -e ${BINARY_FILE} ]; then
|
||||
echo "==> Partial binary file found. Resuming download..."
|
||||
binaryIncrementalDownload ${BINARY_FILE} ${URL}
|
||||
else
|
||||
curl ${URL} | tar xz || rc=$?
|
||||
if [ ! -z "$rc" ]; then
|
||||
echo "==> There was an error downloading the binary file. Switching to incremental download."
|
||||
echo "==> Downloading file..."
|
||||
binaryIncrementalDownload ${BINARY_FILE} ${URL}
|
||||
else
|
||||
echo "==> Done."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
binariesInstall() {
|
||||
echo "===> Downloading version ${FABRIC_TAG} platform specific fabric binaries"
|
||||
binaryDownload ${BINARY_FILE} https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric/hyperledger-fabric/${ARCH}-${VERSION}/${BINARY_FILE}
|
||||
if [ $? -eq 22 ]; then
|
||||
echo
|
||||
echo "------> ${FABRIC_TAG} platform specific fabric binary is not available to download <----"
|
||||
echo
|
||||
fi
|
||||
|
||||
echo "===> Downloading version ${CA_TAG} platform specific fabric-ca-client binary"
|
||||
binaryDownload ${CA_BINARY_FILE} https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-ca/hyperledger-fabric-ca/${ARCH}-${CA_VERSION}/${CA_BINARY_FILE}
|
||||
if [ $? -eq 22 ]; then
|
||||
echo
|
||||
echo "------> ${CA_TAG} fabric-ca-client binary is not available to download (Available from 1.1.0-rc1) <----"
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
dockerInstall() {
|
||||
which docker >& /dev/null
|
||||
NODOCKER=$?
|
||||
if [ "${NODOCKER}" == 0 ]; then
|
||||
echo "===> Pulling fabric Images"
|
||||
dockerFabricPull ${FABRIC_TAG}
|
||||
echo "===> Pulling fabric ca Image"
|
||||
dockerCaPull ${CA_TAG}
|
||||
echo "===> Pulling thirdparty docker images"
|
||||
dockerThirdPartyImagesPull ${THIRDPARTY_TAG}
|
||||
echo
|
||||
echo "===> List out hyperledger docker images"
|
||||
docker images | grep hyperledger*
|
||||
else
|
||||
echo "========================================================="
|
||||
echo "Docker not installed, bypassing download of Fabric images"
|
||||
echo "========================================================="
|
||||
fi
|
||||
}
|
||||
|
||||
DOCKER=true
|
||||
SAMPLES=true
|
||||
BINARIES=true
|
||||
|
||||
# Parse commandline args pull out
|
||||
# version and/or ca-version strings first
|
||||
if echo $1 | grep -q '\d'; then
|
||||
VERSION=$1;shift
|
||||
if echo $1 | grep -q '\d'; then
|
||||
CA_VERSION=$1;shift
|
||||
if echo $1 | grep -q '\d'; then
|
||||
THIRDPARTY_IMAGE_VERSION=$1;shift
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# prior to 1.1.0 architecture was determined by uname -m
|
||||
if [[ $VERSION =~ ^1\.[0]\.* ]]; then
|
||||
export FABRIC_TAG=${MARCH}-${VERSION}
|
||||
export CA_TAG=${MARCH}-${CA_VERSION}
|
||||
export THIRDPARTY_TAG=${MARCH}-${THIRDPARTY_IMAGE_VERSION}
|
||||
else
|
||||
# starting with 1.2.0, multi-arch images will be default
|
||||
: ${CA_TAG:="$CA_VERSION"}
|
||||
: ${FABRIC_TAG:="$VERSION"}
|
||||
: ${THIRDPARTY_TAG:="$THIRDPARTY_IMAGE_VERSION"}
|
||||
fi
|
||||
|
||||
BINARY_FILE=hyperledger-fabric-${ARCH}-${VERSION}.tar.gz
|
||||
CA_BINARY_FILE=hyperledger-fabric-ca-${ARCH}-${CA_VERSION}.tar.gz
|
||||
|
||||
# then parse opts
|
||||
while getopts "h?db" opt; do
|
||||
case "$opt" in
|
||||
h|\?)
|
||||
printHelp
|
||||
exit 0
|
||||
;;
|
||||
d) DOCKER=false
|
||||
;;
|
||||
b) BINARIES=false
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$BINARIES" == "true" ]; then
|
||||
echo
|
||||
echo "Installing Hyperledger Fabric binaries"
|
||||
echo
|
||||
binariesInstall
|
||||
fi
|
||||
if [ "$DOCKER" == "true" ]; then
|
||||
echo
|
||||
echo "Installing Hyperledger Fabric docker images"
|
||||
echo
|
||||
dockerInstall
|
||||
fi
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright IBM Corp. All Rights Reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
export VERSION=${1:-1.0.0}
|
||||
export ARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')" | awk '{print tolower($0)}')
|
||||
#Set MARCH variable i.e ppc64le,s390x,x86_64,i386
|
||||
MARCH=`uname -m`
|
||||
|
||||
dockerFabricPull() {
|
||||
local FABRIC_TAG=$1
|
||||
for IMAGES in peer orderer couchdb ccenv javaenv kafka zookeeper tools; do
|
||||
echo "==> FABRIC IMAGE: $IMAGES"
|
||||
echo
|
||||
docker pull hyperledger/fabric-$IMAGES:$FABRIC_TAG
|
||||
docker tag hyperledger/fabric-$IMAGES:$FABRIC_TAG hyperledger/fabric-$IMAGES
|
||||
done
|
||||
}
|
||||
|
||||
dockerCaPull() {
|
||||
local CA_TAG=$1
|
||||
echo "==> FABRIC CA IMAGE"
|
||||
echo
|
||||
docker pull hyperledger/fabric-ca:$CA_TAG
|
||||
docker tag hyperledger/fabric-ca:$CA_TAG hyperledger/fabric-ca
|
||||
}
|
||||
|
||||
: ${CA_TAG:="$MARCH-$VERSION"}
|
||||
: ${FABRIC_TAG:="$MARCH-$VERSION"}
|
||||
|
||||
echo "===> Pulling fabric Images"
|
||||
dockerFabricPull ${FABRIC_TAG}
|
||||
|
||||
echo "===> Pulling fabric ca Image"
|
||||
dockerCaPull ${CA_TAG}
|
||||
echo
|
||||
echo "===> List out hyperledger docker images"
|
||||
docker images | grep hyperledger*
|
||||
|
||||
Loading…
Reference in a new issue