diff --git a/.gitignore b/.gitignore index 84262045..4b705ae4 100644 --- a/.gitignore +++ b/.gitignore @@ -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* diff --git a/.gitreview b/.gitreview new file mode 100644 index 00000000..c1d6cb23 --- /dev/null +++ b/.gitreview @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +[gerrit] +host=gerrit.hyperledger.org +port=29418 +project=fabric-samples diff --git a/scripts/README.md b/CODE_OF_CONDUCT.md similarity index 51% rename from scripts/README.md rename to CODE_OF_CONDUCT.md index 4dce8de6..2f1f0e36 100644 --- a/scripts/README.md +++ b/CODE_OF_CONDUCT.md @@ -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] -``` - -Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License +Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..6432cb62 --- /dev/null +++ b/CONTRIBUTING.md @@ -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 + +See our [Code of Conduct Guidelines](../blob/master/CODE_OF_CONDUCT.md). + +## Maintainers + +Should you have any questions or concerns, please reach out to one of the project's [Maintainers](../blob/master/MAINTAINERS.md). + +Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. diff --git a/README.md b/README.md index 2df26ca2..f35817e8 100644 --- a/README.md +++ b/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 -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/. diff --git a/balance-transfer/.gitignore b/balance-transfer/.gitignore new file mode 100644 index 00000000..5ab9c94c --- /dev/null +++ b/balance-transfer/.gitignore @@ -0,0 +1,3 @@ +/node_modules/* +/package-lock.json +/fabric-client-kv-org* diff --git a/balance-transfer/artifacts/channel/configtx.yaml b/balance-transfer/artifacts/channel/configtx.yaml index 4cf7ffe9..98f5cb72 100644 --- a/balance-transfer/artifacts/channel/configtx.yaml +++ b/balance-transfer/artifacts/channel/configtx.yaml @@ -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 diff --git a/balance-transfer/artifacts/network-config-aws.yaml b/balance-transfer/artifacts/network-config-aws.yaml index 7402a67f..d9ecd513 100644 --- a/balance-transfer/artifacts/network-config-aws.yaml +++ b/balance-transfer/artifacts/network-config-aws.yaml @@ -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 diff --git a/balance-transfer/artifacts/network-config.yaml b/balance-transfer/artifacts/network-config.yaml index e01768a4..f7544dd9 100644 --- a/balance-transfer/artifacts/network-config.yaml +++ b/balance-transfer/artifacts/network-config.yaml @@ -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 diff --git a/balance-transfer/testAPIs.sh b/balance-transfer/testAPIs.sh index 57673c63..e83a672e 100755 --- a/balance-transfer/testAPIs.sh +++ b/balance-transfer/testAPIs.sh @@ -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 diff --git a/balance-transfer/typescript/.gitignore b/balance-transfer/typescript/.gitignore index 9f22bacf..5e283e61 100644 --- a/balance-transfer/typescript/.gitignore +++ b/balance-transfer/typescript/.gitignore @@ -1,4 +1,4 @@ node_modules package-lock.json dist -types/fabric-client \ No newline at end of file +types/fabric-client diff --git a/balance-transfer/typescript/testAPIs.sh b/balance-transfer/typescript/testAPIs.sh index 63430ad7..8447ad2c 100755 --- a/balance-transfer/typescript/testAPIs.sh +++ b/balance-transfer/typescript/testAPIs.sh @@ -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 diff --git a/basic-network/configtx.yaml b/basic-network/configtx.yaml index f157db20..98828ebc 100644 --- a/basic-network/configtx.yaml +++ b/basic-network/configtx.yaml @@ -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: diff --git a/basic-network/docker-compose.yml b/basic-network/docker-compose.yml index bfad9d95..2ebe3a43 100644 --- a/basic-network/docker-compose.yml +++ b/basic-network/docker-compose.yml @@ -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 diff --git a/basic-network/init.sh b/basic-network/init.sh index 3ab47473..caf7c76d 100755 --- a/basic-network/init.sh +++ b/basic-network/init.sh @@ -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 diff --git a/basic-network/teardown.sh b/basic-network/teardown.sh index 70367930..189b6070 100755 --- a/basic-network/teardown.sh +++ b/basic-network/teardown.sh @@ -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 diff --git a/chaincode-docker-devmode/.gitignore b/chaincode-docker-devmode/.gitignore new file mode 100644 index 00000000..699c14a5 --- /dev/null +++ b/chaincode-docker-devmode/.gitignore @@ -0,0 +1,3 @@ +/myc.block +/chaincode/sacc/sacc +/chaincode/chaincode_example02/chaincode_example02 diff --git a/chaincode-docker-devmode/README.rst b/chaincode-docker-devmode/README.rst index 40e6a217..91bccb30 100644 --- a/chaincode-docker-devmode/README.rst +++ b/chaincode-docker-devmode/README.rst @@ -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 `_. 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 `_, 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 `_, then you will see additional images listed. However, we are only concerned with these four. diff --git a/chaincode/marbles02_private/collections_config.json b/chaincode/marbles02_private/collections_config.json new file mode 100644 index 00000000..d61434a8 --- /dev/null +++ b/chaincode/marbles02_private/collections_config.json @@ -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 + } +] diff --git a/chaincode/marbles02_private/go/META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexOwner.json b/chaincode/marbles02_private/go/META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexOwner.json new file mode 100644 index 00000000..305f0904 --- /dev/null +++ b/chaincode/marbles02_private/go/META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexOwner.json @@ -0,0 +1 @@ +{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"} diff --git a/chaincode/marbles02_private/go/marbles_chaincode_private.go b/chaincode/marbles02_private/go/marbles_chaincode_private.go new file mode 100644 index 00000000..385687c0 --- /dev/null +++ b/chaincode/marbles02_private/go/marbles_chaincode_private.go @@ -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//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//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 +} diff --git a/fabcar/.gitignore b/fabcar/.gitignore new file mode 100644 index 00000000..1e3d188c --- /dev/null +++ b/fabcar/.gitignore @@ -0,0 +1,3 @@ +/node_modules/ +/package-lock.json +/hfc-key-store/ diff --git a/fabcar/invoke.js b/fabcar/invoke.js index 1c0270ac..221e2c00 100644 --- a/fabcar/invoke.js +++ b/fabcar/invoke.js @@ -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') { diff --git a/fabcar/registerUser.js b/fabcar/registerUser.js index 4b4c9091..9aa93a9c 100644 --- a/fabcar/registerUser.js +++ b/fabcar/registerUser.js @@ -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); diff --git a/fabric-ca/README.md b/fabric-ca/README.md index 3a88c602..9c11e16f 100755 --- a/fabric-ca/README.md +++ b/fabric-ca/README.md @@ -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. diff --git a/fabric-ca/scripts/run-fabric.sh b/fabric-ca/scripts/run-fabric.sh index a4ab0f80..c812f961 100755 --- a/fabric-ca/scripts/run-fabric.sh +++ b/fabric-ca/scripts/run-fabric.sh @@ -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 } diff --git a/first-network/.gitignore b/first-network/.gitignore new file mode 100644 index 00000000..715dcea0 --- /dev/null +++ b/first-network/.gitignore @@ -0,0 +1,6 @@ +/channel-artifacts/*.tx +/channel-artifacts/*.block +/crypto-config/* +/docker-compose-e2e.yaml +/ledgers +/ledgers-backup diff --git a/first-network/byfn.sh b/first-network/byfn.sh index df17cc33..6cf20793 100755 --- a/first-network/byfn.sh +++ b/first-network/byfn.sh @@ -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 ] [-t ] [-d ] [-f ] [-s ] [-i ]" - echo " byfn.sh -h|--help (print this message)" - echo " - one of 'up', 'down', 'restart' or 'generate'" + echo " byfn.sh [-c ] [-t ] [-d ] [-f ] [-s ] [-l ] [-i ] [-v]" + echo " - 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 - the database backend to use: goleveldb (default) or couchdb" echo " -l - the chaincode language: golang (default) or node" echo " -i - 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 diff --git a/first-network/configtx.yaml b/first-network/configtx.yaml index 31c545c3..e55efb05 100644 --- a/first-network/configtx.yaml +++ b/first-network/configtx.yaml @@ -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 diff --git a/first-network/docker-compose-org3.yaml b/first-network/docker-compose-org3.yaml index c46ad4e3..49fc939c 100644 --- a/first-network/docker-compose-org3.yaml +++ b/first-network/docker-compose-org3.yaml @@ -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 diff --git a/first-network/eyfn.sh b/first-network/eyfn.sh index b6783aac..cee408b8 100755 --- a/first-network/eyfn.sh +++ b/first-network/eyfn.sh @@ -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 - the database backend to use: goleveldb (default) or couchdb" echo " -l - the chaincode language: golang (default) or node" echo " -i - 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 diff --git a/first-network/scripts/script.sh b/first-network/scripts/script.sh index 5762cb25..1d43a37e 100755 --- a/first-network/scripts/script.sh +++ b/first-network/scripts/script.sh @@ -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..." diff --git a/first-network/scripts/step1org3.sh b/first-network/scripts/step1org3.sh index ad607e35..bff4d6a0 100755 --- a/first-network/scripts/step1org3.sh +++ b/first-network/scripts/step1org3.sh @@ -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 diff --git a/first-network/scripts/step2org3.sh b/first-network/scripts/step2org3.sh index 41268c4b..75745ef9 100755 --- a/first-network/scripts/step2org3.sh +++ b/first-network/scripts/step2org3.sh @@ -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 diff --git a/first-network/scripts/step3org3.sh b/first-network/scripts/step3org3.sh index 585fa203..9588a8b8 100755 --- a/first-network/scripts/step3org3.sh +++ b/first-network/scripts/step3org3.sh @@ -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 diff --git a/first-network/scripts/testorg3.sh b/first-network/scripts/testorg3.sh index 1668f45e..6d1930cd 100755 --- a/first-network/scripts/testorg3.sh +++ b/first-network/scripts/testorg3.sh @@ -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 diff --git a/first-network/scripts/upgrade_to_v11.sh b/first-network/scripts/upgrade_to_v11.sh index 69eb2fbd..93ab6f61 100755 --- a/first-network/scripts/upgrade_to_v11.sh +++ b/first-network/scripts/upgrade_to_v11.sh @@ -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 diff --git a/first-network/scripts/utils.sh b/first-network/scripts/utils.sh index 7509147e..a82eed8a 100755 --- a/first-network/scripts/utils.sh +++ b/first-network/scripts/utils.sh @@ -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 -# 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 ... +# 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 } diff --git a/high-throughput/README.md b/high-throughput/README.md index 0956f99d..a899792f 100644 --- a/high-throughput/README.md +++ b/high-throughput/README.md @@ -1,3 +1,9 @@ + + # 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 diff --git a/high-throughput/chaincode/high-throughput.go b/high-throughput/chaincode/high-throughput.go index 90888208..252c9805 100644 --- a/high-throughput/chaincode/high-throughput.go +++ b/high-throughput/chaincode/high-throughput.go @@ -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 diff --git a/high-throughput/scripts/channel-setup.sh b/high-throughput/scripts/channel-setup.sh index b9232602..2843ffe8 100755 --- a/high-throughput/scripts/channel-setup.sh +++ b/high-throughput/scripts/channel-setup.sh @@ -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 diff --git a/high-throughput/scripts/delete-invoke.sh b/high-throughput/scripts/delete-invoke.sh index be892a47..ec08035e 100755 --- a/high-throughput/scripts/delete-invoke.sh +++ b/high-throughput/scripts/delete-invoke.sh @@ -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'"]}' diff --git a/high-throughput/scripts/get-invoke.sh b/high-throughput/scripts/get-invoke.sh index aae4eee7..f89bbb2d 100755 --- a/high-throughput/scripts/get-invoke.sh +++ b/high-throughput/scripts/get-invoke.sh @@ -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'"]}' diff --git a/high-throughput/scripts/get-traditional.sh b/high-throughput/scripts/get-traditional.sh index c5327909..bb0fe522 100755 --- a/high-throughput/scripts/get-traditional.sh +++ b/high-throughput/scripts/get-traditional.sh @@ -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'"]}' diff --git a/high-throughput/scripts/install-chaincode.sh b/high-throughput/scripts/install-chaincode.sh index 014ad0fd..7817ae64 100755 --- a/high-throughput/scripts/install-chaincode.sh +++ b/high-throughput/scripts/install-chaincode.sh @@ -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 diff --git a/high-throughput/scripts/instantiate-chaincode.sh b/high-throughput/scripts/instantiate-chaincode.sh index 45eacbc3..25fe046c 100755 --- a/high-throughput/scripts/instantiate-chaincode.sh +++ b/high-throughput/scripts/instantiate-chaincode.sh @@ -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')" diff --git a/high-throughput/scripts/many-updates-traditional.sh b/high-throughput/scripts/many-updates-traditional.sh index 3f57e57d..921edc62 100755 --- a/high-throughput/scripts/many-updates-traditional.sh +++ b/high-throughput/scripts/many-updates-traditional.sh @@ -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'"]}' diff --git a/high-throughput/scripts/many-updates.sh b/high-throughput/scripts/many-updates.sh index ffedb7c9..13aaf026 100755 --- a/high-throughput/scripts/many-updates.sh +++ b/high-throughput/scripts/many-updates.sh @@ -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'"]}' & diff --git a/high-throughput/scripts/prunefast-invoke.sh b/high-throughput/scripts/prunefast-invoke.sh index 0db2d9bc..bd7b168c 100755 --- a/high-throughput/scripts/prunefast-invoke.sh +++ b/high-throughput/scripts/prunefast-invoke.sh @@ -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'"]}' diff --git a/high-throughput/scripts/prunesafe-invoke.sh b/high-throughput/scripts/prunesafe-invoke.sh index 8c39e422..e42019e8 100755 --- a/high-throughput/scripts/prunesafe-invoke.sh +++ b/high-throughput/scripts/prunesafe-invoke.sh @@ -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'"]}' diff --git a/high-throughput/scripts/setclienv.sh b/high-throughput/scripts/setclienv.sh index 9e7e8bc8..8e953500 100644 --- a/high-throughput/scripts/setclienv.sh +++ b/high-throughput/scripts/setclienv.sh @@ -1,2 +1,8 @@ +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + export CHANNEL_NAME=mychannel export CC_NAME=bigdatacc diff --git a/high-throughput/scripts/update-invoke.sh b/high-throughput/scripts/update-invoke.sh index 7f51f9ba..d49b2ccc 100755 --- a/high-throughput/scripts/update-invoke.sh +++ b/high-throughput/scripts/update-invoke.sh @@ -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'"]}' diff --git a/high-throughput/scripts/upgrade-chaincode.sh b/high-throughput/scripts/upgrade-chaincode.sh index 78d0b83f..add1b8c7 100755 --- a/high-throughput/scripts/upgrade-chaincode.sh +++ b/high-throughput/scripts/upgrade-chaincode.sh @@ -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')" diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh new file mode 100755 index 00000000..37beaf4d --- /dev/null +++ b/scripts/bootstrap.sh @@ -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 [] [] [][-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 diff --git a/scripts/fabric-preload.sh b/scripts/fabric-preload.sh deleted file mode 100755 index a88963ed..00000000 --- a/scripts/fabric-preload.sh +++ /dev/null @@ -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* -