├── .gitignore ├── meetup-180621 ├── chaincode │ ├── index.js │ ├── package.json │ └── cs04.js ├── challenge-01.md └── index.md ├── meetup-120321 ├── index.js ├── META-INF │ └── statedb │ │ └── couchdb │ │ └── indexRevenue.json ├── package.json ├── lib │ └── cs01.js └── index.md ├── meetup-231020 └── chaincode │ ├── abstore │ ├── go.mod │ ├── abstore.go │ └── go.sum │ └── abstore2 │ ├── go.mod │ ├── abstore2.go │ └── go.sum ├── meetup-260221 ├── index.js ├── cs01.sh ├── lib │ └── cs01.js └── index.md ├── meetup-290121 ├── index.md ├── docker-compose.yaml ├── fabric2DevModeDockerEdition.md └── fabric2DevMode.md ├── meetup-backlog ├── blocks.md └── index.md ├── meetup-260321 ├── client │ ├── ccp.json │ ├── helper.js │ ├── addtowallet.js │ └── index.js └── index.md ├── README.md ├── meetup-120221 ├── helper.js ├── ledgerActions.js ├── index.md └── caActions.js ├── meetup-181220 ├── crypto-config.yaml ├── docker-compose.yaml └── index.md ├── meetup-061120 ├── reproduce.md ├── assetTransfer.go ├── index.md └── helper.md └── meetup-061020 └── index.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /meetup-180621/chaincode/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const cs04Contract = require('./cs04.js'); 4 | 5 | module.exports.contracts = [cs04Contract]; -------------------------------------------------------------------------------- /meetup-120321/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const cs01Contract = require('./lib/cs01.js'); 4 | 5 | module.exports.Cs01Contract = cs01Contract; 6 | module.exports.contracts = [cs01Contract]; -------------------------------------------------------------------------------- /meetup-231020/chaincode/abstore/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hyperledger/fabric-samples/chaincode/abstore/go 2 | 3 | go 1.13 4 | 5 | require github.com/hyperledger/fabric-contract-api-go v1.1.0 -------------------------------------------------------------------------------- /meetup-231020/chaincode/abstore2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hyperledger/fabric-samples/chaincode/abstore/go 2 | 3 | go 1.13 4 | 5 | require github.com/hyperledger/fabric-contract-api-go v1.1.0 -------------------------------------------------------------------------------- /meetup-260221/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const cs01Contract = require('./lib/cs01.js'); 4 | 5 | module.exports.Cs01Contract = cs01Contract; 6 | module.exports.contracts = [cs01Contract]; -------------------------------------------------------------------------------- /meetup-120321/META-INF/statedb/couchdb/indexRevenue.json: -------------------------------------------------------------------------------- 1 | { 2 | "index":{ 3 | "fields":["revenueTs"] 4 | }, 5 | "ddoc":"indexRevenueTs", 6 | "name":"indexRevenueTs", 7 | "type":"json" 8 | } -------------------------------------------------------------------------------- /meetup-120321/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cs01-2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "fabric-chaincode-node start" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "fabric-contract-api": "^2.2.1", 13 | "fabric-shim": "^2.2.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /meetup-180621/chaincode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cs04", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "fabric-chaincode-node start" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "fabric-contract-api": "^2.2.1", 15 | "fabric-shim": "^2.2.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /meetup-290121/index.md: -------------------------------------------------------------------------------- 1 | # Meetup Support Material 2 | 3 | This guide will help you to get started with the fabric chaincode development. For this tutorial we are going to use a digital ocean droplet, but you can use an environment of your choice. 4 | 5 | First set up your system. For this follow this [guide](../meetup-061020/index.md) including the section: "Install Samples, Binaries and Docker Images". 6 | 7 | At this point we have two possibilities to use fabric from the development point of view. 8 | 9 | 1. [Fabric 2.2 Chaincode Devmode Environment - Binary Edition](fabric2DevMode.md) 10 | 2. [Fabric 2.2 Chaincode Devmode Environment - Docker Edition](fabric2DevModeDockerEdition.md) 11 | 12 | 13 | [Index](../README.md) -------------------------------------------------------------------------------- /meetup-backlog/blocks.md: -------------------------------------------------------------------------------- 1 | ## Peer channel 2 | 3 | ```bash 4 | # get new newset block on this leader 5 | peer channel fetch newest newest_mychannel.block -c mychannel -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 6 | 7 | # result could be something like 8 | # 2020-11-13 08:50:17.344 CET [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 9 | # 2020-11-13 08:50:17.346 CET [cli.common] readBlock -> INFO 002 Received block: 9 10 | 11 | # block number 9 is the latest block in the chain 12 | 13 | configtxlator proto_decode --type=common.Block --input=newest_mychannel.block | jq . 14 | ``` -------------------------------------------------------------------------------- /meetup-260321/client/ccp.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev-network", 3 | "version": "1.0.0", 4 | "client": { 5 | "organization": "SampleOrg", 6 | "connection": { 7 | "timeout": { 8 | "peer": { 9 | "endorser": "300" 10 | } 11 | } 12 | } 13 | }, 14 | "channels": { 15 | "ch1": { 16 | "orderers": ["localhost"], 17 | "peers": { 18 | "localhost": { 19 | "endorsingPeer": true, 20 | "chaincodeQuery": true, 21 | "eventSource": true 22 | } 23 | } 24 | } 25 | }, 26 | "organizations": { 27 | "SampleOrg": { 28 | "mspid": "SampleOrg", 29 | "peers": ["localhost"] 30 | } 31 | }, 32 | "orderers": { 33 | "localhost": { 34 | "url": "grpc://127.0.0.1:7050" 35 | } 36 | }, 37 | "peers": { 38 | "localhost": { 39 | "url": "grpc://127.0.0.1:7051" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /meetup-260221/cs01.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # how many tries? 4 | max=100 5 | 6 | # start the test 7 | start_time="$(date -u +%s.%N)" 8 | 9 | # set some env vars 10 | export FABRIC_CFG_PATH=../config 11 | . ./scripts/envVar.sh 12 | setGlobals 1 13 | 14 | # do the invoke 15 | for (( i = 0; i <= $max; i++ )) 16 | do 17 | key="a$i" 18 | echo '> TX '"${key}" 19 | 20 | # create random revenue between 1000 and 10000 21 | revenue=$((1000 + $RANDOM % 10000)) 22 | 23 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C channel1 -n cs01CC --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["storeCs","'$revenue'","2021-02-21T17:15:57.928Z","reve"]}' 24 | done 25 | # stop the test 26 | end_time="$(date -u +%s.%N)" 27 | 28 | # calc the duration and TPS 29 | elapsed="$(bc <<<"$end_time-$start_time")" 30 | tps="$(bc <<< "scale=0; $max/$elapsed")" 31 | 32 | # print the result 33 | echo "$max Invokes took a total of $elapsed seconds = $tps TPS" -------------------------------------------------------------------------------- /meetup-260321/client/helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * helper functions 3 | */ 4 | 5 | const path = require('path') 6 | const fs = require('fs') 7 | 8 | /** 9 | * loads the existing CCP 10 | */ 11 | exports.buildCCP = function() { 12 | // load the common connection configuration file 13 | const ccpPath = path.resolve(__dirname, 'ccp.json'); 14 | const fileExists = fs.existsSync(ccpPath); 15 | if (!fileExists) { 16 | throw new Error(`no such file or directory: ${ccpPath}`); 17 | } 18 | const contents = fs.readFileSync(ccpPath, 'utf8'); 19 | 20 | // build a JSON object from the file contents 21 | const ccp = JSON.parse(contents); 22 | return ccp; 23 | }; 24 | 25 | /** 26 | * Create a new wallet : Note that wallet is for managing identities. 27 | * @param {*} Wallets 28 | * @param {*} walletPath 29 | */ 30 | exports.buildWallet = async function (Wallets, walletPath) { 31 | let wallet; 32 | if (walletPath) { 33 | wallet = await Wallets.newFileSystemWallet(walletPath); 34 | //console.log(`Built a file system wallet at ${walletPath}`); 35 | } else { 36 | wallet = await Wallets.newInMemoryWallet(); 37 | //console.log('Built an in memory wallet'); 38 | } 39 | 40 | return wallet; 41 | }; 42 | 43 | /** 44 | * create a json string 45 | * @param {*} inputString 46 | */ 47 | exports.prettyJSONString = function(inputString) { 48 | return JSON.stringify(JSON.parse(inputString), null, 2); 49 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Samlinux Academy 2 | Hyperledger Fabric learning materials. 3 | 4 | | Meetup | Topic | 5 | | ------------- |-------------| 6 | | [06.10.2020](./meetup-061020/index.md)| This meetup is about a HLF 2.2.x installation on a DigitalOcean Droplet. | 7 | | [23.10.2020](./meetup-231020/index.md)| This meetup is about the CC installation and upgrade process. | 8 | | [06.11.2020](./meetup-061120/index.md)| This meetup is about external vs internal chaincode (CC). | 9 | | [20.11.2020](./meetup-201120/index.md)| This meetup is about Channels, all about channels. | 10 | | [18.12.2020](./meetup-181220/index.md)| This meetup is about the creation of a persistent three ORG fabric network with a one node RAFT orderer. | 11 | | [29.01.2021](./meetup-290121/index.md)| This meetup is about the peer-devmode and a comparison between docker and bianry. | 12 | | [12.02.2021](./meetup-120221/index.md)| This meetup is about how you can use Node.js as an application developer. | 13 | | [26.02.2021](./meetup-260221/index.md)| Part 1 - Node.js development; Comparison between Node.js and Golang chaincode. | 14 | | [12.03.2021](./meetup-120321/index.md)| Part 2 - Node.js development; Extends part 1 with a couchDb query. | 15 | | [26.03.2021](./meetup-260321/index.md)| Part 3 - Node.js development; Access development environment with Node.js SDK. | 16 | | [18.06.2021](./meetup-180621/index.md)| Attribute-based access controll (ABAC) with Node.js | 17 | -------------------------------------------------------------------------------- /meetup-120221/helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * helper functions 3 | */ 4 | 5 | const path = require('path') 6 | const fs = require('fs') 7 | 8 | /** 9 | * loads the existing CCP for Org1 10 | */ 11 | exports.buildCCPOrg1 = function() { 12 | // load the common connection configuration file 13 | const ccpPath = path.resolve(__dirname, '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); 14 | const fileExists = fs.existsSync(ccpPath); 15 | if (!fileExists) { 16 | throw new Error(`no such file or directory: ${ccpPath}`); 17 | } 18 | const contents = fs.readFileSync(ccpPath, 'utf8'); 19 | 20 | // build a JSON object from the file contents 21 | const ccp = JSON.parse(contents); 22 | 23 | console.log(`Loaded the network configuration located at ${ccpPath}`); 24 | return ccp; 25 | }; 26 | 27 | /** 28 | * Create a new wallet : Note that wallet is for managing identities. 29 | * @param {*} Wallets 30 | * @param {*} walletPath 31 | */ 32 | exports.buildWallet = async function (Wallets, walletPath) { 33 | let wallet; 34 | if (walletPath) { 35 | wallet = await Wallets.newFileSystemWallet(walletPath); 36 | console.log(`Built a file system wallet at ${walletPath}`); 37 | } else { 38 | wallet = await Wallets.newInMemoryWallet(); 39 | console.log('Built an in memory wallet'); 40 | } 41 | 42 | return wallet; 43 | }; 44 | 45 | /** 46 | * create a json string 47 | * @param {*} inputString 48 | */ 49 | exports.prettyJSONString = function(inputString) { 50 | return JSON.stringify(JSON.parse(inputString), null, 2); 51 | } -------------------------------------------------------------------------------- /meetup-260321/client/addtowallet.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // global nodejs modules 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | 7 | // fabric requirements 8 | const { Wallets } = require('fabric-network'); 9 | 10 | // path correcture 11 | const fixtures = path.resolve(__dirname, '../'); 12 | 13 | // Identity to credentials to be stored in the wallet 14 | const credPath = path.join(fixtures, '/fabric/sampleconfig'); 15 | const certificate = fs.readFileSync(path.join(credPath, '/msp/admincerts/admincert.pem')).toString(); 16 | const privateKey = fs.readFileSync(path.join(credPath, '/msp/keystore/key.pem')).toString(); 17 | 18 | // set the identity lablel 19 | const identityLabel = 'admin'; 20 | 21 | // main function to add an existing identity 22 | async function init() { 23 | 24 | try { 25 | 26 | // A wallet stores a collection of identities 27 | const wallet = await Wallets.newFileSystemWallet('./wallet'); 28 | 29 | // set the identity credentials 30 | const identity = { 31 | credentials: { 32 | certificate, 33 | privateKey 34 | }, 35 | mspId: 'SampleOrg', 36 | type: 'X.509' 37 | } 38 | 39 | // Load credentials into wallet 40 | await wallet.put(identityLabel, identity); 41 | 42 | } catch (error) { 43 | console.log(`Error adding to wallet. ${error}`); 44 | console.log(error.stack); 45 | } 46 | } 47 | 48 | // start the import 49 | init().then(() => { 50 | console.log(`Identity ${identityLabel} successfully added to the wallet.`); 51 | }).catch((e) => { 52 | console.log(e); 53 | console.log(e.stack); 54 | process.exit(-1); 55 | }); -------------------------------------------------------------------------------- /meetup-290121/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # Copyright IBM Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | 6 | version: '2' 7 | 8 | networks: 9 | dev-network: 10 | 11 | services: 12 | 13 | orderer.example.com: 14 | container_name: orderer.example.com 15 | image: hyperledger/fabric-orderer:$IMAGE_TAG 16 | environment: 17 | - FABRIC_LOGGING_SPEC=DEBUG 18 | - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 19 | - ORDERER_GENERAL_LISTENPORT=7050 20 | - ORDERER_GENERAL_GENESISMETHOD=file 21 | - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block 22 | - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp 23 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric 24 | command: orderer 25 | volumes: 26 | - ./sampleconfig/msp:/var/hyperledger/orderer/msp 27 | - ./artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block 28 | - ./ledgerData/orderer:/var/hyperledger/production/orderer 29 | ports: 30 | - 7050:7050 31 | networks: 32 | - dev-network 33 | 34 | peer0.org1.example.com: 35 | container_name: peer0.org1.example.com 36 | image: hyperledger/fabric-peer:$IMAGE_TAG 37 | environment: 38 | #Generic peer variables 39 | - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 40 | # the following setting starts chaincode containers on the same 41 | # bridge network as the peers 42 | # https://docs.docker.com/compose/networking/ 43 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_dev-network 44 | - FABRIC_LOGGING_SPEC=DEBUG 45 | - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 46 | - CORE_PEER_ID=peer0.org1.example.com 47 | - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 48 | - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052 49 | - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 50 | volumes: 51 | - /var/run/:/host/var/run/ 52 | - ./ledgerData/:/var/hyperledger/production 53 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer 54 | command: peer node start --peer-chaincodedev=true 55 | ports: 56 | - 7051:7051 57 | - 7052:7052 58 | networks: 59 | - dev-network 60 | -------------------------------------------------------------------------------- /meetup-120221/ledgerActions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ledger - Actions 3 | */ 4 | 5 | // node.js includes 6 | const helper = require('./helper') 7 | const path = require('path') 8 | 9 | // fabric includes 10 | const { Gateway, Wallets } = require('fabric-network'); 11 | const walletPath = path.join(__dirname, 'wallet'); 12 | 13 | // some vars 14 | const org1UserId = 'sabine'; 15 | const channelName = 'channel1'; 16 | const chaincodeName = 'basic'; 17 | 18 | async function main () { 19 | try { 20 | // build CCP 21 | const ccp = helper.buildCCPOrg1(); 22 | 23 | // setup the wallet to hold the credentials of the application user 24 | const wallet = await helper.buildWallet(Wallets, walletPath); 25 | 26 | // Create a new gateway instance for interacting with the fabric network. 27 | // In a real application this would be done as the backend server session is setup for 28 | // a user that has been verified. 29 | const gateway = new Gateway(); 30 | 31 | // setup the gateway instance 32 | // The user will now be able to create connections to the fabric network and be able to 33 | // submit transactions and query. All transactions submitted by this gateway will be 34 | // signed by this user using the credentials stored in the wallet. 35 | await gateway.connect(ccp, { 36 | wallet, 37 | identity: org1UserId, 38 | discovery: { enabled: true, asLocalhost: true } // using asLocalhost as this gateway is using a fabric network deployed locally 39 | }); 40 | 41 | // Build a network instance based on the channel where the smart contract is deployed 42 | const network = await gateway.getNetwork(channelName); 43 | 44 | // Get the contract from the network. 45 | const contract = network.getContract(chaincodeName); 46 | 47 | let args = process.argv 48 | if(args[2] === 'GetAllAssets'){ 49 | let result = await contract.evaluateTransaction('GetAllAssets'); 50 | console.log(`${helper.prettyJSONString(result.toString())}`); 51 | } 52 | else if(args[2] === 'ReadAsset'){ 53 | let asset = args[3] 54 | result = await contract.evaluateTransaction('ReadAsset', asset); 55 | console.log(`${helper.prettyJSONString(result.toString())}`); 56 | } 57 | else if(args[2] === 'CreateAsset'){ 58 | let r = await contract.submitTransaction('CreateAsset', 'asset14', 'yellow', '5', 'Snorre3', '1300'); 59 | console.log('*** Result: committed', r.toString()); 60 | } 61 | else { 62 | console.log('...') 63 | } 64 | // disconnect form the network 65 | gateway.disconnect(); 66 | } 67 | catch(e){ 68 | throw new Error(e) 69 | } 70 | } 71 | 72 | main() 73 | -------------------------------------------------------------------------------- /meetup-260321/client/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ledger - Actions 3 | */ 4 | 5 | // node.js includes 6 | const helper = require('./helper') 7 | const path = require('path') 8 | 9 | // fabric includes 10 | const { Gateway, Wallets } = require('fabric-network'); 11 | const walletPath = path.join(__dirname, 'wallet'); 12 | 13 | // some vars 14 | const identityLabel = 'admin'; 15 | const channelName = 'ch1'; 16 | const chaincodeName = 'mycc'; 17 | 18 | async function main () { 19 | try { 20 | 21 | // build CCP 22 | const ccp = helper.buildCCP(); 23 | 24 | // setup the wallet to hold the credentials of the application user 25 | let wallet = await helper.buildWallet(Wallets, walletPath); 26 | 27 | // Create a new gateway instance for interacting with the fabric network. 28 | // In a real application this would be done as the backend server session is setup for 29 | // a user that has been verified. 30 | const gateway = new Gateway(); 31 | 32 | // setup the gateway instance 33 | // The user will now be able to create connections to the fabric network and be able to 34 | // submit transactions and query. All transactions submitted by this gateway will be 35 | // signed by this user using the credentials stored in the wallet. 36 | 37 | // using asLocalhost as this gateway is using a fabric network deployed locally 38 | try { 39 | await gateway.connect(ccp, { 40 | wallet, 41 | identity: identityLabel, 42 | discovery: { enabled: false, asLocalhost: true } 43 | }); 44 | } catch (e){ 45 | throw new Error(e) 46 | } 47 | 48 | // Build a network instance based on the channel where the smart contract is deployed 49 | const network = await gateway.getNetwork(channelName); 50 | 51 | // Get the contract from the network. 52 | const contract = network.getContract(chaincodeName); 53 | 54 | // import CLI arguments 55 | let args = process.argv; 56 | 57 | if(args[2] === 'GetAllAssets'){ 58 | let result = await contract.evaluateTransaction('GetAllAssets'); 59 | console.log(`${helper.prettyJSONString(result.toString())}`); 60 | } 61 | else if(args[2] === 'ReadAsset'){ 62 | let asset = args[3] 63 | result = await contract.evaluateTransaction('ReadAsset', asset); 64 | console.log(`${helper.prettyJSONString(result.toString())}`); 65 | } 66 | else if(args[2] === 'CreateAsset'){ 67 | let r = await contract.submitTransaction('CreateAsset', 'A5', 'yellow', '5', 'Sonnenschein', 5300); 68 | console.log('*** Result: committed', r.toString()); 69 | } 70 | else { 71 | console.log('...') 72 | } 73 | // disconnect form the network 74 | gateway.disconnect(); 75 | } 76 | catch(e){ 77 | throw new Error(e) 78 | } 79 | } 80 | 81 | // start the CLI process 82 | main() -------------------------------------------------------------------------------- /meetup-231020/chaincode/abstore/abstore.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright IBM Corp. 2016 All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "strconv" 23 | 24 | "github.com/hyperledger/fabric-contract-api-go/contractapi" 25 | ) 26 | 27 | // ABstore Chaincode implementation 28 | type ABstore struct { 29 | contractapi.Contract 30 | } 31 | 32 | func (t *ABstore) Init(ctx contractapi.TransactionContextInterface, A string, Aval int, B string, Bval int) error { 33 | fmt.Println("ABstore Init") 34 | var err error 35 | // Initialize the chaincode 36 | fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) 37 | // Write the state to the ledger 38 | err = ctx.GetStub().PutState(A, []byte(strconv.Itoa(Aval))) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | err = ctx.GetStub().PutState(B, []byte(strconv.Itoa(Bval))) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return nil 49 | } 50 | 51 | // Transaction makes payment of X units from A to B 52 | func (t *ABstore) Invoke(ctx contractapi.TransactionContextInterface, A, B string, X int) error { 53 | var err error 54 | var Aval int 55 | var Bval int 56 | // Get the state from the ledger 57 | // TODO: will be nice to have a GetAllState call to ledger 58 | Avalbytes, err := ctx.GetStub().GetState(A) 59 | if err != nil { 60 | return fmt.Errorf("Failed to get state") 61 | } 62 | if Avalbytes == nil { 63 | return fmt.Errorf("Entity not found") 64 | } 65 | Aval, _ = strconv.Atoi(string(Avalbytes)) 66 | 67 | Bvalbytes, err := ctx.GetStub().GetState(B) 68 | if err != nil { 69 | return fmt.Errorf("Failed to get state") 70 | } 71 | if Bvalbytes == nil { 72 | return fmt.Errorf("Entity not found") 73 | } 74 | Bval, _ = strconv.Atoi(string(Bvalbytes)) 75 | 76 | // Perform the execution 77 | Aval = Aval - X 78 | Bval = Bval + X 79 | fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) 80 | 81 | // Write the state back to the ledger 82 | err = ctx.GetStub().PutState(A, []byte(strconv.Itoa(Aval))) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | err = ctx.GetStub().PutState(B, []byte(strconv.Itoa(Bval))) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | return nil 93 | } 94 | 95 | // Delete an entity from state 96 | func (t *ABstore) Delete(ctx contractapi.TransactionContextInterface, A string) error { 97 | 98 | // Delete the key from the state in ledger 99 | err := ctx.GetStub().DelState(A) 100 | if err != nil { 101 | return fmt.Errorf("Failed to delete state") 102 | } 103 | 104 | return nil 105 | } 106 | 107 | // Query callback representing the query of a chaincode 108 | func (t *ABstore) Query(ctx contractapi.TransactionContextInterface, A string) (string, error) { 109 | var err error 110 | // Get the state from the ledger 111 | Avalbytes, err := ctx.GetStub().GetState(A) 112 | if err != nil { 113 | jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" 114 | return "", errors.New(jsonResp) 115 | } 116 | 117 | if Avalbytes == nil { 118 | jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" 119 | return "", errors.New(jsonResp) 120 | } 121 | 122 | jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" 123 | fmt.Printf("Query Response:%s\n", jsonResp) 124 | return string(Avalbytes), nil 125 | } 126 | 127 | func main() { 128 | cc, err := contractapi.NewChaincode(new(ABstore)) 129 | if err != nil { 130 | panic(err.Error()) 131 | } 132 | if err := cc.Start(); err != nil { 133 | fmt.Printf("Error starting ABstore chaincode: %s", err) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /meetup-180621/challenge-01.md: -------------------------------------------------------------------------------- 1 | # Challenge 01 2 | Try installing the sample chaincode cs04 within the official test network of fabric 2.2 Try to use the ./network.sh script. 3 | 4 | **Please try it yourself first and then follow the instructions!** 5 | 6 | ```bash 7 | # switch to the base folder 8 | cd fabric-samples/test-network 9 | 10 | # bring up the network 11 | ./network.sh up createChannel -c channel1 -ca 12 | 13 | # Install the chaincode 14 | ./network.sh deployCC -c channel1 -ccn cs04 -ccl javascript -ccv 1 -ccs 1 -ccp ../../sdg-dev-network/chaincode/nodejs/cs04/ 15 | 16 | # set env peer0 Org1 17 | . ./scripts/envVar.sh 18 | 19 | # show if some containers are running 20 | docker ps --format "{{.ID}} {{.Names}}" 21 | 22 | 988f8aea5734 dev-peer0.org2.example.com-cs04_1-8bb43bb8d3c64721968bc157979cd5ef6e0098759421c2703f935676921e815f 23 | e87e590c76c0 dev-peer0.org1.example.com-cs04_1-8bb43bb8d3c64721968bc157979cd5ef6e0098759421c2703f935676921e815f 24 | 160f5b00bdd9 cli 25 | 96be768b2027 orderer.example.com 26 | 8946a2b5b7e5 peer0.org2.example.com 27 | 6e26aa81cf71 peer0.org1.example.com 28 | 027805fe332a ca_org2 29 | 380834ba12b9 ca_orderer 30 | 816606a4c959 ca_org1 31 | 32 | ``` 33 | 34 | Try to use the chaincode example. Register and enroll the identities. 35 | 36 | ```bash 37 | export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ 38 | 39 | fabric-ca-client register --id.name writer --id.secret writerpw --id.type client --id.attrs 'samlinux.writer=true:ecert' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 40 | 41 | fabric-ca-client register --id.name reader --id.secret readerpw --id.type client --id.attrs 'samlinux.reader=true:ecert' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 42 | 43 | fabric-ca-client enroll -u https://writer:writerpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/writer@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 44 | 45 | fabric-ca-client enroll -u https://reader:readerpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 46 | 47 | cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/writer@org1.example.com/msp/config.yaml" 48 | 49 | cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp/config.yaml" 50 | 51 | tree -L 1 organizations/peerOrganizations/org1.example.com/users/ 52 | ``` 53 | 54 | Try and play with the chaincode. 55 | ```bash 56 | 57 | # use Org1 env vars 58 | setGlobals 1 59 | 60 | # export path to fabric config 61 | export FABRIC_CFG_PATH=../config/ 62 | 63 | # set the CORE_PEER_MSPCONFIGPATH variable to the users MSP 64 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/writer@org1.example.com/msp 65 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp 66 | 67 | # invoke 68 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C channel1 -n cs04 --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["set","{\"no\":\"a1\", \"desc\":\"Product number 1\",\"amount\":120, \"price\":\"10.50\", \"type\":\"brick\"}"]}' 69 | 70 | # query 71 | peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C channel1 -n cs04 --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -C channel1 -n cs04 -c '{"Args":["get","a1"]}' | jq . 72 | ``` 73 | -------------------------------------------------------------------------------- /meetup-181220/crypto-config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright IBM Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | 6 | # --------------------------------------------------------------------------- 7 | # "OrdererOrgs" - Definition of organizations managing orderer nodes 8 | # --------------------------------------------------------------------------- 9 | OrdererOrgs: 10 | # --------------------------------------------------------------------------- 11 | # Orderer 12 | # --------------------------------------------------------------------------- 13 | - Name: Orderer 14 | Domain: example.com 15 | EnableNodeOUs: true 16 | # --------------------------------------------------------------------------- 17 | # "Specs" - See PeerOrgs for complete description 18 | # --------------------------------------------------------------------------- 19 | Specs: 20 | - Hostname: orderer 21 | SANS: 22 | - localhost 23 | 24 | # --------------------------------------------------------------------------- 25 | # "PeerOrgs" - Definition of organizations managing peer nodes 26 | # --------------------------------------------------------------------------- 27 | PeerOrgs: 28 | # --------------------------------------------------------------------------- 29 | # Org1 30 | # --------------------------------------------------------------------------- 31 | - Name: Org1 32 | Domain: org1.example.com 33 | EnableNodeOUs: true 34 | # --------------------------------------------------------------------------- 35 | # "Specs" 36 | # --------------------------------------------------------------------------- 37 | # Uncomment this section to enable the explicit definition of hosts in your 38 | # configuration. Most users will want to use Template, below 39 | # 40 | # Specs is an array of Spec entries. Each Spec entry consists of two fields: 41 | # - Hostname: (Required) The desired hostname, sans the domain. 42 | # - CommonName: (Optional) Specifies the template or explicit override for 43 | # the CN. By default, this is the template: 44 | # 45 | # "{{.Hostname}}.{{.Domain}}" 46 | # 47 | # which obtains its values from the Spec.Hostname and 48 | # Org.Domain, respectively. 49 | # --------------------------------------------------------------------------- 50 | # - Hostname: foo # implicitly "foo.org1.example.com" 51 | # CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above 52 | # - Hostname: bar 53 | # - Hostname: baz 54 | # --------------------------------------------------------------------------- 55 | # "Template" 56 | # --------------------------------------------------------------------------- 57 | # Allows for the definition of 1 or more hosts that are created sequentially 58 | # from a template. By default, this looks like "peer%d" from 0 to Count-1. 59 | # You may override the number of nodes (Count), the starting index (Start) 60 | # or the template used to construct the name (Hostname). 61 | # 62 | # Note: Template and Specs are not mutually exclusive. You may define both 63 | # sections and the aggregate nodes will be created for you. Take care with 64 | # name collisions 65 | # --------------------------------------------------------------------------- 66 | Template: 67 | Count: 1 68 | SANS: 69 | - localhost 70 | # Start: 5 71 | # Hostname: {{.Prefix}}{{.Index}} # default 72 | # --------------------------------------------------------------------------- 73 | # "Users" 74 | # --------------------------------------------------------------------------- 75 | # Count: The number of user accounts _in addition_ to Admin 76 | # --------------------------------------------------------------------------- 77 | Users: 78 | Count: 1 79 | # 80 | - Name: Org2 81 | Domain: org2.example.com 82 | EnableNodeOUs: true 83 | Template: 84 | Count: 1 85 | SANS: 86 | - localhost 87 | Users: 88 | Count: 1 89 | 90 | - Name: Org3 91 | Domain: org3.example.com 92 | EnableNodeOUs: true 93 | Template: 94 | Count: 1 95 | SANS: 96 | - localhost 97 | Users: 98 | Count: 1 -------------------------------------------------------------------------------- /meetup-260221/lib/cs01.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // SDK Library to asset with writing the logic 4 | const { Contract } = require('fabric-contract-api'); 5 | 6 | /** 7 | * ToDo 8 | * - couchDB implementation 9 | */ 10 | class Cs01Contract extends Contract { 11 | 12 | constructor(){ 13 | super('Cs01Contract'); 14 | this.TxId = '' 15 | } 16 | 17 | /** 18 | * is done befor the transaction starts 19 | * @param {*} ctx 20 | */ 21 | async beforeTransaction(ctx) { 22 | // default implementation is do nothing 23 | this.TxId = ctx.stub.getTxID(); 24 | console.log(`we can do some logging for ${this.TxId} !!`) 25 | } 26 | 27 | /** 28 | * is done after the transaction ends 29 | * @param {*} ctx 30 | * @param {*} result 31 | */ 32 | async afterTransaction(ctx, result) { 33 | // default implementation is do nothing 34 | console.log(`TX ${this.TxId} done !!`) 35 | } 36 | 37 | /** 38 | * store a new state 39 | * @param {*} ctx 40 | * @param {*} revenue 41 | * @param {*} revenueTs 42 | * @param {*} cstype 43 | */ 44 | async storeCs(ctx, revenue, revenueTs, cstype ) { 45 | 46 | // calc our values 47 | let _commission = 0 48 | let _revenue = parseFloat(revenue) 49 | let _revenueTs = revenueTs 50 | 51 | if(cstype === 'reco'){ 52 | // 1 % 53 | _commission = _revenue / 100 * 1 54 | } else if(cstype === 'reve'){ 55 | // 10 % 56 | _commission = _revenue / 100 * 10 57 | } 58 | 59 | // compose our model 60 | let model = { 61 | revenue : _revenue, 62 | commission : _commission, 63 | revenueTs: _revenueTs, 64 | cstype: cstype, 65 | txId: this.TxId 66 | } 67 | 68 | try { 69 | 70 | // store the composite key with a the value 71 | let indexName = 'year~month~txid' 72 | 73 | let _keyHelper = new Date(revenueTs) 74 | let _keyYearAsString = _keyHelper.getFullYear().toString() 75 | let _keyMonthAsString = _keyHelper.getMonth().toString() 76 | 77 | let yearMonthIndexKey = await ctx.stub.createCompositeKey(indexName, [_keyYearAsString, _keyMonthAsString, this.TxId]); 78 | 79 | //console.info(yearMonthIndexKey, _keyYearAsString, _keyMonthAsString, this.TxId); 80 | 81 | // store the new state 82 | await ctx.stub.putState(yearMonthIndexKey, Buffer.from(JSON.stringify(model))); 83 | 84 | // compose the return values 85 | return { 86 | key: _keyYearAsString+'~'+_keyMonthAsString+'~'+this.TxId 87 | }; 88 | 89 | } catch(e){ 90 | throw new Error(`The tx ${this.TxId} can not be stored: ${e}`); 91 | } 92 | } 93 | 94 | /** 95 | * get all in a given year and month 96 | * 97 | * @param {*} ctx 98 | * @param {*} year 99 | * @param {*} month 100 | */ 101 | async getCsByYearMonth(ctx){ 102 | 103 | // we use the args option 104 | const args = ctx.stub.getArgs(); 105 | 106 | // we split the key into single peaces 107 | const keyValues = args[1].split('~') 108 | 109 | // collect the keys 110 | let keys = [] 111 | keyValues.forEach(element => keys.push(element)) 112 | 113 | // do the query 114 | let resultsIterator = await ctx.stub.getStateByPartialCompositeKey('year~month~txid', keys); 115 | 116 | // prepare the result 117 | const allResults = []; 118 | while (true) { 119 | const res = await resultsIterator.next(); 120 | 121 | if (res.value) { 122 | // if not a getHistoryForKey iterator then key is contained in res.value.key 123 | allResults.push(res.value.value.toString('utf8')); 124 | // console.log('V:',res.value.value.toString('utf8')) 125 | // console.log('K:',res.value.key.toString('utf8')) 126 | } 127 | 128 | // check to see if we have reached then end 129 | if (res.done) { 130 | // explicitly close the iterator 131 | await resultsIterator.close(); 132 | return allResults; 133 | } 134 | } 135 | } 136 | }; 137 | 138 | module.exports = Cs01Contract -------------------------------------------------------------------------------- /meetup-231020/chaincode/abstore2/abstore2.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright IBM Corp. 2016 All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "strconv" 23 | "github.com/hyperledger/fabric-contract-api-go/contractapi" 24 | ) 25 | 26 | // ABstore Chaincode implementation 27 | type ABstore struct { 28 | contractapi.Contract 29 | } 30 | 31 | func (t *ABstore) Init(ctx contractapi.TransactionContextInterface, A string, Aval int, B string, Bval int) error { 32 | fmt.Println("ABstore Init") 33 | var err error 34 | // Initialize the chaincode 35 | fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) 36 | // Write the state to the ledger 37 | err = ctx.GetStub().PutState(A, []byte(strconv.Itoa(Aval))) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | err = ctx.GetStub().PutState(B, []byte(strconv.Itoa(Bval))) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | return nil 48 | } 49 | 50 | // Transaction makes payment of X units from A to B 51 | func (t *ABstore) Invoke(ctx contractapi.TransactionContextInterface, A, B string, X int) error { 52 | var err error 53 | var Aval int 54 | var Bval int 55 | var Feeval int 56 | var Feecurrent int 57 | var Fee int 58 | var FeeHolder string 59 | 60 | Fee = 2 61 | FeeHolder = "bank" 62 | 63 | // Get the state from the ledger 64 | Avalbytes, err := ctx.GetStub().GetState(A) 65 | if err != nil { 66 | return fmt.Errorf("Failed to get state") 67 | } 68 | if Avalbytes == nil { 69 | return fmt.Errorf("Entity not found") 70 | } 71 | Aval, _ = strconv.Atoi(string(Avalbytes)) 72 | 73 | Bvalbytes, err := ctx.GetStub().GetState(B) 74 | if err != nil { 75 | return fmt.Errorf("Failed to get state") 76 | } 77 | if Bvalbytes == nil { 78 | return fmt.Errorf("Entity not found") 79 | } 80 | Bval, _ = strconv.Atoi(string(Bvalbytes)) 81 | 82 | // upgrade 83 | // get bank value 84 | // ------------------- 85 | Bankvalbytes, err := ctx.GetStub().GetState(FeeHolder) 86 | if err != nil { 87 | return fmt.Errorf("Failed to get state") 88 | } 89 | if Bankvalbytes == nil { 90 | Feecurrent = 0 91 | } else { 92 | Feecurrent, _ = strconv.Atoi(string(Bankvalbytes)) 93 | } 94 | 95 | // upgrade 96 | //cal the fee 97 | Feeval = (X / 100 * Fee) 98 | 99 | // Perform the execution 100 | Aval = Aval - X 101 | Bval = Bval + (X - Feeval) 102 | 103 | fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) 104 | fmt.Printf("Fee = %d\n", Feeval) 105 | 106 | // Write the state back to the ledger 107 | err = ctx.GetStub().PutState(A, []byte(strconv.Itoa(Aval))) 108 | if err != nil { 109 | return err 110 | } 111 | 112 | err = ctx.GetStub().PutState(B, []byte(strconv.Itoa(Bval))) 113 | if err != nil { 114 | return err 115 | } 116 | // upgrade 117 | var NewFeeVal int 118 | NewFeeVal = Feecurrent + Feeval 119 | err = ctx.GetStub().PutState(FeeHolder, []byte(strconv.Itoa(NewFeeVal))) 120 | if err != nil { 121 | return err 122 | } 123 | 124 | return nil 125 | } 126 | 127 | // Delete an entity from state 128 | func (t *ABstore) Delete(ctx contractapi.TransactionContextInterface, A string) error { 129 | 130 | // Delete the key from the state in ledger 131 | err := ctx.GetStub().DelState(A) 132 | if err != nil { 133 | return fmt.Errorf("Failed to delete state") 134 | } 135 | 136 | return nil 137 | } 138 | 139 | // Query callback representing the query of a chaincode 140 | func (t *ABstore) Query(ctx contractapi.TransactionContextInterface, A string) (string, error) { 141 | var err error 142 | // Get the state from the ledger 143 | Avalbytes, err := ctx.GetStub().GetState(A) 144 | if err != nil { 145 | jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" 146 | return "", errors.New(jsonResp) 147 | } 148 | 149 | if Avalbytes == nil { 150 | jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" 151 | return "", errors.New(jsonResp) 152 | } 153 | 154 | jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" 155 | fmt.Printf("Query Response:%s\n", jsonResp) 156 | return string(Avalbytes), nil 157 | } 158 | 159 | func main() { 160 | cc, err := contractapi.NewChaincode(new(ABstore)) 161 | if err != nil { 162 | panic(err.Error()) 163 | } 164 | if err := cc.Start(); err != nil { 165 | fmt.Printf("Error starting ABstore chaincode: %s", err) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /meetup-061120/reproduce.md: -------------------------------------------------------------------------------- 1 | # Reproduce the asset-transfer-basic/chaincode-external example 2 | 3 | fabric version 2.2.1 4 | 5 | ```bash 6 | apt install tree jq make g++ 7 | ``` 8 | 9 | ## Edit config/core.yaml 10 | ```bash 11 | externalBuilders: [] 12 | - path: /opt/gopath/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external/sampleBuilder 13 | name: external-sample-builder 14 | ``` 15 | 16 | ## Edit docker-compose-test-net.yaml 17 | 18 | Add these two volumns by both peers 19 | ```bash 20 | - ../..:/opt/gopath/src/github.com/hyperledger/fabric-samples 21 | - ../../config/core.yaml:/etc/hyperledger/fabric/core.yaml 22 | ``` 23 | 24 | ## Package the chaoncode 25 | 26 | ```bash 27 | cd ./fabric/fabric-samples/asset-transfer-basic/chaincode-external 28 | 29 | tar cfz code.tar.gz connection.json 30 | tar cfz asset-transfer-basic-external.tgz metadata.json code.tar.gz 31 | ``` 32 | 33 | ## Start the test-network 34 | ```bash 35 | ./network.sh up createChannel -c mychannel -ca 36 | 37 | ``` 38 | 39 | ## Installing the external chaincode 40 | ```bash 41 | export FABRIC_CFG_PATH=$HOME/fabric/fabric-samples/config/ 42 | 43 | . ./scripts/envVar.sh 44 | 45 | # Install the asset-transfer-basic-external.tar.gz chaincode on org1: 46 | setGlobals 1 47 | peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz 48 | 49 | 50 | # Install the asset-transfer-basic-external.tar.gz chaincode on org2: 51 | setGlobals 2 52 | peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz 53 | 54 | export PKGID=basic_1.0:2555c3cc621aedc7cfe296ca50a934e1386cf853fb572f69ea115e3eb3a57edb 55 | 56 | ``` 57 | 58 | ## Edit the chaincode.env file 59 | ```bash 60 | vi ../asset-transfer-basic/chaincode-external/chaincode.env 61 | # edit chaoncode_id 62 | CHAINCODE_ID=basic_1.0:2555c3cc621aedc7cfe296ca50a934e1386cf853fb572f69ea115e3eb3a57edb 63 | ``` 64 | ## Running the Asset-Transfer-Basic external service 65 | ```bash 66 | cd ../asset-transfer-basic/chaincode-external/ 67 | docker build -t hyperledger/asset-transfer-basic . 68 | 69 | ``` 70 | 71 | ## Start the Asset-Transfer-Basic service: 72 | ```bash 73 | docker run -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode.env --network=net_test hyperledger/asset-transfer-basic 74 | ``` 75 | 76 | ## Finish deploying the Asset-Transfer-Basic external chaincode 77 | ```bash 78 | setGlobals 2 79 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1 80 | 81 | setGlobals 1 82 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1 83 | 84 | peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles $PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1.0 --sequence 1 85 | 86 | ``` 87 | 88 | ## Using the Asset-Transfer-Basic external chaincode 89 | ```bash 90 | cd ../../fabric-samples/asset-transfer-basic/application-javascript 91 | 92 | rm -rf wallet # in case you ran this before 93 | npm install 94 | node app.js 95 | 96 | ``` 97 | 98 | ## Use the CLI 99 | ```bash 100 | export FABRIC_CFG_PATH=$HOME/fabric/fabric-samples/config/ 101 | 102 | . ./scripts/envVar.sh 103 | 104 | setGlobals 1 105 | peer chaincode query -C mychannel -n basic -c '{"function":"ReadAsset","Args":["asset1"]}' 106 | 107 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"CreateAsset","Args":["roland2", "yellow", "5", "Tom", "1300"]}' 108 | 109 | peer chaincode query -C mychannel -n basic -c '{"function":"ReadAsset","Args":["roland1"]}' 110 | ``` 111 | -------------------------------------------------------------------------------- /meetup-120321/lib/cs01.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // SDK Library to asset with writing the logic 4 | const { Contract } = require('fabric-contract-api'); 5 | 6 | class Cs01Contract extends Contract { 7 | 8 | constructor(){ 9 | super('Cs01Contract'); 10 | this.TxId = '' 11 | } 12 | 13 | async beforeTransaction(ctx) { 14 | // default implementation is do nothing 15 | this.TxId = ctx.stub.getTxID(); 16 | console.log(`we can do some logging for ${this.TxId} and many more !!`) 17 | } 18 | 19 | async storeCs(ctx, revenue, revenueTs, cstype ) { 20 | // calc our values 21 | let _commission = 0 22 | let _revenue = parseFloat(revenue) 23 | let _revenueTs = revenueTs 24 | 25 | if(cstype === 'reco'){ 26 | // 1 % 27 | _commission = _revenue / 100 * 1 28 | } else if(cstype === 'reve'){ 29 | // 10 % 30 | _commission = _revenue / 100 * 10 31 | } 32 | 33 | // compose our model 34 | let model = { 35 | revenue : _revenue, 36 | commission : _commission, 37 | revenueTs: _revenueTs, 38 | cstype: cstype, 39 | txId: this.TxId 40 | } 41 | 42 | try { 43 | 44 | // store the composite key with a the value 45 | let indexName = 'year~month~txid' 46 | 47 | let _keyHelper = new Date(revenueTs) 48 | let _keyYearAsString = _keyHelper.getFullYear().toString() 49 | let _keyMonthAsString = _keyHelper.getMonth().toString() 50 | 51 | let yearMonthIndexKey = await ctx.stub.createCompositeKey(indexName, [_keyYearAsString, _keyMonthAsString, this.TxId]); 52 | 53 | //console.info(yearMonthIndexKey, _keyYearAsString, _keyMonthAsString, this.TxId); 54 | 55 | // store the new state 56 | await ctx.stub.putState(yearMonthIndexKey, Buffer.from(JSON.stringify(model))); 57 | 58 | // compose the return values 59 | return { 60 | key: _keyYearAsString+'~'+_keyMonthAsString+'~'+this.TxId 61 | }; 62 | 63 | } catch(e){ 64 | throw new Error(`The tx ${this.TxId} can not be stored: ${e}`); 65 | } 66 | } 67 | 68 | async getCsByYearMonth(ctx){ 69 | 70 | // we use the args option 71 | const args = ctx.stub.getArgs(); 72 | 73 | // we split the key into single peaces 74 | const keyValues = args[1].split('~') 75 | 76 | // collect the keys 77 | let keys = [] 78 | keyValues.forEach(element => keys.push(element)) 79 | 80 | // do the query 81 | let resultsIterator = await ctx.stub.getStateByPartialCompositeKey('year~month~txid', keys); 82 | 83 | // prepare the result 84 | const allResults = []; 85 | while (true) { 86 | const res = await resultsIterator.next(); 87 | 88 | if (res.value) { 89 | // if not a getHistoryForKey iterator then key is contained in res.value.key 90 | allResults.push(res.value.value.toString('utf8')); 91 | //console.log('V:',res.value.value.toString('utf8')) 92 | //console.log('K:',res.value.key.toString('utf8')) 93 | } 94 | 95 | // check to see if we have reached then end 96 | if (res.done) { 97 | //console.log(res.done) 98 | // explicitly close the iterator 99 | await resultsIterator.close(); 100 | return allResults; 101 | } 102 | } 103 | } 104 | 105 | /** 106 | * CouchDb Query test 107 | * 108 | * @param {*} ctx 109 | * @returns 110 | */ 111 | async getCsByTimeRange(ctx){ 112 | // we use the args option 113 | const args = ctx.stub.getArgs(); 114 | 115 | // break condition 116 | if(args.length !== 3){ 117 | return JSON.stringify({error:true}); 118 | } 119 | 120 | // we collect our result 121 | let allResults = []; 122 | 123 | // compose the selector 124 | let queryString = {}; 125 | queryString.selector = {}; 126 | queryString.selector.revenueTs = { 127 | $gt: args[1], 128 | $lt: args[2] 129 | } 130 | queryString.sort = [{"revenueTs": "asc"}] 131 | 132 | //console.log(queryString) 133 | // -------------------- 134 | 135 | // do the query 136 | let resultsIterator = await ctx.stub.getQueryResult(JSON.stringify(queryString)); 137 | 138 | // loop over the results and create the allResults array 139 | let result = await resultsIterator.next(); 140 | while (!result.done) { 141 | const strValue = Buffer.from(result.value.value.toString()).toString('utf8'); 142 | let record; 143 | try { 144 | record = JSON.parse(strValue); 145 | } catch (err) { 146 | console.log(err); 147 | record = strValue; 148 | } 149 | allResults.push({ Key: result.value.key, Record: record }); 150 | result = await resultsIterator.next(); 151 | } 152 | 153 | // return the finale result 154 | return JSON.stringify(allResults); 155 | } 156 | 157 | async afterTransaction(ctx, result) { 158 | // default implementation is do nothing 159 | console.log(`TX ${this.TxId} done !!`) 160 | } 161 | 162 | } 163 | 164 | module.exports = Cs01Contract 165 | -------------------------------------------------------------------------------- /meetup-120321/index.md: -------------------------------------------------------------------------------- 1 | # How to use CouchDb for your Chaincode 2 | 3 | You can find the slides and the recording from this session on my [blog](https://samlinux.at/en/blog/fabric2-10/). 4 | 5 | This example is based on the session example from 26.02.2021 and extends this example with a couchDb query. 6 | 7 | - modify the chaincode 8 | - set index for couchDb 9 | - start the Docker devmode composition 10 | 11 | ## Housekeepting 12 | To clean up the system we have to delete the content of the data folder (leader data) and the content of the artifacts folder. 13 | 14 | ```bash 15 | rm -R $(pwd)/ledgerData/* 16 | rm $(pwd)/artifacts/* 17 | 18 | docker rm $(docker ps -a -f status=exited -q) 19 | docker volume prune 20 | ``` 21 | 22 | ## Chaincode DevMode - Node.js 23 | 24 | ## Some notes to usage 25 | See the files: 26 | - [index.js](./index.js) 27 | - [lib/cs01.js](./lib/cs01.js) 28 | - [META-INF/statedb/cuchdb/indexRevenue.json](META-INF/statedb/cuchdb/indexRevenue.json) 29 | 30 | 31 | ## Terminal 1 - Start the network 32 | Terminal one is responsible for running the network without the chaincode container. 33 | 34 | ```bash 35 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 36 | 37 | # generate the genesis block for the ordering service 38 | configtxgen -profile SampleDevModeSolo -channelID syschannel -outputBlock genesisblock -configPath $FABRIC_CFG_PATH -outputBlock $(pwd)/artifacts/genesis.block 39 | 40 | # create channel creation transaction 41 | configtxgen -channelID ch1 -outputCreateChannelTx $(pwd)/artifacts/ch1.tx -profile SampleSingleMSPChannel -configPath $FABRIC_CFG_PATH 42 | 43 | # start the network 44 | docker-compose up 45 | ``` 46 | 47 | ## Terminal 2 - is the Chaincode terminal 48 | 49 | ## Create and join the channel 50 | 51 | ```bash 52 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 53 | # create a new channel 54 | peer channel create -o 127.0.0.1:7050 --outputBlock $(pwd)/artifacts/ch1.block -c ch1 -f $(pwd)/artifacts/ch1.tx 55 | 56 | # dev peer joins the channel 57 | peer channel join -b $(pwd)/artifacts/ch1.block 58 | 59 | ``` 60 | 61 | ## Install the chaincode 62 | ```bash 63 | # package the node.js chaincode 64 | peer lifecycle chaincode package cs01-2.tar.gz --path chaincode/nodejs/cs01-2 --lang node --label mycc 65 | 66 | # install the node.js chaincode 67 | peer lifecycle chaincode install cs01-2.tar.gz --peerAddresses localhost:7051 68 | 69 | # check if chaincode is installed 70 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 71 | 72 | # remember the package Id 73 | export PK_ID=mycc:80636242f7e0e9763d903c7bb078afbfc0d44061dd9288a0532be70d3a4e9133 74 | ``` 75 | 76 | ## Start/Stop the chaincode 77 | cd chaincode/nodejs/cs01-2 78 | ```bash 79 | #### Start the node.js Chaincode #### 80 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_ADDRESS=127.0.0.1:7052 CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=$PK_ID ./node_modules/.bin/fabric-chaincode-node start --peer.address 127.0.0.1:7052 81 | 82 | ``` 83 | 84 | ## Terminal 3 - Approve and using the chaincode 85 | 86 | ```bash 87 | cd fabric/fabric-samples/dev-network/ 88 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 89 | 90 | # remember the package Id 91 | export PK_ID=mycc:80636242f7e0e9763d903c7bb078afbfc0d44061dd9288a0532be70d3a4e9133 92 | 93 | # approve the chaincode 94 | peer lifecycle chaincode approveformyorg -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --package-id $PK_ID 95 | 96 | peer lifecycle chaincode checkcommitreadiness -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" 97 | 98 | peer lifecycle chaincode commit -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --peerAddresses 127.0.0.1:7051 99 | ``` 100 | 101 | ## Testing the chaincode 102 | Test the chaincode with your CLI commands. 103 | 104 | ```bash 105 | # call the --isInit option only for the first time 106 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["storeCs","100","2021-02-21T17:15:57.928Z","reco"]}' --isInit 107 | 108 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["storeCs","540.34","2021-03-01T17:15:57.928Z","reve"]}' 109 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["storeCs","760","2021-03-22T17:15:57.928Z","reve"]}' 110 | 111 | # query the chaincode 112 | ## query by year 113 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["getCsByYearMonth","2021"]}' | jq . 114 | 115 | ## query by month 116 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["getCsByYearMonth","2021~2"]}' | jq . 117 | 118 | ## query by full key 119 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["getCsByYearMonth","2021~3~1ac634c81f3b17dce80585b3cba9ae088493f2bae999e54fbc9f9bcd54173ca6"]}' | jq . 120 | 121 | ## query by time range (date to date) 122 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["getCsByTimeRange","2021-02-01T01:15:57.928Z", "2021-02-28T17:15:57.928Z"]}' | jq . 123 | 124 | ``` 125 | [Index](../README.md) 126 | 127 | 128 | -------------------------------------------------------------------------------- /meetup-120221/index.md: -------------------------------------------------------------------------------- 1 | # How you can use Node.js as an application developer 2 | 3 | ## How to use Node.js as a chaincode 4 | In this example we are going to use the predefined asset-basic-transfer chaincode. 5 | 6 | ```bash 7 | # switch to the base folder 8 | cd fabric-samples/test-network 9 | 10 | # bring up the network 11 | ./network.sh up createChannel -c channel1 -ca 12 | 13 | # install default CC - asset-transfer (basic) chaincode 14 | cd ../asset-transfer-basic/chaincode-javascript 15 | npm install 16 | cd ../../test-network 17 | 18 | export FABRIC_CFG_PATH=$PWD/../config/ 19 | 20 | peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-javascript/ --lang node --label basic_1.0 21 | 22 | # install one peer0 Org1 23 | . ./scripts/envVar.sh 24 | 25 | setGlobals 1 26 | peer lifecycle chaincode install basic.tar.gz 27 | 28 | # install one peer0 Org2 29 | setGlobals 2 30 | peer lifecycle chaincode install basic.tar.gz 31 | 32 | # check installed chaincode and get PKID 33 | setGlobals 1 34 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 35 | 36 | export PKGID=basic_1.0:d2e3329812d27a187ea1f84b1a2c45cb7bf5e677a139044a3af3188e308f2c89 37 | 38 | # approve for Org1 39 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID channel1 --name basic --version 1 --package-id $PKGID --sequence 1 40 | 41 | # approve for Org2 42 | setGlobals 2 43 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID channel1 --name basic --version 1 --package-id $PKGID --sequence 1 44 | 45 | # commit the CC 46 | peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID channel1 --name basic --peerAddresses localhost:7051 --tlsRootCertFiles $PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1 --sequence 1 47 | 48 | # check committed chaincode 49 | peer lifecycle chaincode querycommitted --channelID channel1 --name basic --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 50 | 51 | 52 | # show if some containers are running 53 | docker ps 54 | docker-compose -f docker/docker-compose-test-net.yaml ps 55 | 56 | ``` 57 | 58 | 59 | ## Use the basic (asset-transfer-basic) CC 60 | ```bash 61 | # call the invoke 62 | 63 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C channel1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}' 64 | 65 | # Read the last state of all assets 66 | peer chaincode query -C channel1 -n basic -c '{"Args":["GetAllAssets"]}' | jq . 67 | 68 | # Read an asset 69 | peer chaincode query -C channel1 -n basic -c '{"Args":["ReadAsset","asset1"]}' | jq . 70 | 71 | # Update an asset 72 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C channel1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"UpdateAsset","Args":["asset1","green","10","Roland","600"]}' 73 | ``` 74 | 75 | ## How to use Node.js to access the leder 76 | Create a new project folder. 77 | 78 | ```bash 79 | # create a folder 80 | mkdir myapp && cd myapp 81 | 82 | # init a project 83 | npm init 84 | 85 | # install fabric dependencies 86 | npm install fabric-ca-client fabric-network 87 | ``` 88 | 89 | We use the following three files: 90 | - helper.js 91 | - caActions.js 92 | - ledgerActions.js 93 | 94 | Firstly we have to enroll an admin user. 95 | ```bash 96 | node caActions.js admin 97 | ``` 98 | 99 | Secondly, we have to register and enroll an application user. 100 | ```bash 101 | node caActions.js user roland 102 | ``` 103 | 104 | Now you should have two new identities under the folder wallet/ 105 | 106 | Start interacting with the ledger. 107 | ```bash 108 | # GetAllAssets 109 | node ledgerActions.js GetAllAssets 110 | 111 | # Get a particular asset 112 | node.ledgerActions.js ReadAsset asset1 113 | 114 | # Create and update an asset 115 | node ledgerActions.js CreateAsset 116 | 117 | ``` 118 | [Index](../README.md) 119 | -------------------------------------------------------------------------------- /meetup-120221/caActions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Certificate Authority - Actions 3 | */ 4 | 5 | // node.js includes 6 | const path = require('path') 7 | 8 | // own helper functions 9 | const helper = require('./helper') 10 | 11 | // fabric includes 12 | const FabricCAServices = require('fabric-ca-client'); 13 | const { Wallets } = require('fabric-network'); 14 | 15 | // CA admin credentions based on test-network 16 | const adminUserId = 'admin'; 17 | const adminUserPasswd = 'adminpw'; 18 | 19 | // wallet path 20 | const walletPath = path.join(__dirname, 'wallet'); 21 | 22 | /** 23 | * Create a new CA client for interacting with the CA 24 | * @param {*} FabricCAServices 25 | * @param {*} ccp 26 | * @param {*} caHostName 27 | */ 28 | function buildCAClient (FabricCAServices, ccp, caHostName) { 29 | //lookup CA details from config 30 | const caInfo = ccp.certificateAuthorities[caHostName]; 31 | const caTLSCACerts = caInfo.tlsCACerts.pem; 32 | const caClient = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName); 33 | 34 | console.log(`Built a CA Client named ${caInfo.caName}`); 35 | return caClient; 36 | }; 37 | 38 | /** 39 | * Enroll an Admin user 40 | * @param {*} caClient 41 | * @param {*} wallet 42 | * @param {*} orgMspId 43 | */ 44 | async function enrollAdmin (caClient, wallet, orgMspId){ 45 | try { 46 | // Check to see if we've already enrolled the admin user. 47 | const identity = await wallet.get(adminUserId); 48 | if (identity) { 49 | console.log('An identity for the admin user already exists in the wallet'); 50 | return; 51 | } 52 | 53 | // Enroll the admin user, and import the new identity into the wallet. 54 | const enrollment = await caClient.enroll({ enrollmentID: adminUserId, enrollmentSecret: adminUserPasswd }); 55 | const x509Identity = { 56 | credentials: { 57 | certificate: enrollment.certificate, 58 | privateKey: enrollment.key.toBytes(), 59 | }, 60 | mspId: orgMspId, 61 | type: 'X.509', 62 | }; 63 | await wallet.put(adminUserId, x509Identity); 64 | console.log('Successfully enrolled admin user and imported it into the wallet'); 65 | } catch (error) { 66 | console.error(`Failed to enroll admin user : ${error}`); 67 | } 68 | }; 69 | 70 | /** 71 | * Register and enroll an application user 72 | * @param {*} caClient 73 | * @param {*} wallet 74 | * @param {*} orgMspId 75 | * @param {*} userId 76 | * @param {*} affiliation 77 | */ 78 | async function registerAndEnrollUser (caClient, wallet, orgMspId, userId, affiliation){ 79 | try { 80 | // Check to see if we've already enrolled the user 81 | const userIdentity = await wallet.get(userId); 82 | if (userIdentity) { 83 | console.log(`An identity for the user ${userId} already exists in the wallet`); 84 | return; 85 | } 86 | 87 | // Must use an admin to register a new user 88 | const adminIdentity = await wallet.get(adminUserId); 89 | if (!adminIdentity) { 90 | console.log('An identity for the admin user does not exist in the wallet'); 91 | console.log('Enroll the admin user before retrying'); 92 | return; 93 | } 94 | 95 | // build a user object for authenticating with the CA 96 | const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type); 97 | const adminUser = await provider.getUserContext(adminIdentity, adminUserId); 98 | 99 | // Register the user, enroll the user, and import the new identity into the wallet. 100 | // if affiliation is specified by client, the affiliation value must be configured in CA 101 | const secret = await caClient.register({ 102 | affiliation: affiliation, 103 | enrollmentID: userId, 104 | role: 'client' 105 | }, adminUser); 106 | const enrollment = await caClient.enroll({ 107 | enrollmentID: userId, 108 | enrollmentSecret: secret 109 | }); 110 | const x509Identity = { 111 | credentials: { 112 | certificate: enrollment.certificate, 113 | privateKey: enrollment.key.toBytes(), 114 | }, 115 | mspId: orgMspId, 116 | type: 'X.509', 117 | }; 118 | console.log(x509Identity) 119 | await wallet.put(userId, x509Identity); 120 | console.log(`Successfully registered and enrolled user ${userId} and imported it into the wallet`); 121 | } catch (error) { 122 | console.error(`Failed to register user : ${error}`); 123 | } 124 | }; 125 | 126 | /** 127 | * Enroll an admin user for Org1 128 | */ 129 | async function getAdmin(){ 130 | let ccp = buildCCPOrg1() 131 | 132 | // build an instance of the fabric ca services client based on 133 | // the information in the network configuration 134 | const caClient = buildCAClient(FabricCAServices, ccp, 'ca.org1.example.com'); 135 | 136 | // setup the wallet to hold the credentials of the application user 137 | const wallet = await buildWallet(Wallets, walletPath); 138 | 139 | // in a real application this would be done on an administrative flow, and only once 140 | await enrollAdmin(caClient, wallet, 'Org1MSP'); 141 | } 142 | 143 | /** 144 | * Register and enroll an application user for Org1 145 | * @param {*} org1UserId 146 | */ 147 | async function getUser(org1UserId){ 148 | let ccp = helper.buildCCPOrg1() 149 | 150 | // build an instance of the fabric ca services client based on 151 | // the information in the network configuration 152 | const caClient = buildCAClient(FabricCAServices, ccp, 'ca.org1.example.com'); 153 | 154 | // setup the wallet to hold the credentials of the application user 155 | const wallet = await helper.buildWallet(Wallets, walletPath); 156 | 157 | await registerAndEnrollUser(caClient, wallet, 'Org1MSP', org1UserId, 'org1.department1'); 158 | } 159 | 160 | 161 | let args = process.argv 162 | 163 | if(args[2] === 'admin'){ 164 | // node caActions.js admin 165 | getAdmin() 166 | } else if(args[2] === 'user'){ 167 | // node caActions.js user peter 168 | let org1UserId = args[3] 169 | getUser(org1UserId) 170 | } else { 171 | console.log('...') 172 | } 173 | 174 | 175 | -------------------------------------------------------------------------------- /meetup-180621/chaincode/cs04.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // SDK Library to asset with writing the logic 4 | const { Contract } = require('fabric-contract-api'); 5 | const ClientIdentity = require('fabric-shim').ClientIdentity; 6 | 7 | /** 8 | * Chaincode Interface = dependencies of fabric-shim = old version 9 | * Contract Interface = dependencies of fabric-contract-api and fabric-shim will be required too = new version 10 | */ 11 | class Cs04Contract extends Contract { 12 | constructor(){ 13 | super('Cs04Contract'); 14 | 15 | // DataModel 16 | this.Model = {}; 17 | this.TxId = ''; 18 | this.Cid = {}; 19 | } 20 | 21 | beforeTransaction(ctx) { 22 | // default implementation is do nothing 23 | this.TxId = ctx.stub.txId; 24 | console.log('---------------------------'); 25 | console.log('transaction start'); 26 | console.log(`TxId: ${this.TxId}`); 27 | 28 | // create a client identity instance 29 | this.Cid = new ClientIdentity(ctx.stub); 30 | 31 | // get the MSPID from the invoker 32 | console.log(this.Cid.getMSPID()); 33 | 34 | // a string in the format: "x509::{subject DN}::{issuer DN}" will be returned 35 | const Cert = this.splitId(this.Cid.getID()); 36 | console.log(Cert); 37 | 38 | // get the value of an given attribute 39 | console.log('samlinux.writer',this.Cid.getAttributeValue("samlinux.writer")); 40 | console.log('samlinux.reader',this.Cid.getAttributeValue("samlinux.reader")); 41 | console.log('samlinux.auditor',this.Cid.getAttributeValue("samlinux.auditor")); 42 | 43 | } 44 | 45 | afterTransaction(ctx, result) { 46 | console.log('transaction done, R: ',result); 47 | console.log('---------------------------'); 48 | } 49 | 50 | unknownTransaction(ctx) { 51 | //Sending error message back to peer 52 | let ret = ctx.stub.getFunctionAndParameters(); 53 | throw new Error(`CC method ${ret.fcn} not defined!`); 54 | } 55 | 56 | /** 57 | * Split X509 data 58 | * @param {*} X509 59 | * @returns 60 | */ 61 | splitId(X509){ 62 | let a = X509.split('::'), cert = {}; 63 | cert.typ = a[0]; 64 | cert.subject = this.splitInfo(a[1]); 65 | cert.issuer = this.splitInfo(a[2]); 66 | return cert; 67 | } 68 | 69 | /** 70 | * helper to split the data 71 | * @param {*} data 72 | * @returns 73 | */ 74 | splitInfo(data){ 75 | let dataA = data.split('/'); 76 | return dataA.reduce(function(result, item) { 77 | let i = item.split('=') 78 | if(i[0] !== ''){ 79 | result[i[0]] = i[1]; 80 | } 81 | 82 | return result; 83 | }, {}); 84 | } 85 | 86 | /** 87 | * create or update an asset 88 | * @param {*} ctx 89 | * @returns 90 | */ 91 | async set(ctx){ 92 | // chekc the proper permissions 93 | if(!this.Cid.assertAttributeValue('samlinux.writer', 'true')){ 94 | return { 95 | key: 'Error, you are not allowed to create or update an asset!' 96 | }; 97 | } 98 | 99 | // create the model and get the key 100 | this.createModel(ctx); 101 | 102 | try { 103 | // store the key 104 | const assetBuffer = Buffer.from(JSON.stringify(this.Model.data)); 105 | await ctx.stub.putState(this.Model.key, assetBuffer); 106 | 107 | // compose the return values 108 | return { 109 | key: this.Model.key 110 | }; 111 | 112 | } catch(e){ 113 | throw new Error(`The tx ${this.TxId} can not be stored: ${e}`); 114 | } 115 | } 116 | 117 | /** 118 | * get the latest state of a given key 119 | * 120 | * @param {*} ctx 121 | * @param {*} key 122 | */ 123 | async get(ctx, key){ 124 | const allowedAttributes = ['samlinux.reader', 'samlinux.writer', 'samlinux.auditor']; 125 | const status = this.hasAttribute(allowedAttributes); 126 | 127 | if(!status){ 128 | return { 129 | key: 'Error, you are not allowed to read an asset!' 130 | }; 131 | } 132 | 133 | // get the asset from chaincode state 134 | const assetAsBuffer = await ctx.stub.getState(key); 135 | 136 | // check if the asset key was found 137 | if (!assetAsBuffer || assetAsBuffer.length === 0) { 138 | throw new Error(`The asset ${key} does not exist`); 139 | } 140 | // convert the buffer to string 141 | return assetAsBuffer.toString('utf8'); 142 | } 143 | 144 | // AssetExists returns true when asset with given KEY exists in world state. 145 | async AssetExists(ctx, key) { 146 | const assetJSON = await ctx.stub.getState(key); 147 | return assetJSON && assetJSON.length > 0; 148 | } 149 | 150 | /** 151 | * check if one attributes is true 152 | * @param {*} allowedAttributes 153 | * @returns 154 | */ 155 | hasAttribute(allowedAttributes){ 156 | let status = false; 157 | for (let i = 0; i < allowedAttributes.length; i++){ 158 | if(this.Cid.getAttributeValue(allowedAttributes[i], 'true')){ 159 | status = true; 160 | break; 161 | } 162 | } 163 | return status; 164 | } 165 | 166 | /** 167 | * Create Model 168 | * product {no, desc, amount, price} 169 | * @param {*} data 170 | */ 171 | createModel(ctx){ 172 | // get passed parameters 173 | const ret = ctx.stub.getFunctionAndParameters(); 174 | 175 | // convert passed parameter to JSON 176 | const data = JSON.parse(ret.params[0]); 177 | 178 | // start composing a data and key model 179 | this.Model.data = {}; 180 | 181 | if(data.hasOwnProperty('no')){ 182 | this.Model.key = data.no; 183 | } 184 | 185 | if(data.hasOwnProperty('desc')){ 186 | this.Model.data.desc = data.desc; 187 | } 188 | 189 | if(data.hasOwnProperty('amount')){ 190 | this.Model.data.amount = parseInt(data.amount); 191 | } 192 | 193 | if(data.hasOwnProperty('price')){ 194 | this.Model.data.price = parseFloat(data.price); 195 | } 196 | 197 | if(data.hasOwnProperty('type')){ 198 | this.Model.data.type = data.type; 199 | } 200 | } 201 | 202 | }; 203 | 204 | module.exports = Cs04Contract -------------------------------------------------------------------------------- /meetup-backlog/index.md: -------------------------------------------------------------------------------- 1 | # DRAFT 2 | ## Fabric-Ca 3 | 4 | - create docker-compose file with CAs for every organization 5 | - start CAs 6 | - steps for each organization 7 | - create an CA admin only with enrollment, because admin is already registered 8 | - registration 9 | - peers 10 | - users (admin, user) 11 | - enrollment 12 | - peers 13 | - users 14 | - copy crypto material to the right place 15 | 16 | 17 | 18 | ## Start the network 19 | ```bash 20 | ./network.sh up createChannel -ca 21 | ./network.sh deployCC 22 | ``` 23 | 24 | 25 | ## Work with the Fabric-CA 26 | 27 | ```bash 28 | # set an environment variable 29 | export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ 30 | 31 | # list identities 32 | fabric-ca-client identity list --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem 33 | 34 | fabric-ca-client identity list --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem --id user1 35 | 36 | # register new user 37 | fabric-ca-client register --caname ca-org1 --id.name user5 --id.secret user2pw --id.type client --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem 38 | 39 | # Generate the user msp 40 | tree organizations/peerOrganizations/org1.example.com/users/ 41 | 42 | mkdir -p organizations/peerOrganizations/org1.example.com/users/User2@org1.example.com 43 | 44 | fabric-ca-client enroll -u https://user5:user2pw@localhost:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.example.com/users/User5@org1.example.com/msp --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem 45 | 46 | cp ${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.example.com/users/User2@org1.example.com/msp/config.yaml 47 | 48 | # check the result 49 | tree organizations/peerOrganizations/org1.example.com/users/ 50 | 51 | # inspect the cert 52 | openssl x509 -in msp/signcerts/cert.pem -text 53 | ``` 54 | 55 | ## Do a transaction with user2 56 | ```bash 57 | . ./scripts/envVars.sh 58 | setGlobals 1 59 | 60 | export FABRIC_CFG_PATH=$PWD/../config/ 61 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp 62 | export CHANNEL_NAME="mychannel" 63 | 64 | # Read the last state of all assets 65 | peer chaincode query -C $CHANNEL_NAME -n basic -c '{"Args":["GetAllAssets"]}' | jq . 66 | 67 | # Read an asset 68 | peer chaincode query -C $CHANNEL_NAME -n basic -c '{"Args":["ReadAsset","asset1"]}' | jq . 69 | 70 | # Update an asset 71 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"UpdateAsset","Args":["asset1","green","10","Roland4","600"]}' 72 | ``` 73 | 74 | 75 | ### Inspect the transaction 76 | ```bash 77 | peer channel fetch newest info.block -c mychannel -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 78 | 79 | configtxlator proto_decode --type=common.Block --input=info.block | jq . 80 | 81 | copy "signature_header.creator.id_bytes" to info 82 | 83 | base64 -d info 84 | 85 | base64 -d info | openssl x509 -text 86 | 87 | echo VXBkYXRlQXNzZXQ= | base64 -d; echo 88 | 89 | ``` 90 | 91 | 92 | ## Remove a user 93 | 94 | –cfg.identities.allowremove 95 | 96 | 97 | fabric-ca-client revoke -e User --gencrl --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem 98 | 99 | 100 | 101 | ## Channel config update 102 | 103 | ```bash 104 | 105 | # get the config of the channel 106 | peer channel fetch config config_block.pb -c mychannel -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 107 | 108 | # concert the config to json 109 | configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json 110 | 111 | # get the relevant part of the config 112 | jq .data.data[0].payload.data.config config_block.json > config.json 113 | 114 | # copy the config 115 | cp config.json modified_config.json 116 | 117 | ## Step 2: Modify the config 118 | 119 | ## Step 3: Re-encode and submit the config 120 | 121 | # convert config.json back to proto buffer 122 | configtxlator proto_encode --input config.json --type common.Config --output config.pb 123 | 124 | # convert modified_config.json back to proto buffer 125 | configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb 126 | 127 | # compute the difference between the two files, 128 | configtxlator compute_update --channel_id mychannel --original config.pb --updated modified_config.pb --output config_update.pb 129 | 130 | # apply the changes to the config 131 | 132 | configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json 133 | 134 | echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json 135 | 136 | configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb 137 | 138 | 139 | # Submit the config update transaction 140 | peer channel update -f config_update_in_envelope.pb -c mychannel -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 141 | 142 | ``` 143 | 144 | # Check the content of the CRL 145 | ```bash 146 | # extract the serial number for the RCL 147 | openssl x509 -in cert.pem -serial -noout | cut -d "=" -f 2 148 | 149 | # create CRL pem file 150 | fabric-ca-client gencrl -M ./msp --tls.certfiles ${PWD}/../organizations/fabric-ca/org1/tls-cert.pem 151 | 152 | # inspect CRL file 153 | openssl crl -text -in /root/fabric/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/msp/crls/crl.pem 154 | ``` 155 | 156 | AKI (Authority Key Identifier) 157 | 158 | aki=$(openssl x509 -in cert.pem -text | awk '/keyid/ {gsub(/ *keyid:|:/,"",$1);print tolower($0)}') 159 | -------------------------------------------------------------------------------- /meetup-260221/index.md: -------------------------------------------------------------------------------- 1 | # Comparison between Go and Node.js Chaincode 2 | This is an ongoing work to compare chaincode written in Node.js and Golang. 3 | 4 | ## Housekeepting 5 | To clean up the system we have to delete the content of the data folder (leader data) and the content of the artifacts folder. 6 | 7 | ```bash 8 | rm -R $(pwd)/ledgerData/* 9 | rm $(pwd)/artifacts/* 10 | 11 | docker rm $(docker ps -a -f status=exited -q) 12 | docker volume prune 13 | ``` 14 | 15 | ## Chaincode DevMode - Node.js 16 | 17 | ## Overview different APIs 18 | 19 | We have two APIs to communicate with he ledger. 20 | 21 | - fabric-contract-api **(contract interface)** 22 | - provides the contract interface. A high level API for application developers to implement Smart Contracts) 23 | - fabric-shim **(chaincode interface)** 24 | - provides the chaincode interface. A lower level API for implementing Smart Contracts. It also provides the implementation to support communication with Hyperledger Fabric peers for Smart Contracts written using the fabric-contract-api together with the fabric-chaincode-node cli to launch Chaincode or Smart Contracts. 25 | 26 | ## Some notes to usage 27 | See the files: 28 | - [index.js](./index.js) 29 | - [lib/cs01.js](./lib/cs01.js) 30 | - [cs01.sh](./cs01.sh) 31 | 32 | ```bash 33 | cd fabric/fabric-samples/dev-network/chaincode/nodejs 34 | mkdir cs01 && cd cs01 35 | 36 | npm init 37 | npm install --save fabric-contract-api fabric-shim 38 | 39 | # we need this also for the chaincode start command fabric-chaincode-node under ./node_modules/.bin/ 40 | 41 | touch index.html 42 | mkdir lib 43 | touch lib/cs01.js 44 | 45 | # modify the package.json file > scripts.start section 46 | "scripts": { 47 | "start": "fabric-chaincode-node start", 48 | } 49 | 50 | ``` 51 | 52 | ## Terminal 1 - Start the network 53 | Terminal one is responsible for running the network without the chaincode container. 54 | 55 | ```bash 56 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 57 | 58 | # generate the genesis block for the ordering service 59 | configtxgen -profile SampleDevModeSolo -channelID syschannel -outputBlock genesisblock -configPath $FABRIC_CFG_PATH -outputBlock $(pwd)/artifacts/genesis.block 60 | 61 | # create channel creation transaction 62 | configtxgen -channelID ch1 -outputCreateChannelTx $(pwd)/artifacts/ch1.tx -profile SampleSingleMSPChannel -configPath $FABRIC_CFG_PATH 63 | 64 | # start the network 65 | docker-compose up 66 | ``` 67 | 68 | ## Terminal 2 - is the Chaincode terminal 69 | 70 | ## Create and join the channel 71 | 72 | ```bash 73 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 74 | # create a new channel 75 | peer channel create -o 127.0.0.1:7050 --outputBlock $(pwd)/artifacts/ch1.block -c ch1 -f $(pwd)/artifacts/ch1.tx 76 | 77 | # dev peer joins the channel 78 | peer channel join -b $(pwd)/artifacts/ch1.block 79 | 80 | ``` 81 | 82 | ## Install the chaincode 83 | ```bash 84 | # package the node.js chaincode 85 | peer lifecycle chaincode package cs01.tar.gz --path chaincode/nodejs/cs01 --lang node --label mycc 86 | 87 | # install the node.js chaincode 88 | peer lifecycle chaincode install cs01.tar.gz --peerAddresses localhost:7051 89 | 90 | # check if chaincode is installed 91 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 92 | 93 | # remember the package Id 94 | export PK_ID=mycc:ecbc4ec15302eace477c8f2fe3645b4b7315427fcf89f7dd710d455aa130f268 95 | ``` 96 | 97 | ## Start/Stop the chaincode 98 | cd chaincode/nodejs/cs01 99 | ```bash 100 | #### Start the node.js Chaincode #### 101 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_ADDRESS=127.0.0.1:7052 CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=$PK_ID ./node_modules/.bin/fabric-chaincode-node start --peer.address 127.0.0.1:7052 102 | 103 | ``` 104 | 105 | ## Terminal 3 - Approve and using the chaincode 106 | 107 | ```bash 108 | cd fabric/fabric-samples/dev-network/ 109 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 110 | 111 | # remember the package Id 112 | export PK_ID=mycc:ecbc4ec15302eace477c8f2fe3645b4b7315427fcf89f7dd710d455aa130f268 113 | 114 | # approve the chaincode 115 | peer lifecycle chaincode approveformyorg -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --package-id $PK_ID 116 | 117 | peer lifecycle chaincode checkcommitreadiness -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" 118 | 119 | peer lifecycle chaincode commit -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --peerAddresses 127.0.0.1:7051 120 | ``` 121 | 122 | ## Testing the chaincode 123 | ```bash 124 | # call the --isInit option only for the first time 125 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["storeCs","100","2021-02-21T17:15:57.928Z","reco"]}' --isInit 126 | 127 | # query the chaincode 128 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["getCsByYearMonth","2021~1~c475e5e57cd2a2dd2a4a66eb1e94c5f1dd1aad7fe5f25d458051411b058f6795"]}' | jq . 129 | 130 | # use the chaincode 131 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["storeCs","540.34","2021-04-22T17:15:57.928Z","reve"]}' 132 | 133 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["getCsByYearMonth","2021~3~1ac634c81f3b17dce80585b3cba9ae088493f2bae999e54fbc9f9bcd54173ca6"]}' | jq . 134 | 135 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["getCsByYearMonth","2021~2"]}' | jq . 136 | 137 | ``` 138 | 139 | ## Use the test-network 140 | ## Install the Chaincode into the test-network 141 | ```bash 142 | cd $HOME/fabric/fabric-samples/test-network 143 | 144 | export FABRIC_CFG_PATH=../config 145 | 146 | # Start network and install the chaincode in one single line 147 | ./network.sh createChannel -c channel1 && ./network.sh deployCC -c channel1 -ccn cs01CC -ccl javascript -ccv 1 -ccs 1 -ccp ../dev-network/chaincode/nodejs/cs01 148 | 149 | # check your logs 150 | docker-compose -f docker/docker-compose-test-net.yaml logs -f 151 | 152 | # in terminal 2 - make clear who you are 153 | . ./scripts/envVar.sh 154 | setGlobals 1 155 | 156 | # use the script 157 | ./cs01.sh 158 | 159 | # invoke it by hand 160 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C channel1 -n cs01CC --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["storeCs","6555","2021-06-21T17:15:57.928Z","reco"]}' 161 | 162 | # do the queries 163 | peer chaincode query -o 127.0.0.1:7050 -C channel1 -n cs01CC -c '{"Args":["getCsByYearMonth","2021~1~fda3f767386ddb137ef6b09eb722339864c05b87a0f64a10a8ccceec9c28db50"]}' | jq . 164 | peer chaincode query -o 127.0.0.1:7050 -C channel1 -n cs01CC -c '{"Args":["getCsByYearMonth","2021~2"]}' | jq . 165 | peer chaincode query -o 127.0.0.1:7050 -C channel1 -n cs01CC -c '{"Args":["getCsByYearMonth","2020"]}' | jq . 166 | 167 | ``` 168 | [Index](../README.md) 169 | -------------------------------------------------------------------------------- /meetup-290121/fabric2DevModeDockerEdition.md: -------------------------------------------------------------------------------- 1 | # Fabric 2.2 Chaincode Devmode Environment - Docker Edition 2 | In this tutorial we are going to compose a docker based network for chaincode development. 3 | 4 | # Contents 5 | - [Preparation](#Preparation) 6 | - [Create artifacts](#Create-artifacts) 7 | - [Start the Network](#Start-the-network) 8 | - [Create and join Channel](#Create-and-join-Channel) 9 | - [Build and start the Chaincode](#Build-and-start-the-chaincode) 10 | - [Approve the Chaincode](#Approve-the-Chaincode) 11 | - [Test the Chaincode](#Test-the-Chaincode) 12 | - [Stop the Network](#Stop-the-Network) 13 | - [Continue your Chaincode work](#Continue-your-Chaincode-work) 14 | - [Hauskeeping](#Hauskeeping) 15 | 16 | # Preparation 17 | 18 | ```bash 19 | # I start in the fabric-samples folder 20 | cd fabric-samples 21 | 22 | mkdir dev-network && cd dev-network 23 | 24 | # make sure you have cloned the fabric git repro to some place you know 25 | # git clone https://github.com/hyperledger/fabric.git 26 | 27 | cp -R ../../../fabricDev/fabric/sampleconfig ./ 28 | cp ../test-network/.env ./ 29 | cp ../test-network/docker/docker-compose-test-net.yaml docker-compose.yaml 30 | 31 | # home for our chaincodes 32 | mkdir chaincode 33 | 34 | # persistent ledger data 35 | mkdir ledgerData 36 | 37 | # artifacts 38 | mkdir artifacts 39 | ``` 40 | ## Customize .env 41 | Adjust the COMPOSE_PROJECT_NAME to dev-network. 42 | 43 | ## Customize docker-compose.yaml 44 | We need only the orderer and peer services. 45 | 46 | ## Customize configtx.yaml 47 | We have to change the OrdererEndpoints from 127.0.0.1:7050 to orderer.example.com:7050. 48 | 49 | ```bash 50 | OrdererEndpoints: 51 | - "orderer.example.com:7050" 52 | ``` 53 | We are ready with the preparations. 54 | 55 | # Create artifacts 56 | 57 | ```bash 58 | # in terminal 1 59 | # set the FABRIC_CFG_PATH environment variable to point to the sampleconfig folder 60 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 61 | 62 | # generate the genesis block for the ordering service 63 | configtxgen -profile SampleDevModeSolo -channelID syschannel -outputBlock genesisblock -configPath $FABRIC_CFG_PATH -outputBlock $(pwd)/artifacts/genesis.block 64 | 65 | #create channel creattion transaction 66 | configtxgen -channelID ch1 -outputCreateChannelTx $(pwd)/artifacts/ch1.tx -profile SampleSingleMSPChannel -configPath $FABRIC_CFG_PATH 67 | ``` 68 | 69 | # Start the Network 70 | ```bash 71 | # in terminal 1 72 | docker-compose up 73 | ``` 74 | 75 | # Create and join Channel 76 | 77 | ```bash 78 | # in terminal 2 79 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 80 | 81 | # create the channel ch1 82 | peer channel create -o 127.0.0.1:7050 --outputBlock $(pwd)/artifacts/ch1.block -c ch1 -f $(pwd)/artifacts/ch1.tx 83 | 84 | # we can fetch the newest block as well 85 | # peer channel fetch newest $(pwd)/artifacts/ch1.block -c ch1 -o 127.0.0.1:7050 86 | 87 | # join the peer to the channel ch1 88 | peer channel join -b $(pwd)/artifacts/ch1.block 89 | ``` 90 | 91 | # Build and start the Chaincode 92 | At this time we should have our chaincode onto the folder chaincode e.g. chaincode/saac 93 | 94 | **This step is also the step which you have to repeat every time if your chaincode is changing.** 95 | 96 | ```bash 97 | cd chaincode 98 | 99 | ## Build the chaincode 100 | # We use the simple chaincode from the fabric/integration/chaincode directory to demonstrate how to run a chaincode package in DevMode. 101 | # GO111MODULE=on go mod vendor 102 | go build -o saac ./ 103 | 104 | # Start the chaincode 105 | # in terminal 2 106 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./saac -peer.address 127.0.0.1:7052 107 | #CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./atbcc -peer.address 127.0.0.1:7052 108 | ``` 109 | 110 | # Approve the Chaincode 111 | This step has to be done only once. 112 | 113 | ```bash 114 | # in terminal 3 115 | export FABRIC_CFG_PATH=$(pwd)/sampleconfig 116 | 117 | peer lifecycle chaincode approveformyorg -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --package-id mycc:1.0 118 | 119 | peer lifecycle chaincode checkcommitreadiness -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" 120 | 121 | peer lifecycle chaincode commit -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --peerAddresses 127.0.0.1:7051 122 | ``` 123 | 124 | # Test the Chaincode 125 | ## Version one sacc (simple asset chaincode) 126 | By the way this chaincode is based on old shim api implementation. 127 | 128 | ```bash 129 | # in terminal 2 130 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["k1","roland"]}' --isInit 131 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["","k1"]}' 132 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["set","k1","Roland2"]}' 133 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["set","k2","Snorre"]}' 134 | ``` 135 | 136 | ## Version two atbcc (asset-transfer-basic chaincode) 137 | By the way this chaincode is based on the chaincode-api. 138 | 139 | ```bash 140 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["InitLedger"]}' --isInit 141 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["ReadAsset","asset1"]}' | jq . 142 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["GetAllAssets"]}' | jq . 143 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["TransferAsset","asset1","Roland"]}' 144 | ``` 145 | 146 | # Stop the Network 147 | Notice you network is persistent. We can stop and start the network at any time we want. 148 | 149 | ```bash 150 | # in terminal 3 151 | docker-compose down 152 | ``` 153 | 154 | # Continue your Chaincode work 155 | ```bash 156 | # ---------------------------------------------- 157 | # in terminal 1 - start the network 158 | # ---------------------------------------------- 159 | docker-compose up 160 | 161 | ## OR in the background with logs 162 | docker-compose up -d && docker-compose logs -f -t 163 | 164 | # ---------------------------------------------- 165 | # in terminal 2 - bind and start the chaincode 166 | # ---------------------------------------------- 167 | # make sure you are in your chaincode folder 168 | # $(PWD) => chaincode/saac 169 | 170 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./sacc -peer.address 127.0.0.1:7052 171 | 172 | # ---------------------------------------------- 173 | # in terminal 3 - test your chaincode 174 | # ---------------------------------------------- 175 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["","k1"]}' 176 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["","k2"]}' 177 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["set","k1","Roland - xxx"]}' 178 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["set","k2","Snorre - now"]}' 179 | ``` 180 | 181 | # Hauskeeping 182 | 183 | ```bash 184 | rm -R ledgerData/* && rm -R artifacts/* 185 | ``` 186 | 187 | -------------------------------------------------------------------------------- /meetup-260321/index.md: -------------------------------------------------------------------------------- 1 | # Meetup Support Material 2 | 3 | This lesson continues the priviouse session from 29.01.2021. Watch this session [Fabric 2.2 Chaincode Devmode Environment - Binary Edition](../meetup-290121/fabric2DevMode.md) to be prepared. 4 | 5 | In this session I want to answer the following question: "How can we use the Node.js SDK to interact with the development environment and test chaincode?" 6 | 7 | This is session can be divided into two parts. 8 | 9 | 1. Preparation of the chaincode development environment (our starting point) 10 | 2. Usage of the Node.js SDK to get access to the development environment 11 | 12 | ## Preparation 13 | See the section "Set up the development environment" in the preparation session [Fabric 2.2 Chaincode Devmode Environment - Binary Edition](../meetup-290121/fabric2DevMode.md.md) to setup you system. 14 | 15 | Follow the following steps from the preparation guide: 16 | - Set up the development environment then follow the instructions below 17 | - Hauskeeping 18 | 19 | # Housekeepting 20 | To clean up the system we have to delete the content of the data folder (leader data) and the content of the artifacts folder. 21 | 22 | ```bash 23 | rm -R $(pwd)/data/* 24 | rm $(pwd)/artifacts/* 25 | ``` 26 | 27 | ### Start the network (start orderer and peer) 28 | ```bash 29 | 30 | tmux new -s fabric 31 | export PATH=$(pwd)/fabric/build/bin:$PATH 32 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 33 | 34 | # generate the genesis block for the ordering service 35 | configtxgen -profile SampleDevModeSolo -channelID syschannel -outputBlock genesisblock -configPath $FABRIC_CFG_PATH -outputBlock $(pwd)/artifacts/genesis.block 36 | 37 | # run the commands in the background and redirect the outputs 38 | # >/dev/null 2>&1 means redirect stdout to /dev/null and stderr to stdout 39 | 40 | # start the orderer 41 | ORDERER_GENERAL_GENESISFILE=$(pwd)/artifacts/genesis.block ORDERER_FILELEDGER_LOCATION=$(pwd)/data/orderer ORDERER_GENERAL_GENESISPROFILE=SampleDevModeSolo orderer > /dev/null 2>&1 & 42 | 43 | # start the peer 44 | CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:10443 CORE_PEER_FILESYSTEMPATH=$(pwd)/data/ FABRIC_LOGGING_SPEC=chaincode=debug CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 peer node start --peer-chaincodedev=true > /dev/null 2>&1 & 45 | 46 | # display all running jobs 47 | jobs -r 48 | ``` 49 | 50 | ### Create and join the channel 51 | ```bash 52 | 53 | configtxgen -channelID ch1 -outputCreateChannelTx $(pwd)/artifacts/ch1.tx -profile SampleSingleMSPChannel -configPath $FABRIC_CFG_PATH 54 | 55 | peer channel create -o 127.0.0.1:7050 --outputBlock $(pwd)/artifacts/ch1.block -c ch1 -f $(pwd)/artifacts/ch1.tx 56 | 57 | # Join the channel 58 | peer channel join -b $(pwd)/artifacts/ch1.block 59 | ``` 60 | 61 | ### Install the chaincode 62 | We use the predefined asset-transfer-basic node.js Chaincode in this example. 63 | 64 | ```bash 65 | # set some environment vars 66 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 67 | export PATH=$(pwd)/fabric/build/bin:$PATH 68 | 69 | # package the node.js chaincode 70 | peer lifecycle chaincode package atb.tar.gz --path chaincode/nodejs/atb --lang node --label mycc 71 | 72 | # install the node.js chaincode 73 | peer lifecycle chaincode install atb.tar.gz --peerAddresses localhost:7051 74 | 75 | # check if chaincode is installed 76 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 77 | 78 | # remember the package Id 79 | export PK_ID=mycc:f37c774772cb0154349812e1acd303992ad9cbf4eabbc29079797e4e052fac1d 80 | ``` 81 | ### Start/Stop the chaincode 82 | 83 | ```bash 84 | cd chaincode/nodejs/atb 85 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_ADDRESS=127.0.0.1:7052 CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=$PK_ID ./node_modules/.bin/fabric-chaincode-node start --peer.address 127.0.0.1:7052 86 | ``` 87 | 88 | ### Approve the chaincode 89 | 90 | ```bash 91 | # open a new tmux panel 92 | CTRL b + \" 93 | 94 | cd fabricDev/ 95 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 96 | export PATH=$(pwd)/fabric/build/bin:$PATH 97 | 98 | # remember the package Id 99 | export PK_ID=mycc:f37c774772cb0154349812e1acd303992ad9cbf4eabbc29079797e4e052fac1d 100 | 101 | # approve the chaincode 102 | peer lifecycle chaincode approveformyorg -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --package-id $PK_ID 103 | 104 | peer lifecycle chaincode commit -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --peerAddresses 127.0.0.1:7051 105 | 106 | ``` 107 | 108 | ### Testing the chaincode 109 | Test the chaincode with your CLI commands. 110 | 111 | ```bash 112 | # call the --isInit option only for the first time 113 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["InitLedger"]}' --isInit 114 | 115 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["ReadAsset","A5"]}' | jq . 116 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["CreateAsset","A1", "red", "10", "rbole", "100"]}' 117 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["ReadAsset","A1"]}' | jq . 118 | peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["UpdateAsset","A1", "red", "10", "rbole", "1200.23"]}' 119 | 120 | peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["GetAllAssets"]}' | jq . 121 | 122 | ``` 123 | 124 | ### Watch your system 125 | 126 | ```bash 127 | # try htop and filter to node peer OR orderer 128 | htop 129 | 130 | # try jobs -r 131 | jobs -r 132 | 133 | ``` 134 | 135 | ## Use the Node.js SDK to get access 136 | In this section we are going to compose a CLI application the interact with the network. The following steps are to be done: 137 | 138 | - Create the connection profile as json file. See ccp.json 139 | - Convert an existing identity and put it into the local wallet. See addtowallet.js 140 | - Create an CLI program to interact with the network. See index.js 141 | 142 | To create an identity we need the MSP folder from the fabric sampleconfig folder. You can find this sampleconfig files under the cloned fabric folder. We need this sampleconfig folder also for creating the genesis block and the channel transaction. 143 | 144 | Command to inspect the .pem file. 145 | ```bash 146 | openssl x509 -in ../fabric/sampleconfig/msp/admincerts/admincert.pem -text 147 | ``` 148 | 149 | ```bash 150 | # we create a client folder 151 | mkdir client && cd client 152 | 153 | # place to store the identitities 154 | mkdir wallet 155 | 156 | # init a npm project 157 | npm init 158 | 159 | # install the fabric dependicies 160 | npm install fabric-network --save 161 | 162 | # create addtowallet.js file 163 | 164 | # usage of addtowallet.js 165 | node addtowallet.js 166 | 167 | # create index.js 168 | 169 | # usage index.js 170 | node index.js GetAllAssets 171 | ``` 172 | 173 | ### Steps to do part two 174 | 175 | ```bash 176 | mkdir client 177 | npm init 178 | 179 | # copy or create ccp.json 180 | npm install --save fabric-network 181 | mkdir wallet 182 | 183 | # copy or create addtowallet.js 184 | node addtowallet.js 185 | cat wallet/admin.id | jq . 186 | 187 | # copy or create helper.js 188 | 189 | # copy or create index.js 190 | node index.js GetAllAssets | jq . 191 | node index.js ReadAsset asset6 | jq . 192 | node index.js CreateAsset 193 | node index.js ReadAsset A5 | jq . 194 | ``` 195 | 196 | ### Logging 197 | 198 | There are four levels of logging available within the SDK: 199 | 200 | - info 201 | - warn 202 | - error 203 | - debug 204 | 205 | ```bash 206 | # set logging level to the console 207 | export HFC_LOGGING='{"debug":"console"}' 208 | 209 | # set logging to a file 210 | export HFC_LOGGING='{"error":"./error.log"}' 211 | 212 | # unset logging level 213 | export HFC_LOGGING='' 214 | ``` 215 | 216 | [Index](../README.md) 217 | -------------------------------------------------------------------------------- /meetup-181220/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # Copyright IBM Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | 6 | version: '2' 7 | 8 | volumes: 9 | orderer.example.com: 10 | peer0.org1.example.com: 11 | peer0.org2.example.com: 12 | peer0.org3.example.com: 13 | 14 | networks: 15 | own-network: 16 | 17 | services: 18 | 19 | orderer.example.com: 20 | container_name: orderer.example.com 21 | image: hyperledger/fabric-orderer:$IMAGE_TAG 22 | environment: 23 | - FABRIC_LOGGING_SPEC=INFO 24 | - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 25 | - ORDERER_GENERAL_LISTENPORT=7050 26 | - ORDERER_GENERAL_GENESISMETHOD=file 27 | - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block 28 | - ORDERER_GENERAL_LOCALMSPID=OrdererMSP 29 | - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp 30 | # enabled TLS 31 | - ORDERER_GENERAL_TLS_ENABLED=true 32 | - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key 33 | - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt 34 | - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] 35 | - ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1 36 | - ORDERER_KAFKA_VERBOSE=true 37 | - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt 38 | - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key 39 | - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] 40 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric 41 | command: orderer 42 | volumes: 43 | - ./system-genesis-block/genesis.block:/var/hyperledger/orderer/orderer.genesis.block 44 | - ./organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp 45 | - ./organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls 46 | - orderer.example.com:/var/hyperledger/production/orderer 47 | ports: 48 | - 7050:7050 49 | networks: 50 | - own-network 51 | 52 | peer0.org1.example.com: 53 | container_name: peer0.org1.example.com 54 | image: hyperledger/fabric-peer:$IMAGE_TAG 55 | environment: 56 | #Generic peer variables 57 | - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 58 | # the following setting starts chaincode containers on the same 59 | # bridge network as the peers 60 | # https://docs.docker.com/compose/networking/ 61 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_own-network 62 | - FABRIC_LOGGING_SPEC=INFO 63 | #- FABRIC_LOGGING_SPEC=DEBUG 64 | - CORE_PEER_ADDRESSAUTODETECT=true 65 | - CORE_PEER_TLS_ENABLED=true 66 | - CORE_PEER_PROFILE_ENABLED=true 67 | - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt 68 | - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key 69 | - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt 70 | # Peer specific variabes 71 | - CORE_PEER_ID=peer0.org1.example.com 72 | - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 73 | - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 74 | - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052 75 | - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 76 | - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051 77 | - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 78 | - CORE_PEER_LOCALMSPID=Org1MSP 79 | volumes: 80 | - /var/run/:/host/var/run/ 81 | - ./organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp 82 | - ./organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls 83 | - peer0.org1.example.com:/var/hyperledger/production 84 | command: peer node start 85 | ports: 86 | - 7051:7051 87 | networks: 88 | - own-network 89 | 90 | peer0.org2.example.com: 91 | container_name: peer0.org2.example.com 92 | image: hyperledger/fabric-peer:$IMAGE_TAG 93 | environment: 94 | #Generic peer variables 95 | - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 96 | # the following setting starts chaincode containers on the same 97 | # bridge network as the peers 98 | # https://docs.docker.com/compose/networking/ 99 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_own-network 100 | - FABRIC_LOGGING_SPEC=INFO 101 | - CORE_PEER_ADDRESSAUTODETECT=true 102 | #- FABRIC_LOGGING_SPEC=DEBUG 103 | - CORE_PEER_TLS_ENABLED=true 104 | - CORE_PEER_PROFILE_ENABLED=true 105 | - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt 106 | - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key 107 | - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt 108 | # Peer specific variabes 109 | - CORE_PEER_ID=peer0.org2.example.com 110 | - CORE_PEER_ADDRESS=peer0.org2.example.com:9051 111 | - CORE_PEER_LISTENADDRESS=0.0.0.0:9051 112 | - CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:9052 113 | - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052 114 | - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051 115 | - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:9051 116 | - CORE_PEER_LOCALMSPID=Org2MSP 117 | volumes: 118 | - /var/run/:/host/var/run/ 119 | - ./organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp 120 | - ./organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls 121 | - peer0.org2.example.com:/var/hyperledger/production 122 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer 123 | command: peer node start 124 | ports: 125 | - 9051:9051 126 | networks: 127 | - own-network 128 | 129 | peer0.org3.example.com: 130 | container_name: peer0.org3.example.com 131 | image: hyperledger/fabric-peer:$IMAGE_TAG 132 | environment: 133 | #Generic peer variables 134 | - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 135 | # the following setting starts chaincode containers on the same 136 | # bridge network as the peers 137 | # https://docs.docker.com/compose/networking/ 138 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_own-network 139 | - FABRIC_LOGGING_SPEC=INFO 140 | - CORE_PEER_ADDRESSAUTODETECT=true 141 | #- FABRIC_LOGGING_SPEC=DEBUG 142 | - CORE_PEER_TLS_ENABLED=true 143 | - CORE_PEER_PROFILE_ENABLED=true 144 | - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt 145 | - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key 146 | - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt 147 | # Peer specific variabes 148 | - CORE_PEER_ID=peer0.org3.example.com 149 | - CORE_PEER_ADDRESS=peer0.org3.example.com:10051 150 | - CORE_PEER_LISTENADDRESS=0.0.0.0:10051 151 | - CORE_PEER_CHAINCODEADDRESS=peer0.org3.example.com:10052 152 | - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:10052 153 | - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org3.example.com:10051 154 | - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org3.example.com:10051 155 | - CORE_PEER_LOCALMSPID=Org3MSP 156 | volumes: 157 | - /var/run/:/host/var/run/ 158 | - ./organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/msp:/etc/hyperledger/fabric/msp 159 | - ./organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls:/etc/hyperledger/fabric/tls 160 | - peer0.org3.example.com:/var/hyperledger/production 161 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer 162 | command: peer node start 163 | ports: 164 | - 10051:10051 165 | networks: 166 | - own-network 167 | -------------------------------------------------------------------------------- /meetup-061120/assetTransfer.go: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */ 4 | 5 | package main 6 | 7 | import ( 8 | "encoding/json" 9 | "fmt" 10 | "log" 11 | "os" 12 | "io/ioutil" 13 | "github.com/hyperledger/fabric-chaincode-go/shim" 14 | "github.com/hyperledger/fabric-contract-api-go/contractapi" 15 | ) 16 | 17 | type serverConfig struct { 18 | CCID string 19 | Address string 20 | } 21 | 22 | // SmartContract provides functions for managing an asset 23 | type SmartContract struct { 24 | contractapi.Contract 25 | } 26 | 27 | // Asset describes basic details of what makes up a simple asset 28 | type Asset struct { 29 | ID string `json:"ID"` 30 | Color string `json:"color"` 31 | Size int `json:"size"` 32 | Owner string `json:"owner"` 33 | AppraisedValue int `json:"appraisedValue"` 34 | } 35 | 36 | // QueryResult structure used for handling result of query 37 | type QueryResult struct { 38 | Key string `json:"Key"` 39 | Record *Asset 40 | } 41 | 42 | // InitLedger adds a base set of cars to the ledger 43 | func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error { 44 | assets := []Asset{ 45 | {ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300}, 46 | {ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400}, 47 | {ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500}, 48 | {ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600}, 49 | {ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700}, 50 | {ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800}, 51 | } 52 | 53 | for _, asset := range assets { 54 | assetJSON, err := json.Marshal(asset) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | err = ctx.GetStub().PutState(asset.ID, assetJSON) 60 | if err != nil { 61 | return fmt.Errorf("failed to put to world state: %v", err) 62 | } 63 | } 64 | 65 | return nil 66 | } 67 | 68 | // CreateAsset issues a new asset to the world state with given details. 69 | func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id, color string, size int, owner string, appraisedValue int) error { 70 | exists, err := s.AssetExists(ctx, id) 71 | if err != nil { 72 | return err 73 | } 74 | if exists { 75 | return fmt.Errorf("the asset %s already exists", id) 76 | } 77 | asset := Asset{ 78 | ID: id, 79 | Color: color, 80 | Size: size, 81 | Owner: owner, 82 | AppraisedValue: appraisedValue, 83 | } 84 | 85 | assetJSON, err := json.Marshal(asset) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | return ctx.GetStub().PutState(id, assetJSON) 91 | } 92 | 93 | // ReadAsset returns the asset stored in the world state with given id. 94 | func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { 95 | assetJSON, err := ctx.GetStub().GetState(id) 96 | if err != nil { 97 | return nil, fmt.Errorf("failed to read from world state. %s", err.Error()) 98 | } 99 | if assetJSON == nil { 100 | return nil, fmt.Errorf("the asset %s does not exist", id) 101 | } 102 | 103 | var asset Asset 104 | err = json.Unmarshal(assetJSON, &asset) 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | return &asset, nil 110 | } 111 | 112 | // UpdateAsset updates an existing asset in the world state with provided parameters. 113 | func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id, color string, size int, owner string, appraisedValue int) error { 114 | exists, err := s.AssetExists(ctx, id) 115 | if err != nil { 116 | return err 117 | } 118 | if !exists { 119 | return fmt.Errorf("the asset %s does not exist", id) 120 | } 121 | 122 | // overwritting original asset with new asset 123 | asset := Asset{ 124 | ID: id, 125 | Color: color, 126 | Size: size, 127 | Owner: owner, 128 | AppraisedValue: appraisedValue, 129 | } 130 | 131 | assetJSON, err := json.Marshal(asset) 132 | if err != nil { 133 | return err 134 | } 135 | 136 | return ctx.GetStub().PutState(id, assetJSON) 137 | } 138 | 139 | // DeleteAsset deletes an given asset from the world state. 140 | func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error { 141 | exists, err := s.AssetExists(ctx, id) 142 | if err != nil { 143 | return err 144 | } 145 | if !exists { 146 | return fmt.Errorf("the asset %s does not exist", id) 147 | } 148 | 149 | return ctx.GetStub().DelState(id) 150 | } 151 | 152 | // AssetExists returns true when asset with given ID exists in world state 153 | func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) { 154 | assetJSON, err := ctx.GetStub().GetState(id) 155 | if err != nil { 156 | return false, fmt.Errorf("failed to read from world state. %s", err.Error()) 157 | } 158 | 159 | return assetJSON != nil, nil 160 | } 161 | 162 | // TransferAsset updates the owner field of asset with given id in world state. 163 | func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error { 164 | asset, err := s.ReadAsset(ctx, id) 165 | if err != nil { 166 | return err 167 | } 168 | 169 | asset.Owner = newOwner 170 | assetJSON, err := json.Marshal(asset) 171 | if err != nil { 172 | return err 173 | } 174 | 175 | return ctx.GetStub().PutState(id, assetJSON) 176 | } 177 | 178 | // GetAllAssets returns all assets found in world state 179 | func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]QueryResult, error) { 180 | // range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace. 181 | resultsIterator, err := ctx.GetStub().GetStateByRange("", "") 182 | 183 | if err != nil { 184 | return nil, err 185 | } 186 | defer resultsIterator.Close() 187 | 188 | var results []QueryResult 189 | 190 | for resultsIterator.HasNext() { 191 | queryResponse, err := resultsIterator.Next() 192 | 193 | if err != nil { 194 | return nil, err 195 | } 196 | 197 | var asset Asset 198 | err = json.Unmarshal(queryResponse.Value, &asset) 199 | if err != nil { 200 | return nil, err 201 | } 202 | 203 | queryResult := QueryResult{Key: queryResponse.Key, Record: &asset} 204 | results = append(results, queryResult) 205 | } 206 | 207 | return results, nil 208 | } 209 | 210 | func main() { 211 | 212 | fmt.Printf("------------------------------------------\n") 213 | CORE_PEER_TLS_KEY_FILE, err := loadTLSFile(os.Getenv("CORE_PEER_TLS_KEY_FILE")) 214 | if err != nil { 215 | fmt.Printf("Error CORE_PEER_TLS_KEY_FILE : %s\n", err) 216 | } else { 217 | fmt.Printf("load CORE_PEER_TLS_KEY_FILE OK %s\n", CORE_PEER_TLS_KEY_FILE) 218 | } 219 | 220 | CORE_PEER_TLS_CERT_FILE, err := loadTLSFile(os.Getenv("CORE_PEER_TLS_CERT_FILE")) 221 | if err != nil { 222 | fmt.Printf("Error CORE_PEER_TLS_CERT_FILE : %s", err) 223 | } else { 224 | fmt.Printf("load CORE_PEER_TLS_CERT_FILE OK \n") 225 | } 226 | 227 | CORE_PEER_TLS_ROOTCERT_FILE, err := loadTLSFile(os.Getenv("CORE_PEER_TLS_ROOTCERT_FILE")) 228 | if err != nil { 229 | fmt.Printf("Error CORE_PEER_TLS_ROOTCERT_FILE : %s", err) 230 | } else { 231 | fmt.Printf("load CORE_PEER_TLS_ROOTCERT_FILE OK \n") 232 | } 233 | 234 | // See chaincode.env.example 235 | config := serverConfig{ 236 | CCID: os.Getenv("CHAINCODE_ID"), 237 | Address: os.Getenv("CHAINCODE_SERVER_ADDRESS"), 238 | } 239 | 240 | fmt.Printf("CCID %s\n", config.CCID) 241 | fmt.Printf("CHAINCODE_SERVER_ADDRESS %s\n", config.Address) 242 | 243 | 244 | chaincode, err := contractapi.NewChaincode(&SmartContract{}) 245 | 246 | if err != nil { 247 | log.Panicf("error create asset-transfer-basic chaincode: %s", err) 248 | } 249 | 250 | server := &shim.ChaincodeServer{ 251 | CCID: config.CCID, 252 | Address: config.Address, 253 | CC: chaincode, 254 | TLSProps: shim.TLSProperties{ 255 | Disabled: false, 256 | Key: CORE_PEER_TLS_KEY_FILE, 257 | Cert: CORE_PEER_TLS_CERT_FILE, 258 | ClientCACerts: CORE_PEER_TLS_ROOTCERT_FILE, 259 | }, 260 | } 261 | 262 | if err := server.Start(); err != nil { 263 | log.Panicf("error starting asset-transfer-basic chaincode: %s", err) 264 | } else { 265 | fmt.Printf("CHAINCODE SERVER is running %s\n", config.Address) 266 | } 267 | } 268 | 269 | 270 | func loadTLSFile(filePth string) ([]byte, error) { 271 | f, err := os.Open(filePth) 272 | if err != nil { 273 | return nil, err 274 | } 275 | return ioutil.ReadAll(f) 276 | } 277 | 278 | -------------------------------------------------------------------------------- /meetup-290121/fabric2DevMode.md: -------------------------------------------------------------------------------- 1 | # Fabric 2.2 Chaincode Devmode Environment - Binary Edition 2 | In this tutorial you will learn how you can enable the so called **peer devmode** for chaincode development. The devmode is running with binaries and **without** docker containers. 3 | 4 | # Contents 5 | - [Set up the Development Environment](#Set-up-the-development-environment) 6 | - [Start the Orderer](#Start-the-orderer) 7 | - [Start the peer in DevMode](#Start-the-peer-in-DevMode) 8 | - [Create the Channel](#Create-the-channel-ch1) 9 | - [Join the Channel](#Join-the-channel) 10 | - [Build the Chaincode](#Build-the-chaincode) 11 | - [Start the Chaincode](#Start-the-Chaincode) 12 | - [Approve and commit the Chaincode](#Approve-and-commit-the-Chaincode) 13 | - [Test your Chaincode](#Test-your-Chaincode) 14 | - [Modify your Chaincode](#Modify-your-Chaincode) 15 | - [Helpful tmux operations](#Helpful-tmux-operations) 16 | - [Stop the network](#Stop-the-network) 17 | - [Start the network again](#Start-the-network-again) 18 | - [Housekeepting](#Housekeepting) 19 | 20 | For the next steps we need four terminals. You can use four different ssh terminals or one tmux terminal with four panels as well. 21 | 22 | # Housekeepting 23 | To clean up the system we have to delete the content of the data folder (leader data) and the content of the artifacts folder. 24 | 25 | ```bash 26 | rm -R $(pwd)/data/* 27 | rm $(pwd)/artifacts/* 28 | ``` 29 | 30 | # Set up the development environment 31 | 32 | ```bash 33 | mkdir fabricDev 34 | cd fabricDev 35 | # clone the latest fabric repro 36 | git clone https://github.com/hyperledger/fabric.git 37 | 38 | # switch onto this folder 39 | cd fabric 40 | 41 | # create a place to store the artifacts 42 | mkdir artifacts 43 | 44 | # create a place to store our chaincodes 45 | mkdir chaincode 46 | ``` 47 | At this time you should have a folder structure like the following: 48 | 49 | ```bash 50 | root@fabric-04:~/fabricDev# tree -L 1 . 51 | . 52 | ├── artifacts 53 | ├── chaincode 54 | └── fabric 55 | ``` 56 | 57 | ```bash 58 | # as a next step you have to build the binaries 59 | # run the following commands to build the binaries for orderer, peer, and configtxgen 60 | ## we switch into the fabric-folder 61 | cd fabric 62 | 63 | ## build (make sure you have installed gcc and make), Building build/bin/ 64 | make orderer peer configtxgen 65 | 66 | ## if you are ready then go back 67 | cd ../ 68 | 69 | # set the PATH environment variable to include orderer and peer binaries 70 | export PATH=$(pwd)/fabric/build/bin:$PATH 71 | 72 | # set the FABRIC_CFG_PATH environment variable to point to the sampleconfig folder and MSP 73 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 74 | 75 | # generate the genesis block for the ordering service 76 | configtxgen -profile SampleDevModeSolo -channelID syschannel -outputBlock genesisblock -configPath $FABRIC_CFG_PATH -outputBlock $(pwd)/artifacts/genesis.block 77 | ``` 78 | 79 | # Start the orderer 80 | ```bash 81 | # in terminal 0 82 | export PATH=$(pwd)/fabric/build/bin:$PATH 83 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 84 | 85 | ## version with environment variables 86 | export ORDERER_GENERAL_GENESISFILE=$(pwd)/artifacts/genesis.block 87 | export ORDERER_FILELEDGER_LOCATION=$(pwd)/data/orderer 88 | export ORDERER_GENERAL_GENESISPROFILE=SampleDevModeSolo 89 | orderer 90 | 91 | ## version in a single command 92 | ORDERER_GENERAL_GENESISFILE=$(pwd)/artifacts/genesis.block ORDERER_FILELEDGER_LOCATION=$(pwd)/data/orderer ORDERER_GENERAL_GENESISPROFILE=SampleDevModeSolo orderer 93 | ``` 94 | 95 | # Start the peer in DevMode 96 | ```bash 97 | # in terminal 1 98 | # Open another terminal window and set the required environment variables to override the peer configuration and start the peer node. Starting the peer with the --peer-chaincodedev=true flag puts the peer into DevMode. 99 | 100 | export PATH=$(pwd)/fabric/build/bin:$PATH 101 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 102 | 103 | # we have to modify core.yaml and change the port to 10443, because 9443 is double used between the orderer and the peer (operations services) 104 | 105 | ## version with environment variables 106 | export CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:10443 107 | export CORE_PEER_FILESYSTEMPATH=$(pwd)/data/ 108 | export FABRIC_LOGGING_SPEC=chaincode=debug 109 | export CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 110 | 111 | peer node start --peer-chaincodedev=true 112 | 113 | ## version in a single command 114 | CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:10443 CORE_PEER_FILESYSTEMPATH=$(pwd)/data/ FABRIC_LOGGING_SPEC=chaincode=debug CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 peer node start --peer-chaincodedev=true 115 | 116 | ``` 117 | # Create the channel 118 | ```bash 119 | # in terminal 2 120 | export PATH=$(pwd)/fabric/build/bin:$PATH 121 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 122 | 123 | configtxgen -channelID ch1 -outputCreateChannelTx $(pwd)/artifacts/ch1.tx -profile SampleSingleMSPChannel -configPath $FABRIC_CFG_PATH 124 | 125 | peer channel create -o 127.0.0.1:7050 --outputBlock $(pwd)/artifacts/ch1.block -c ch1 -f $(pwd)/artifacts/ch1.tx 126 | 127 | # we can fetch the newest block as well 128 | # peer channel fetch newest $(pwd)/artifacts/ch1.block -c ch1 -o 127.0.0.1:7050 129 | ``` 130 | 131 | # Join the channel 132 | ```bash 133 | peer channel join -b $(pwd)/artifacts/ch1.block 134 | ``` 135 | 136 | # Build the chaincode 137 | Now it is time to use your chaincode. 138 | 139 | ```bash 140 | # We use the simple chaincode from the fabric/integration/chaincode directory to demonstrate how to run a chaincode package in DevMode. 141 | cp -R ../fabric/fabric-samples/chaincode/sacc/ chaincode 142 | cd chaincode/sacc 143 | 144 | #go mod init chaincode 145 | G111MODULE=on go mod vendor 146 | go build -o simpleChaincode 147 | ``` 148 | 149 | # Start the Chaincode 150 | ```bash 151 | 152 | export DEVMODE_ENABLED=true 153 | 154 | # in terminal 3 155 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./simpleChaincode -peer.address 127.0.0.1:7052 156 | 157 | ``` 158 | 159 | # Approve and commit the Chaincode 160 | 161 | ```bash 162 | # in terminal 4 163 | 164 | export PATH=$(pwd)/fabric/build/bin:$PATH 165 | export FABRIC_CFG_PATH=$(pwd)/fabric/sampleconfig 166 | 167 | peer lifecycle chaincode approveformyorg -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --package-id mycc:1.0 168 | 169 | peer lifecycle chaincode checkcommitreadiness -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" 170 | 171 | peer lifecycle chaincode commit -o 127.0.0.1:7050 --channelID ch1 --name mycc --version 1.0 --sequence 1 --init-required --signature-policy "OR ('SampleOrg.member')" --peerAddresses 127.0.0.1:7051 172 | ``` 173 | 174 | # Test your Chaincode 175 | 176 | ```bash 177 | # in terminal 4 178 | ## calls the init function 179 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["msg","Hello"]}' --isInit 180 | 181 | # querys the key 182 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["","msg"]}' 183 | 184 | # set new value 185 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["set","msg2","Hello2"]}' 186 | 187 | ``` 188 | 189 | # Modify your Chaincode 190 | Stop the chaincode in terminal 2. 191 | ```bash 192 | CTRL + c 193 | ``` 194 | 195 | Modify the chaincode e.g. add some debug values. Add the following snippet into the get function (befor the return command). 196 | ``` 197 | if os.Getenv("DEVMODE_ENABLED") != "" { 198 | fmt.Printf("Asset: %s\n",args[0]) 199 | } 200 | 201 | # add the os package to the import statement 202 | "os" 203 | ``` 204 | 205 | Build your chaincode again. 206 | ```bash 207 | go build -o simpleChaincode 208 | ``` 209 | 210 | Start your chaincode again. 211 | ```bash 212 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./simpleChaincode -peer.address 127.0.0.1:7052 213 | 214 | DEVMODE_ENABLED=test CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./simpleChaincode -peer.address 127.0.0.1:7052 215 | 216 | DEVMODE_ENABLED= CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./simpleChaincode -peer.address 127.0.0.1:7052 217 | 218 | ``` 219 | 220 | # Helpful tmux operations 221 | ```bash 222 | # start a new tmux session 223 | tmux new -s mysession 224 | 225 | # split your screen 226 | ## split pane horizontally 227 | CTRL + b \" (do it without the backslash) 228 | 229 | ## split pane vertically 230 | CTRL + b % 231 | 232 | # switch between panels 233 | CTRL + q 1 (the number of the panel) 234 | 235 | # leave the running tmux session 236 | CTRL + b d 237 | 238 | # show all running tmux session 239 | tmux ls 240 | 241 | # attach a running tmux session 242 | tmux att -t fabricDev 243 | 244 | # enable scrolling mode 245 | CTRL + b fn + up 246 | 247 | # leave scrolling mode 248 | ESC 249 | 250 | # remove a panel 251 | CTRL + b x 252 | 253 | ``` 254 | 255 | # Stop the network 256 | ```bash 257 | # kill the chaincode 258 | pkill -9 simpleChaincode 259 | 260 | # kill the peer 261 | pkill -9 peer 262 | 263 | # kill the orderer 264 | pkill -9 orderer 265 | 266 | # or use a bash script 267 | ``` 268 | 269 | # Start the network again 270 | ```bash 271 | # start the orderer in terminal 0 272 | 273 | # start the peer in terminal 1 274 | 275 | # start the chaincode in terminal 2 276 | 277 | # do your CLI calls from terminal 3 278 | ``` 279 | -------------------------------------------------------------------------------- /meetup-180621/index.md: -------------------------------------------------------------------------------- 1 | # Attribute-based access controll (ABAC) 2 | 3 | In this lab we are going to implement the following scenario. One organization with two different roles: 4 | 5 | - one for creating and updating assets and 6 | - one only for reading those assets. 7 | 8 | For that we need at least **three terminals**. I use three different tmux panes in that lab. 9 | 10 | Start a tmux session. 11 | ```bash 12 | tmux new -s fabric 13 | ``` 14 | 15 | Let's start the development test network. Refer to previous labs for more information on getting started with a fabric development network and with tmux panels. 16 | 17 | The sdg devNetwork is optimized for this lab and not suitable for productive use. It is based on the test-network but reduced for the usage of this course. 18 | 19 | 20 | ```bash 21 | ./devNetwork.sh up -ca 22 | ``` 23 | 24 | Now, create two more panes - one for starting the chaincode and one for interacting with your chaincode. 25 | 26 | ## Register identities with attributes 27 | 28 | We will create the identities using the predefined Org1 CA. Firstly, we have to set the **FABRIC_CA_CLIENT_HOME** environment variable to the MSP of the Org1 CA admin: 29 | 30 | ```bash 31 | # set the path 32 | export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ 33 | 34 | # check the path 35 | echo $FABRIC_CA_CLIENT_HOME 36 | ``` 37 | 38 | Secondly, we can register and enroll two users: writer and reader under the prefix samlinux. Both new users are defined with a proper attribute **--id.attrs 'samlinux.writer=true:ecert'**. 39 | 40 | ```bash 41 | # register first 42 | ## client samlinux.writer 43 | fabric-ca-client register --id.name writer --id.secret writerpw --id.type client --id.attrs 'samlinux.writer=true:ecert' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 44 | 45 | ## client samlinux.reader 46 | fabric-ca-client register --id.name reader --id.secret readerpw --id.type client --id.attrs 'samlinux.reader=true:ecert' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 47 | ``` 48 | 49 | ```bash 50 | # enroll second 51 | fabric-ca-client enroll -u https://writer:writerpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/writer@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 52 | 53 | fabric-ca-client enroll -u https://reader:readerpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 54 | ``` 55 | 56 | Now, as you have enrolled the identity, run the command below to copy the Node OU configuration file into the creator1 MSP folder. 57 | 58 | ```bash 59 | cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/writer@org1.example.com/msp/config.yaml" 60 | 61 | cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp/config.yaml" 62 | ``` 63 | 64 | Check your result. 65 | ```bash 66 | # inspect the user folder from org1 67 | tree -L 1 organizations/peerOrganizations/org1.example.com/users/ 68 | 69 | # you should see the following result 70 | organizations/peerOrganizations/org1.example.com/users/ 71 | ├── Admin@org1.example.com 72 | ├── User1@org1.example.com 73 | ├── reader@org1.example.com 74 | └── writer@org1.example.com 75 | ``` 76 | 77 | **One note to the :ecert suffix.** 78 | 79 | The ”:ecert” suffix means that by default the attribute and it's value will be inserted into the identity’s enrollment certificate which can then be used to make access control decisions. 80 | 81 | You can leave this suffix as well. But in this case you have to use the **--enrollment.attrs** option to include some attributes into the enrolled certificate. 82 | 83 | Let's do some experiments to get more familiar with that approach. 84 | ```bash 85 | # register a manager 86 | fabric-ca-client register --id.name manager --id.secret writerpw --id.type client --id.attrs 'samlinux.manager=true' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 87 | 88 | # enroll the manager 89 | ## without enrollment.attrs 90 | fabric-ca-client enroll -u https://manager:writerpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/manager@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 91 | 92 | ## with enrollment.attrs 93 | fabric-ca-client enroll -u https://manager:writerpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/manager@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" --enrollment.attrs 'samlinux.manager,hf.Type,hf.EnrollmentID' 94 | 95 | # check the certificate 96 | openssl x509 -in organizations/peerOrganizations/org1.example.com/users/manager@org1.example.com/msp/signcerts/cert.pem -text -noout 97 | ``` 98 | What is your observation? 99 | 100 | ## Inspect signing certs 101 | Some further useful commands. 102 | 103 | Get a list of all identities. 104 | ```bash 105 | fabric-ca-client identity list --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 106 | ``` 107 | 108 | List one particular identity. 109 | ```bash 110 | fabric-ca-client identity list --id reader --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 111 | ``` 112 | 113 | Inspect the signcert form reader. 114 | ```bash 115 | openssl x509 -in organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp/signcerts/cert.pem -text -noout 116 | ``` 117 | 118 | Take some time to inspect the content of one of those created signing certs. 119 | 120 | ```bash 121 | Certificate: 122 | Data: 123 | Version: 3 (0x2) 124 | Serial Number: 125 | 3a:a2:f8:fd:7f:a8:c7:0e:7d:8e:7c:e5:6d:fd:5f:21:92:16:b1:77 126 | Signature Algorithm: ecdsa-with-SHA256 127 | Issuer: C = US, ST = North Carolina, O = Hyperledger, OU = Fabric, CN = fabric-ca-server 128 | Validity 129 | Not Before: Jun 4 05:46:00 2021 GMT 130 | Not After : Jun 4 05:51:00 2022 GMT 131 | Subject: C = US, ST = North Carolina, O = Hyperledger, OU = client + OU = org1, CN = reader 132 | Subject Public Key Info: 133 | Public Key Algorithm: id-ecPublicKey 134 | Public-Key: (256 bit) 135 | pub: 136 | 04:71:4e:c3:f7:82:c0:d0:91:8b:4a:d6:d8:75:49: 137 | c3:15:49:63:de:9e:d3:0d:35:a1:65:28:f5:6d:95: 138 | 8b:80:8d:59:34:2e:98:67:8c:6a:03:88:ac:be:45: 139 | 02:c7:b7:aa:a6:92:f7:2b:d4:d6:78:b8:56:c4:9c: 140 | a1:fc:9f:1b:42 141 | ASN1 OID: prime256v1 142 | NIST CURVE: P-256 143 | X509v3 extensions: 144 | X509v3 Key Usage: critical 145 | Digital Signature 146 | X509v3 Basic Constraints: critical 147 | CA:FALSE 148 | X509v3 Subject Key Identifier: 149 | 91:06:0C:49:07:D8:E5:25:FE:4D:88:7B:0B:84:C3:7F:48:60:15:A7 150 | X509v3 Authority Key Identifier: 151 | keyid:FB:03:89:63:09:98:A6:91:D7:72:2A:6D:D4:8C:AA:98:23:3F:1B:15 152 | 153 | X509v3 Subject Alternative Name: 154 | DNS:fabric04 155 | 1.2.3.4.5.6.7.8.1: 156 | {"attrs":{"hf.Affiliation":"org1","hf.EnrollmentID":"reader","hf.Type":"client","samlinux.writer":"true"}} 157 | Signature Algorithm: ecdsa-with-SHA256 158 | 30:44:02:20:6d:1f:83:68:ee:ae:be:00:c0:04:71:4a:21:c8: 159 | 9f:12:2f:38:bc:b2:40:c9:37:3d:13:46:2b:9a:d7:f6:a2:9b: 160 | 02:20:25:bd:da:62:9d:30:4e:cf:53:f8:55:36:e7:85:46:a1: 161 | 3d:ba:2e:5b:2e:8e:44:68:02:e4:68:df:a6:ad:dc:51 162 | ``` 163 | 164 | ## Start the chaincode 165 | 166 | In the second panel start the chaincode. 167 | ```bash 168 | cd chaincode/nodejs/cs04 169 | 170 | CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_TLS_ENABLED=false CORE_CHAINCODE_ID_NAME=mycc:1.0 ./node_modules/.bin/fabric-chaincode-node start --peer.address 127.0.0.1:7052 171 | ``` 172 | 173 | ## Testcalls for the chaincode 174 | In the third panel interact with the chaincode, but first you have to set some environment variables. 175 | 176 | ```bash 177 | # set environment vars 178 | source org1.sh 179 | setGlobals 180 | ``` 181 | 182 | ### Test the chaincode 183 | 184 | Use the **writer** identity first. 185 | 186 | ```bash 187 | # set the CORE_PEER_MSPCONFIGPATH variable to the users MSP 188 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/writer@org1.example.com/msp 189 | 190 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["set","{\"no\":\"a1\", \"desc\":\"Product number 1\",\"amount\":120, \"price\":\"10.50\", \"type\":\"brick\"}"]}' 191 | ``` 192 | 193 | Use the **reader** identity for the same test. 194 | ```bash 195 | # set the CORE_PEER_MSPCONFIGPATH variable to the users MSP 196 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp 197 | 198 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode invoke -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["set","{\"no\":\"a1\", \"desc\":\"Product number 1\",\"amount\":1000, \"price\":\"10.50\", \"type\":\"brick\"}"]}' 199 | ``` 200 | 201 | The **reader** should be allowed only reading, not invoking. 202 | ```bash 203 | CORE_PEER_ADDRESS=127.0.0.1:7051 peer chaincode query -o 127.0.0.1:7050 -C ch1 -n mycc -c '{"Args":["get","a1"]}' 204 | ``` 205 | 206 | Test with a user without any proper permissions **(User1)**. What is the result? 207 | ```bash 208 | # set the CORE_PEER_MSPCONFIGPATH variable to the users MSP 209 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp 210 | ``` 211 | 212 | ## Modify identities and remove the samlinux.reader attribute 213 | 214 | ```bash 215 | # remove samlinux.reader attribute 216 | fabric-ca-client identity modify reader --attrs 'samlinux.reader=' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 217 | 218 | # add the same attribute 219 | fabric-ca-client identity modify reader --attrs '"samlinux.reader=true:ecert","samlinux.auditor=true:ecert"' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 220 | 221 | # reenroll or enroll it again 222 | fabric-ca-client reenroll -u https://reader:reader1pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" 223 | 224 | # inspect the signing cert 225 | openssl x509 -in organizations/peerOrganizations/org1.example.com/users/reader@org1.example.com/msp/signcerts/cert.pem -text -noout 226 | ``` 227 | 228 | [Try the challenge](./challenge-01.md) 229 | 230 | [Index](../README.md) 231 | -------------------------------------------------------------------------------- /meetup-061020/index.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | These steps describes a HLF 2.2.x installation on a DigitalOcean Droplet. 3 | 4 | ## Droplet 5 | Digital Ocean Droplet, 1 CPU, 2 GB, 50 GB SSD 6 | OS, Ubuntu 20.04 (LTS) x64 7 | 8 | ## Access via ssh 9 | ssh root@ssh root@xx 10 | 11 | ## Perparations 12 | The following steps are required to prepare the Droplet. 13 | ```bash 14 | # update the OS 15 | apt update && apt upgrade 16 | 17 | # install some useful helpers 18 | apt install tree jq gcc make 19 | 20 | # it's always good the use the right time 21 | # so setup the correct timezone 22 | timedatectl set-timezone Europe/Vienna 23 | 24 | # check the time 25 | date 26 | ``` 27 | 28 | ## Install Docker 29 | The following steps are required to install docker on the Droplet. Reference: https://docs.docker.com/engine/install/ubuntu/ 30 | 31 | ```bash 32 | # set up the repository 33 | sudo apt install \ 34 | apt-transport-https \ 35 | ca-certificates \ 36 | curl \ 37 | gnupg-agent \ 38 | software-properties-common 39 | 40 | # add Docker’s official GPG key 41 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 42 | 43 | 44 | # set up the stable repository 45 | sudo add-apt-repository \ 46 | "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ 47 | $(lsb_release -cs) \ 48 | stable" 49 | 50 | # install docker engine 51 | apt update 52 | apt install docker-ce docker-ce-cli containerd.io 53 | 54 | # check the docker version 55 | docker --version 56 | ``` 57 | 58 | ## Install Docker-Compose 59 | 60 | Reference https://docs.docker.com/compose/install/ 61 | 62 | ```bash 63 | # install docker-compose 64 | curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 65 | 66 | # apply executable permissions to the binary 67 | sudo chmod +x /usr/local/bin/docker-compose 68 | 69 | # check the docker-compose version 70 | docker-compose --version 71 | ``` 72 | 73 | ## Install Go Programming Language 74 | Hyperledger Fabric uses the Go Programming Language for many of its components. Go version 1.14.x is required. 75 | 76 | ```bash 77 | # download and extract go 78 | # latest version 04.10.20 1.14.9 79 | wget -c https://dl.google.com/go/go1.14.9.linux-amd64.tar.gz -O - | tar -xz -C /usr/local 80 | 81 | # add the go binary to the path 82 | echo 'export PATH="$PATH:/usr/local/go/bin:/root/fabric/fabric-samples/bin"' >> $HOME/.profile 83 | 84 | # point the GOPATH env var to the base fabric workspace folder 85 | echo 'export GOPATH="$HOME/fabric"' >> $HOME/.profile 86 | 87 | # reload the profile 88 | source $HOME/.profile 89 | 90 | # check the go version 91 | go version 92 | 93 | # check the vars 94 | printenv | grep PATH 95 | ``` 96 | 97 | ## Install node.js 98 | 99 | ```bash 100 | # add PPA from NodeSource 101 | curl -sL https://deb.nodesource.com/setup_12.x -o nodesource_setup.sh 102 | 103 | # call the install script 104 | . nodesource_setup.sh 105 | 106 | # install node.js 107 | apt-get install -y nodejs 108 | 109 | # check the version 110 | node -v 111 | ``` 112 | 113 | ## Install Samples, Binaries and Docker Images 114 | 115 | ```bash 116 | mkdir fabric 117 | cd fabric 118 | 119 | # install the latest production release from the 1.4.x branch 120 | # curl -sSL http://bit.ly/2ysbOFE | bash -s -- 121 | 122 | # curl -sSL http://bit.ly/2ysbOFE | bash -s -- 1.4.6 1.4.6 0.4.18 123 | 124 | # latest production ready release, omit all version identifiers 125 | # curl -sSL https://bit.ly/2ysbOFE | bash -s 126 | 127 | # we use 2.2 in our examples 128 | curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.2.1 1.4.9 129 | 130 | # check downloaded images 131 | docker images 132 | 133 | # check the bin cmd 134 | peer version 135 | 136 | ``` 137 | 138 | ## Try the installation 139 | The fabric-samples provisions a sample Hyperledger Fabric test-network consisting of two organizations, each maintaining one peer nodes. It also will deploy a single RAFT ordering service by default. 140 | 141 | To test your installationen we can start interacting with the network. 142 | 143 | ```bash 144 | # switch to the base folder 145 | cd fabric-samples/test-network 146 | 147 | # print some help 148 | ./network.sh --help 149 | 150 | # bring up the network 151 | ./network.sh up createChannel -c channel1 152 | 153 | # install default CC - asset-transfer (basic) chaincode 154 | ./network.sh deployCC -c channel1 155 | 156 | # show if some containers are running 157 | docker ps 158 | docker-compose -f docker/docker-compose-test-net.yaml ps 159 | ``` 160 | 161 | ## Interacting with the network 162 | 163 | tmux control 164 | ```bash 165 | # start a new tmux session 166 | tmux new -s fabric 167 | 168 | # attach to existing session 169 | tmux add -t fabric 170 | 171 | # show all logs 172 | docker-compose -f docker/docker-compose-test-net.yaml logs -f -t 173 | 174 | # open a new panel 175 | CTRL + b (release pressed keys) + " 176 | 177 | # jump between panels 178 | CTRL + b + q 1 179 | 180 | # detach from session 181 | CTRL + b + d 182 | 183 | ``` 184 | 185 | ### Environment variables for peer Org1 186 | 187 | ```bash 188 | # create an env file 189 | vi org1.sh 190 | 191 | export FABRIC_CFG_PATH=$HOME/fabric/fabric-samples/config/ 192 | export CHANNEL_NAME="channel1" 193 | 194 | export CORE_PEER_TLS_ENABLED=true 195 | export CORE_PEER_LOCALMSPID="Org1MSP" 196 | export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 197 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 198 | export CORE_PEER_ADDRESS=localhost:7051 199 | 200 | # execute the env file 201 | source ./org1.sh 202 | 203 | # check env vars 204 | printenv | grep CORE 205 | ``` 206 | 207 | #### Initialize the leder (sample data) 208 | Run the following command to initialize the ledger with assets: 209 | ```bash 210 | 211 | # for explanation 212 | peer chaincode invoke 213 | -o localhost:7050 214 | --ordererTLSHostnameOverride orderer.example.com 215 | --tls 216 | --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 217 | -C $CHANNEL_NAME 218 | -n basic 219 | --peerAddresses localhost:7051 220 | --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 221 | --peerAddresses localhost:9051 222 | --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 223 | -c '{"function":"InitLedger","Args":[]}' 224 | 225 | 226 | # for copy and paste 227 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}' 228 | ``` 229 | 230 | #### Query the leder 231 | 232 | ```bash 233 | # Read the last state of all assets 234 | peer chaincode query -C $CHANNEL_NAME -n basic -c '{"Args":["GetAllAssets"]}' | jq . 235 | 236 | # Read an asset 237 | peer chaincode query -C $CHANNEL_NAME -n basic -c '{"Args":["ReadAsset","asset1"]}' | jq . 238 | ``` 239 | 240 | #### Create an asset 241 | ```bash 242 | 243 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"CreateAsset","Args":["asset7","green","10","Roland","500"]}' 244 | ``` 245 | 246 | #### Update an asset 247 | ```bash 248 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"UpdateAsset","Args":["asset7","green","10","Roland","600"]}' 249 | ``` 250 | 251 | #### Transfer an asset 252 | ```bash 253 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset7","Joana"]}' 254 | ``` 255 | 256 | #### Delete an asset 257 | ```bash 258 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"DeleteAsset","Args":["asset1"]}' 259 | ``` 260 | 261 | ### Switch to peer Org2 262 | We can switch to work with peer Org2 peer0.org2.example.com with changeing the following evironment variables. 263 | ```bash 264 | 265 | # create an env file 266 | vi org2.sh 267 | 268 | # Environment variables for Org2 269 | export FABRIC_CFG_PATH=$HOME/fabric/fabric-samples/config/ 270 | export CHANNEL_NAME="channel1" 271 | 272 | export CORE_PEER_TLS_ENABLED=true 273 | export CORE_PEER_LOCALMSPID="Org2MSP" 274 | export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 275 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 276 | export CORE_PEER_ADDRESS=localhost:9051 277 | 278 | # execute the env file 279 | source ./org2.sh 280 | ``` 281 | 282 | ## Bring down the network 283 | ```bash 284 | ./network.sh down 285 | ``` 286 | 287 | [Index](../README.md) -------------------------------------------------------------------------------- /meetup-181220/index.md: -------------------------------------------------------------------------------- 1 | # How to create your own fabric network 2 | In this guide you will create a **persistent** three org fabric network with a one node RAFT orderer. 3 | 4 | We need the following files: 5 | 6 | - crypto-config.yaml (create identities) 7 | - configtx.yaml (system channel and application channel config) 8 | - docker-compose.yaml (create a docker network with some containers) 9 | 10 | ## Preparation 11 | ```bash 12 | # here we are - base folder pwd shows our current location 13 | fabric-samples/ 14 | 15 | # create a new base folder into the fabric-samples folder 16 | mkdir own-network 17 | 18 | # Cleaning things up, if necessary 19 | rm -Rf organizations 20 | rm -Rf channel-artifacts 21 | rm -Rf channel-artifacts 22 | 23 | # copy some files from the test-network 24 | mkdir configtx 25 | cp ../test-network/configtx/* configtx/ 26 | cp ../test-network/docker/docker-compose-test-net.yaml ./docker-compose.yaml 27 | ``` 28 | ## Create crypto-config.yaml file 29 | Create a crypto-config.yaml file for the cryptogen tool. 30 | 31 | ```bash 32 | vi crypto-config.yaml 33 | cat ../test-network/organizations/cryptogen/crypto-config-orderer.yaml >> crypto-config.yaml 34 | cat ../test-network/organizations/cryptogen/crypto-config-org1.yaml >> crypto-config.yaml 35 | 36 | # extend org2 + org3 37 | ``` 38 | ## Prepare the configtx.yaml 39 | Modify the configtx.yaml file. 40 | 41 | Section Organizations; add new Org3 42 | Section Profile; add new profiles: ThreeOrgsOrdererGenesis, ThreeOrgsChannel 43 | 44 | 45 | ## Generate artifacts 46 | 47 | ```bash 48 | # tell the configtxgen tool where to look for the configtx.yaml file 49 | export FABRIC_CFG_PATH=$PWD/configtx 50 | 51 | # the name of the channels 52 | export CHANNEL_NAME=channel1 53 | export SYS_CHANNEL_NAME=sys-channel 54 | 55 | # Generate the artifacts (identities) 56 | cryptogen generate --config=./crypto-config.yaml --output organizations 57 | 58 | # create channel-artifacts and system-genesis-block folder 59 | mkdir channel-artifacts 60 | mkdir system-genesis-block 61 | 62 | # create genesis block 63 | configtxgen -profile ThreeOrgsOrdererGenesis -channelID $SYS_CHANNEL_NAME -outputBlock ./system-genesis-block/genesis.block 64 | 65 | # create a Channel Configuration Transaction 66 | configtxgen -profile ThreeOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel_$CHANNEL_NAME.tx -channelID $CHANNEL_NAME 67 | 68 | # create the Anchor Peer Transactions for each peer org 69 | configtxgen -profile ThreeOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP 70 | 71 | configtxgen -profile ThreeOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP 72 | 73 | configtxgen -profile ThreeOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org3MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org3MSP 74 | 75 | # finally check your work 76 | tree ./organizations -L 2 77 | tree ./channel-artifacts 78 | tree ./system-genesis-block 79 | 80 | ``` 81 | 82 | ## Start network 83 | Modify the docker-compose-yaml file. Please note the CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE docker variable and also the .env file. 84 | 85 | ```bash 86 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_own-network 87 | 88 | vi .env 89 | COMPOSE_PROJECT_NAME=own-network 90 | IMAGE_TAG=latest 91 | SYS_CHANNEL=system-channel 92 | 93 | # !! change the network name as well to own-network 94 | networks: 95 | - own-network 96 | ``` 97 | 98 | ```bash 99 | # terminal 1 100 | # start the network as a foreground process (we work with two terminals) to see the logs 101 | docker-compose up 102 | ``` 103 | 104 | # Create Channel 105 | ```bash 106 | # terminal 2 107 | cd fabric/fabric-samples/own-network 108 | 109 | # set some env vars 110 | export FABRIC_CFG_PATH=$PWD/../config/ 111 | export CHANNEL_NAME=channel1 112 | export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 113 | 114 | # create env files to switch between orgs 115 | - create org1.env 116 | - create org2.env 117 | - create org3.env 118 | 119 | vi org1.env 120 | export CORE_PEER_TLS_ENABLED=true 121 | export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 122 | export CORE_PEER_LOCALMSPID="Org1MSP" 123 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 124 | export CORE_PEER_ADDRESS=localhost:7051 125 | export FABRIC_CFG_PATH=$PWD/../config/ 126 | 127 | # do this also for org2.env and org3.env 128 | 129 | # switch to the org1 env 130 | source org1.env 131 | 132 | # create channel 133 | peer channel create -o localhost:7050 -c $CHANNEL_NAME --ordererTLSHostnameOverride orderer.example.com -f ./channel-artifacts/channel_${CHANNEL_NAME}.tx --outputBlock ./channel-artifacts/${CHANNEL_NAME}.block --tls --cafile $ORDERER_CA 134 | 135 | # join org1 to channel 136 | peer channel join -b ./channel-artifacts/$CHANNEL_NAME.block 137 | 138 | ## check the result with peer channel list 139 | 140 | # join org2 to channel 141 | source org2.env 142 | peer channel join -b ./channel-artifacts/$CHANNEL_NAME.block 143 | 144 | # join org3 to channel 145 | source org3.env 146 | peer channel join -b ./channel-artifacts/$CHANNEL_NAME.block 147 | 148 | # update anchor peer per org 149 | 150 | source org1.env 151 | peer channel update -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile $ORDERER_CA 152 | 153 | source org2.env 154 | peer channel update -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile $ORDERER_CA 155 | 156 | source org3.env 157 | peer channel update -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c $CHANNEL_NAME -f ./channel-artifacts/Org3MSPanchors.tx --tls --cafile $ORDERER_CA 158 | ``` 159 | 160 | We are ready with the network and channel configuration. At this point we can start installing some chaincode. 161 | 162 | 163 | # Install Chaincode 164 | As a demo we are going to use the ABstore chaincode example. 165 | 166 | ```bash 167 | mkdir chaincode 168 | cp -r ../chaincode/abstore/go/ chaincode/abstore/ 169 | 170 | # if needed 171 | rm -r chaincode/abstore/vendor 172 | 173 | cd ./chaincode/abstore 174 | 175 | # install (external) go dependencies 176 | GO111MODULE=on go mod vendor 177 | 178 | ## fabric chaincode lifecycle 179 | # step 1 - package the chaincode 180 | cd ../../ 181 | peer lifecycle chaincode package basic.tar.gz --path ./chaincode/abstore/ --lang golang --label basic_1 182 | 183 | # check the content 184 | tar -tvf basic.tar.gz 185 | 186 | # install CC on peer0 Org1 187 | source org1.env 188 | peer lifecycle chaincode install basic.tar.gz 189 | 190 | # basic_1:d44a118ea789f00646aec920719320c9c177a68c59150195ec479f3b42e1a672 191 | 192 | # install CC on peer0 Org2 193 | source org2.env 194 | peer lifecycle chaincode install basic.tar.gz 195 | 196 | # install CC on peer0 Org3 197 | source org3.env 198 | peer lifecycle chaincode install basic.tar.gz 199 | 200 | # we switch back to org1 201 | source org1.env 202 | export PKGID=basic_1:d44a118ea789f00646aec920719320c9c177a68c59150195ec479f3b42e1a672 203 | 204 | # approve CC for Org1 205 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name basic --version 1 --package-id $PKGID --sequence 1 206 | 207 | # approve CC for Org2 208 | source org2.env 209 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name basic --version 1 --package-id $PKGID --sequence 1 210 | 211 | # check readyness 212 | peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name basic --version 1 --sequence 1 --tls --cafile $ORDERER_CA --output json 213 | 214 | # approve CC for Org3 215 | source org3.env 216 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name basic --version 1 --package-id $PKGID --sequence 1 217 | 218 | # commit the CC 219 | source org1.env 220 | 221 | # Note it is important to send the commit statement to at least 2 orgs, because of the default chaincode endorsement lifecyle rule: MAJORITY 222 | 223 | peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID $CHANNEL_NAME --name basic --version 1 --sequence 1 --tls --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:10051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt 224 | 225 | # check the result 226 | peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name basic --cafile $ORDERER_CA 227 | 228 | ``` 229 | 230 | # Use the chaincode 231 | Finally we can use the chaincode. 232 | 233 | ```bash 234 | # first init the chaincode 235 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:10051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt -c '{"function":"Init","Args":["account1","1000","account2","10"]}' 236 | 237 | # query the chaincode 238 | peer chaincode query -C $CHANNEL_NAME -n basic -c '{"function":"Query","Args":["account1"]}' 239 | 240 | # invoke the chaincode from org3 241 | source org3.env 242 | 243 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:10051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt -c '{"function":"Invoke","Args":["account1","account2","100"]}' 244 | 245 | ``` 246 | 247 | # A persistent network 248 | ```bash 249 | # stop the network 250 | docker-compose down 251 | 252 | # start the network in the background 253 | docker-compose up -d 254 | 255 | # show the logs 256 | docker-compose logs -f -t 257 | 258 | # Notice that your system is persistent and you can start the network as long as you not clean up the docker volumes. 259 | docker volume ls 260 | docker volume prune 261 | 262 | # check your containers 263 | ## to see the network 264 | docker-compose ps 265 | 266 | ## to see the chaincode-container as well 267 | docker ps 268 | 269 | ```` 270 | [Index](../README.md) 271 | -------------------------------------------------------------------------------- /meetup-061120/index.md: -------------------------------------------------------------------------------- 1 | # Support Material - external vs internal chaincode (CC) 2 | 3 | ## External CC 4 | ### Package the external CC 5 | ```bash 6 | cd fabric/fabric-samples/asset-transfer-basic/chaincode-external/ 7 | 8 | # Inspect the connection.json file 9 | # Inspect the chaincode.env file 10 | # Inspect the metadata.json file 11 | 12 | tar cfz code.tar.gz connection.json 13 | tar cfz asset-transfer-basic-external.tgz metadata.json code.tar.gz 14 | 15 | # for later useage 16 | cp chaincode.env ../../test-network/ 17 | ``` 18 | 19 | ### Start the network 20 | 21 | Modify the config.core.yaml file (config/core.yaml). 22 | 23 | #### Edit config/core.yaml 24 | ```bash 25 | externalBuilders: 26 | - path: /opt/gopath/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external/sampleBuilder 27 | name: external-sample-builder 28 | ``` 29 | 30 | Modify the docker-compose.yaml file (docker/docker-compose-test-net.yaml). 31 | 32 | #### Edit docker-compose-test-net.yaml 33 | 34 | Add these two volumns by both peers 35 | ```bash 36 | - ../..:/opt/gopath/src/github.com/hyperledger/fabric-samples 37 | - ../../config/core.yaml:/etc/hyperledger/fabric/core.yaml 38 | ``` 39 | 40 | 41 | ```bash 42 | # switch to the target folder 43 | cd ../../test-network 44 | 45 | # start the network 46 | ./network.sh up createChannel -c mychannel 47 | 48 | # load some helper scripts from the samples 49 | . scripts/envVar.sh 50 | 51 | export FABRIC_CFG_PATH=$PWD/../config/ 52 | ``` 53 | 54 | ### Install external CC 55 | ```bash 56 | # install one peer0 Org1 57 | setGlobals 1 58 | peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz 59 | 60 | # install one peer0 Org2 61 | setGlobals 2 62 | peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz 63 | 64 | # check installed chaincode and get PKID 65 | setGlobals 1 66 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 67 | 68 | export PKGID=basic:79c332c70a6a7381ae06eb892daf115afaedf7dca1515270f932072f06681a39 69 | 70 | # edit chaincode.env and change CHAINCODE_ID value to PKID 71 | vi chaincode.env 72 | ``` 73 | 74 | ### Build a new CC container 75 | 76 | ```bash 77 | cd ../asset-transfer-basic/chaincode-external 78 | docker build -t hyperledger/asset-transfer-basic . 79 | ``` 80 | 81 | ### Start the external CC container 82 | ```bash 83 | docker run -d -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode.env --network=net_test hyperledger/asset-transfer-basic 84 | cd ../../test-network/ 85 | ``` 86 | 87 | ### Approve the CC 88 | ```bash 89 | # approve for Org2 90 | setGlobals 2 91 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1 92 | 93 | # approve for Org1 94 | setGlobals 1 95 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1 96 | ``` 97 | 98 | ### Commit the external CC 99 | ```bash 100 | 101 | # check 102 | peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json 103 | 104 | #commit 105 | peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles $PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1.0 --sequence 1 106 | ``` 107 | 108 | ### Use the external CC 109 | It is time to look into the chaincode. 110 | 111 | 112 | ```bash 113 | # call the InitLedger function 114 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}' 115 | 116 | # query an asset 117 | peer chaincode query -C mychannel -n basic -c '{"function":"ReadAsset","Args":["asset1"]}' 118 | 119 | # transfer an asset 120 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset1","roland"]}' 121 | 122 | # call the query again 123 | peer chaincode query -C mychannel -n basic -c '{"function":"ReadAsset","Args":["asset1"]}' 124 | ``` 125 | 126 | ## Internal CC 127 | 128 | ## Install chaincode abstore on mychannel 129 | 130 | ```bash 131 | cd ../chaincode/abstore/go/ 132 | GO111MODULE=on go mod vendor 133 | 134 | cd ../../../test-network/ 135 | peer lifecycle chaincode package abstore.tar.gz --path ../chaincode/abstore/go/ --lang golang --label abstore_1 136 | 137 | # install one peer0 Org1 138 | setGlobals 1 139 | peer lifecycle chaincode install abstore.tar.gz 140 | 141 | # install one peer0 Org2 142 | setGlobals 2 143 | peer lifecycle chaincode install abstore.tar.gz 144 | 145 | 146 | # check installed chaincode and get PKID 147 | setGlobals 1 148 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 149 | 150 | #Installed chaincodes on peer: 151 | #Package ID: basic:524d01db7699b85fa9ba802d8811d39f6b30c93c42afd788464f716ef99aa610, Label: basic 152 | #Package ID: abstore_1:3918d0438fd2ebe48ed1bde01533513a14f788846fd2d72ef054482760e73409, Label: abstore_1 153 | 154 | export PKGID=abstore_1:3918d0438fd2ebe48ed1bde01533513a14f788846fd2d72ef054482760e73409 155 | 156 | # approve for Org1 157 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name abstore --version 1 --package-id $PKGID --sequence 1 158 | 159 | # approve for Org2 160 | setGlobals 2 161 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name abstore --version 1 --package-id $PKGID --sequence 1 162 | 163 | # commit the CC 164 | peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name abstore --peerAddresses localhost:7051 --tlsRootCertFiles $PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1 --sequence 1 165 | ``` 166 | 167 | ### Use the internal CC 168 | 169 | ```bash 170 | # call the invoke 171 | 172 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n abstore --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"Init","Args":["account1","1000","account2","10"]}' 173 | 174 | # query the CC 175 | peer chaincode query -C mychannel -n abstore -c '{"function":"Query","Args":["account1"]}' 176 | peer chaincode query -C mychannel -n abstore -c '{"function":"Query","Args":["account2"]}' 177 | 178 | # invoke the CC 179 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n abstore --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"Invoke","Args":["account1","account2","100"]}' 180 | ``` 181 | 182 | ## Demonstration Google Cloud buildpacks 183 | ### Install Pack 184 | 185 | See https://buildpacks.io/docs/ 186 | 187 | ```bash 188 | # install pack 189 | 190 | (curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.14.2/pack-v0.14.2-linux.tgz" | sudo tar -C /usr/local/bin/ --no-same-owner -xzv pack) 191 | 192 | # modify .bashrc and reload it 193 | . $(pack completion) 194 | 195 | # install go packages 196 | go get -u github.com/buildpacks/pack 197 | ``` 198 | 199 | ### Demo buildpacks 200 | read more https://github.com/GoogleCloudPlatform/buildpacks 201 | 202 | ```bash 203 | # get some samples 204 | cd 205 | mkdir cloudbuilds 206 | cd cloudbuilds 207 | 208 | git clone https://github.com/GoogleCloudPlatform/buildpack-samples.git 209 | pack suggest-builders 210 | 211 | # ------------------------ 212 | # node.js example 213 | # ------------------------ 214 | cd buildpack-samples/sample-node 215 | pack build --builder=gcr.io/buildpacks/builder sample-node 216 | docker run -d -it -ePORT=8080 -p8080:8080 --name sample-node sample-node 217 | curl localhost:8080 218 | 219 | # check running containers 220 | docker ps --format '{{ .ID }}\t{{.Status}}\t{{ .Names }}' 221 | 222 | ## rebase an image 223 | pack rebase sample-node 224 | 225 | # ------------------------ 226 | # Option A, golang example 227 | # ------------------------ 228 | cd buildpack-samples/sample-go 229 | 230 | pack build --builder heroku/buildpacks:18 hello-roland 231 | pack build --builder gcr.io/buildpacks/builder:v1 hello-roland 232 | 233 | docker run --rm -p 4000:8080 hello-roland 234 | curl localhost 4000 235 | 236 | ``` 237 | [Index](../README.md) 238 | -------------------------------------------------------------------------------- /meetup-061120/helper.md: -------------------------------------------------------------------------------- 1 | # How to use the external chaincode launcher - CC as a Service 2 | 3 | ## Install Pack 4 | 5 | ```bash 6 | # install pack 7 | 8 | (curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.14.2/pack-v0.14.2-linux.tgz" | sudo tar -C /usr/local/bin/ --no-same-owner -xzv pack) 9 | 10 | # modify .bashrc and reload it 11 | . $(pack completion) 12 | 13 | # install go packages 14 | go get -u github.com/buildpacks/pack 15 | ``` 16 | 17 | ## First try - buildpacks 18 | read more https://github.com/GoogleCloudPlatform/buildpacks 19 | 20 | ```bash 21 | git clone https://github.com/GoogleCloudPlatform/buildpack-samples.git 22 | cd buildpack-samples/sample-go 23 | pack suggest-builders 24 | 25 | pack build --builder heroku/buildpacks:18 hello-roland 26 | pack build --builder gcr.io/buildpacks/builder:v1 hello-roland 27 | 28 | docker run --rm -p 4000:8080 hello-roland 29 | curl localhost 4000 30 | 31 | # node.js example 32 | cd buildpack-samples/sample-node 33 | pack build --builder gcr.io/buildpacks/builder:v1 web:1 34 | docker run --rm -p 3000:3000 web 35 | 36 | ``` 37 | 38 | # External chancode lancher with TLS 39 | 40 | Edit config/core.yaml file 41 | 42 | ```bash 43 | vi config.core.yaml 44 | 45 | externalBuilders: 46 | - path: /opt/gopath/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external/sampleBuilder 47 | name: external-sample-builder 48 | propagateEnvironment: 49 | - CORE_PEER_TLS_ROOTCERT_FILE 50 | - CORE_PEER_TLS_CERT_FILE 51 | - CORE_PEER_TLS_KEY_FILE 52 | ``` 53 | 54 | Prepare a organization switch file for both organizations. 55 | ```bash 56 | # create a new env file and fill in the following env vars 57 | vi org1.env 58 | 59 | export FABRIC_CFG_PATH=$PWD/../config/ 60 | export CORE_PEER_TLS_ENABLED=true 61 | export CORE_PEER_LOCALMSPID="Org1MSP" 62 | export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 63 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 64 | export CORE_PEER_ADDRESS=localhost:7051 65 | 66 | # execute the env file 67 | source org1.env 68 | ``` 69 | 70 | ```bash 71 | # create a new env file and fill in the following env vars 72 | vi org2.env 73 | 74 | export FABRIC_CFG_PATH=$PWD/../config/ 75 | export CORE_PEER_LOCALMSPID="Org2MSP" 76 | export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 77 | export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 78 | export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 79 | export CORE_PEER_ADDRESS=localhost:9051 80 | 81 | # execute the env file 82 | source org2.env 83 | ``` 84 | 85 | ```bash 86 | # start the network and compose the crypto artefacts 87 | ./network.sh up createChannel -c channel1 88 | 89 | #./monitordocker.sh net_test 90 | # start logging 91 | docker-compose -f docker/docker-compose-test-net.yaml logs -f -t 92 | 93 | # switch to target chaincode folder 94 | cd fabric-samples/asset-transfer-basic/chaincode-external 95 | 96 | # adjust connection.json und add the following 97 | { 98 | "address": "asset-transfer-basic.org1.example.com:9999", 99 | "dial_timeout": "10s", 100 | "tls_required": true, 101 | "client_auth_required": true, 102 | "client_key": "CORE_PEER_TLS_KEY_FILE", 103 | "client_cert": "CORE_PEER_TLS_CERT_FILE", 104 | "root_cert": "CORE_PEER_TLS_ROOTCERT_FILE" 105 | } 106 | 107 | tar cfz code.tar.gz connection.json && tar cfz asset-transfer-basic-external_org1.tgz metadata.json code.tar.gz 108 | 109 | # change the address in connection.json from "address": "asset-transfer-basic.org1.example.com:9999", 110 | # to "address": "asset-transfer-basic.org2.example.com:9998", 111 | 112 | tar cfz code.tar.gz connection.json && tar cfz asset-transfer-basic-external_org2.tgz metadata.json code.tar.gz 113 | 114 | # edit to the sampleBuilder/bin/release file and add the following 115 | # on top a function 116 | function one_line_pem { 117 | echo "`awk 'NF {sub(/\\n/, ""); printf "%s\\\\\\\n",$0;}' $1`" 118 | } 119 | 120 | # and this to replace pem content 121 | #if tls_required is true, copy TLS files (using above example, the fully qualified path for these fils would be "$RELEASE"/chaincode/server/tls) 122 | 123 | CORE_PEER_TLS_KEY_FILE=$(one_line_pem $CORE_PEER_TLS_KEY_FILE) 124 | CORE_PEER_TLS_CERT_FILE=$(one_line_pem $CORE_PEER_TLS_CERT_FILE) 125 | CORE_PEER_TLS_ROOTCERT_FILE=$(one_line_pem $CORE_PEER_TLS_ROOTCERT_FILE) 126 | 127 | sed -i "s|CORE_PEER_TLS_KEY_FILE|$CORE_PEER_TLS_KEY_FILE|g" "$RELEASE"/chaincode/server/connection.json 128 | sed -i "s|CORE_PEER_TLS_CERT_FILE|$CORE_PEER_TLS_CERT_FILE|g" "$RELEASE"/chaincode/server/connection.json 129 | sed -i "s|CORE_PEER_TLS_ROOTCERT_FILE|$CORE_PEER_TLS_ROOTCERT_FILE|g" "$RELEASE"/chaincode/server/connection.json 130 | #-------------------------------------------- 131 | 132 | 133 | # install chaincode on peer0 in org1 134 | source org1.env 135 | peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external_org1.tgz 136 | 137 | # install chaincode on peer0 in org2 138 | source org2.env 139 | peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external_org2.tgz 140 | ``` 141 | 142 | ## Running the asset-transfer-basic external service 143 | 144 | ```bash 145 | # switch to target folder 146 | cd fabric-samples/asset-transfer-basic/chaincode-external 147 | 148 | # build the chaoncode container 149 | docker build -t hyperledger/asset-transfer-basic . 150 | 151 | # start external service 152 | # docker run -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode.env --network=net_test hyperledger/asset-transfer-basic 153 | 154 | vi chaincode_org1.env 155 | # add the following 156 | 157 | # CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can 158 | # connect to the chaincode server 159 | CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org1.example.com:9999 160 | 161 | # CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode 162 | # on install. The `peer lifecycle chaincode queryinstalled` command can be 163 | # used to get the ID after install if required 164 | CHAINCODE_ID=basic:b6ea7a5a8ff256d4bc55e743c3861b9c8e2f8bc36643603b37ac23ab5cbc5efe 165 | 166 | CORE_PEER_TLS_KEY_FILE=/tls/server.key 167 | CORE_PEER_TLS_CERT_FILE=/tls/server.crt 168 | CORE_PEER_TLS_ROOTCERT_FILE=/tls/ca.crt 169 | # --------------------------- 170 | 171 | vi chaincode_org2.env 172 | # add the following 173 | 174 | # CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can 175 | # connect to the chaincode server 176 | CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org2.example.com:9998 177 | 178 | # CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode 179 | # on install. The `peer lifecycle chaincode queryinstalled` command can be 180 | # used to get the ID after install if required 181 | CHAINCODE_ID=basic:693b69a4b1d666a03efc3755c14aa91fff440f73445c143ca63c5214ebc89b20 182 | 183 | CORE_PEER_TLS_KEY_FILE=/tls/server.key 184 | CORE_PEER_TLS_CERT_FILE=/tls/server.crt 185 | CORE_PEER_TLS_ROOTCERT_FILE=/tls/ca.crt 186 | # --------------------------- 187 | 188 | # start external service org1 189 | docker run -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode_org1.env --network=net_test -v /root/fabric/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/:/tls -p 9999:9999 hyperledger/asset-transfer-basic 190 | 191 | # start external service org2 192 | docker run -it --rm --name asset-transfer-basic.org2.example.com --hostname asset-transfer-basic.org2.example.com --env-file chaincode_org2.env --network=net_test -v /root/fabric/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/:/tls -p 9998:9999 hyperledger/asset-transfer-basic 193 | 194 | ``` 195 | 196 | ## Finish deploying the asset-transfer-basic external chaincode 197 | 198 | ### Approve org1 199 | ```bash 200 | source org1.env 201 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 202 | 203 | export CCID=basic:b6ea7a5a8ff256d4bc55e743c3861b9c8e2f8bc36643603b37ac23ab5cbc5efe 204 | 205 | source org1.env 206 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID channel1 --name basic --version 1 --package-id $CCID --sequence 1 207 | ``` 208 | 209 | ### Approve org2 210 | ```bash 211 | source org2.env 212 | peer lifecycle chaincode queryinstalled --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 213 | 214 | export CCID=basic:693b69a4b1d666a03efc3755c14aa91fff440f73445c143ca63c5214ebc89b20 215 | 216 | peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID channel1 --name basic --version 1 --package-id $CCID --sequence 1 217 | 218 | ``` 219 | 220 | ### Check the approve progress 221 | ```bash 222 | # command to copy 223 | peer lifecycle chaincode checkcommitreadiness --channelID channel1 --name basic --version 1 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json 224 | ``` 225 | 226 | 227 | ### Commit the chaincode 228 | ```bash 229 | peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID channel1 --name basic --peerAddresses localhost:7051 --tlsRootCertFiles $PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1 --sequence 1 230 | ``` 231 | 232 | ## Using the asset-transfer-basic external chaincode 233 | 234 | ```bash 235 | # Init the chaincode 236 | source org1.env 237 | 238 | peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}' 239 | 240 | 241 | peer chaincode query -C mychannel -n basic -c '{"function":"ReadAsset","Args":["asset1"]}' 242 | ``` 243 | 244 | ### Some helper 245 | ```bash 246 | awk 'NF {sub(/\r/, ""); printf "%s",$0;}' organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key 247 | 248 | # inspect the peer for the connection.json 249 | docker exec -it peer0.org1.example.com sh 250 | cd /var/hyperledger/production/externalbuilder/builds/ 251 | ``` 252 | -------------------------------------------------------------------------------- /meetup-231020/chaincode/abstore/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/DATA-DOG/go-txdb v0.1.3/go.mod h1:DhAhxMXZpUJVGnT+p9IbzJoRKvlArO2pkHjnGX7o0n0= 4 | github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= 5 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 6 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= 7 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 8 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 9 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 10 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 11 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 12 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 13 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 14 | github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A= 15 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 19 | github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= 20 | github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= 21 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 22 | github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= 23 | github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= 24 | github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= 25 | github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= 26 | github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 27 | github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= 28 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 29 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 30 | github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= 31 | github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= 32 | github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= 33 | github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= 34 | github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= 35 | github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= 36 | github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= 37 | github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= 38 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 39 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 40 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 41 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 42 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 43 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 44 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 45 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 46 | github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212 h1:1i4lnpV8BDgKOLi1hgElfBqdHXjXieSuj8629mwBZ8o= 47 | github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= 48 | github.com/hyperledger/fabric-contract-api-go v1.1.0 h1:K9uucl/6eX3NF0/b+CGIiO1IPm1VYQxBkpnVGJur2S4= 49 | github.com/hyperledger/fabric-contract-api-go v1.1.0/go.mod h1:nHWt0B45fK53owcFpLtAe8DH0Q5P068mnzkNXMPSL7E= 50 | github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 51 | github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e h1:9PS5iezHk/j7XriSlNuSQILyCOfcZ9wZ3/PiucmSE8E= 52 | github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 53 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 54 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= 55 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 56 | github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= 57 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 58 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 59 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 60 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 61 | github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= 62 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 63 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 64 | github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= 65 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 66 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 67 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 68 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 69 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= 70 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 71 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 72 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 73 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 74 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 75 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 76 | github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 77 | github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= 78 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 79 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 80 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 81 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 82 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 83 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 84 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 85 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 86 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 87 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 88 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 89 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 90 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 91 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 92 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 93 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 94 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 95 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 96 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 97 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= 98 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= 99 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= 100 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= 101 | github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= 102 | github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 103 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 104 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 105 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 106 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 107 | golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 108 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 109 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 110 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 111 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 112 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 113 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= 114 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 115 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 116 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 117 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 118 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 119 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 120 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 121 | golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 122 | golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 123 | golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= 124 | golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 125 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 126 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 127 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 128 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 129 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 130 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 131 | golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 132 | golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 133 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 134 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 135 | google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= 136 | google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 137 | google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= 138 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 139 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 140 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 141 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 142 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 143 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 144 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 145 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 146 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 147 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 148 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 149 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -------------------------------------------------------------------------------- /meetup-231020/chaincode/abstore2/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/DATA-DOG/go-txdb v0.1.3/go.mod h1:DhAhxMXZpUJVGnT+p9IbzJoRKvlArO2pkHjnGX7o0n0= 4 | github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= 5 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 6 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= 7 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 8 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 9 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 10 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 11 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 12 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 13 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 14 | github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A= 15 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 19 | github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= 20 | github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= 21 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 22 | github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= 23 | github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= 24 | github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= 25 | github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= 26 | github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 27 | github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= 28 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 29 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 30 | github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= 31 | github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= 32 | github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= 33 | github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= 34 | github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= 35 | github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= 36 | github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= 37 | github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= 38 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 39 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 40 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 41 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 42 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 43 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 44 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 45 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 46 | github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212 h1:1i4lnpV8BDgKOLi1hgElfBqdHXjXieSuj8629mwBZ8o= 47 | github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= 48 | github.com/hyperledger/fabric-contract-api-go v1.1.0 h1:K9uucl/6eX3NF0/b+CGIiO1IPm1VYQxBkpnVGJur2S4= 49 | github.com/hyperledger/fabric-contract-api-go v1.1.0/go.mod h1:nHWt0B45fK53owcFpLtAe8DH0Q5P068mnzkNXMPSL7E= 50 | github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 51 | github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e h1:9PS5iezHk/j7XriSlNuSQILyCOfcZ9wZ3/PiucmSE8E= 52 | github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 53 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 54 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= 55 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 56 | github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= 57 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 58 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 59 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 60 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 61 | github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= 62 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 63 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 64 | github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= 65 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 66 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 67 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 68 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 69 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= 70 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 71 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 72 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 73 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 74 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 75 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 76 | github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 77 | github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= 78 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 79 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 80 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 81 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 82 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 83 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 84 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 85 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 86 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 87 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 88 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 89 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 90 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 91 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 92 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 93 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 94 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 95 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 96 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 97 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= 98 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= 99 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= 100 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= 101 | github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= 102 | github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 103 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 104 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 105 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 106 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 107 | golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 108 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 109 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 110 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 111 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 112 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 113 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= 114 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 115 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 116 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 117 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 118 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 119 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 120 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 121 | golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 122 | golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 123 | golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= 124 | golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 125 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 126 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 127 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 128 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 129 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 130 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 131 | golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 132 | golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 133 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 134 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 135 | google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= 136 | google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 137 | google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= 138 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 139 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 140 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 141 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 142 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 143 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 144 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 145 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 146 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 147 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 148 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 149 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= --------------------------------------------------------------------------------