Finish sidedb feature

pull/124/head
Baohua Yang 2018-08-27 10:52:46 +08:00
parent 78a440936b
commit beb7610d52
66 changed files with 150330 additions and 245746 deletions

View File

@ -173,6 +173,14 @@ test_fetch_blocks: # test fetching channel blocks fetch
@echo "Test fetching block files"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/test_fetch_blocks.sh"
test_eventsclient: # test get event notification in a loop
@echo "Test fetching event notification"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/start_eventsclient.sh"
test_sidedb: # test sideDB/private data feature
@echo "Test sideDB"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/test_sideDB.sh"
temp: # test temp instructions, used for experiment
@echo "Test experimental instructions"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/test_temp.sh"

View File

@ -178,6 +178,7 @@ services:
- ./solo/channel-artifacts:/tmp/channel-artifacts
- ./examples:/opt/gopath/src/examples
#deprecated
event-listener:
extends:
file: base.yaml
@ -190,13 +191,13 @@ services:
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.Org1.example.com/msp
volumes:
- ./scripts:/tmp/scripts
- ./crypto-config.yaml:/etc/hyperledger/fabric/crypto-config.yaml
- ./crypto-config:/etc/hyperledger/fabric/crypto-config
- ./solo/channel-artifacts:/tmp/channel-artifacts
- ./solo/configtx.yaml:/etc/hyperledger/fabric/configtx.yaml
- ./examples:/opt/gopath/src/github.com/hyperledger/fabric/examples
- ./solo/channel-artifacts:/tmp/channel-artifacts
- ./examples:/opt/gopath/src/examples
command: bash -c 'while true; do sleep 1; block-listener -events-address=peer0.org1.example.com:7053 -events-mspdir=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp/ -events-mspid=Org1MSP; done'
#command: bash -c 'while true; do sleep 20170504; done'

View File

@ -75,14 +75,12 @@ services:
- CORE_CHIANCODE_LOGGING_FORMAT=%{color}[%{id:03x} %{time:01-02 15:04:05.00 MST}] [%{longpkg}] %{callpath} -> %{level:.4s}%{color:reset} %{message}
volumes:
- $GOPATH/src/github.com/hyperledger/fabric:/go/src/github.com/hyperledger/fabric
# docker.sock is mapped as the default CORE_VM_ENDPOINT
- /var/run/docker.sock:/var/run/docker.sock
expose:
- "7051" # Grpc
- "7052" # Peer CLI
- "7053" # Peer Event
volumes: # docker.sock is mapped as the default CORE_VM_ENDPOINT
- /var/run/docker.sock:/var/run/docker.sock
#volumes:
# - /var/run/:/host/var/run/
#command: bash -c 'bash /tmp/peer_build.sh; peer node start'
command: peer node start
@ -98,6 +96,7 @@ services:
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: bash -c 'cd /tmp; source scripts/func.sh; while true; do sleep 20170504; done'
#deprecated
event-listener-base:
image: yeasy/hyperledger-fabric:latest
restart: always

View File

@ -4,7 +4,7 @@
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
"requiredPeerCount": 0,
"maxPeerCount": 3,
"blockToLive":1000000
"blockToLive":99999
},
{
"name": "collectionMarblePrivateDetails",

View File

@ -0,0 +1,16 @@
[
{
"name": "collectionMarbles",
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
"requiredPeerCount": 0,
"maxPeerCount": 3,
"blockToLive":99999
},
{
"name": "collectionMarblePrivateDetails",
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
"requiredPeerCount": 0,
"maxPeerCount": 3,
"blockToLive":99999
}
]

View File

@ -43,7 +43,7 @@ done
# docker pull yeasy/hyperledger-fabric
echo "=== Pulling fabric images ${FABRIC_IMG_TAG} from fabric repo... ==="
for IMG in peer tools orderer ca ccenv couchdb kafka zookeeper; do
for IMG in peer tools orderer ca ccenv tools couchdb kafka zookeeper; do
HLF_IMG=hyperledger/fabric-${IMG}:$ARCH-$FABRIC_IMG_TAG
pull_image $HLF_IMG
done

View File

@ -22,3 +22,5 @@ install_docker_compose() {
command -v "docker" >/dev/null 2>&1 && echo "Docker already installed" || install_docker
command -v "docker-compose" >/dev/null 2>&1 && echo "Docker-Compose already installed" || install_docker_compose
command -v "jq" >/dev/null 2>&1 && echo "jq already installed" || sudo apt-get install jq

View File

@ -386,7 +386,7 @@ chaincodeInstall () {
# chaincodeInstantiate channel org peer name version args
chaincodeInstantiate () {
if [ "$#" -gt 8 -a "$#" -lt 6 ]; then
echo "Wrong param number for chaincode instantaite"
echo_r "Wrong param number for chaincode instantaite"
exit -1
fi
local channel=$1
@ -405,6 +405,7 @@ chaincodeInstantiate () {
if [ ! -z "$8" ]; then
policy=$8
fi
setEnvs $org $peer
echo "=== chaincodeInstantiate for channel ${channel} on org $org/peer $peer ===="
echo "name=${name}, version=${version}, args=${args}, collection_config=${collection_config}, policy=${policy}"
@ -546,15 +547,21 @@ chaincodeStartDev () {
# chaincodeUpgrade channel peer name version args
chaincodeUpgrade () {
if [ "$#" -gt 8 -a "$#" -lt 6 ]; then
echo_r "Wrong param number for chaincode instantaite"
exit -1
fi
local channel=$1
local org=$2
local peer=$3
local name=$4
local version=$5
local args=$6
[ -z $channel ] && [ -z $org ] && [ -z $peer ] && [ -z $name ] && [ -z $version ] && [ -z $args ] && echo_r "input param invalid" && exit -1
local collection_config="" # collection config file path for sideDB
local policy="OR ('Org1MSP.member','Org2MSP.member')" # endorsement policy
echo "=== chaincodeUpgrade to orderer by id of org ${org}/peer $peer === "
echo "channel=${channel}, name=${name}, args=${args}"
echo "name=${name}, version=${version}, args=${args}, collection_config=${collection_config}, policy=${policy}"
setEnvs $org $peer
# while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
@ -566,6 +573,8 @@ chaincodeUpgrade () {
-n ${name} \
-v ${version} \
-c ${args} \
-P "${policy}" \
--collections-config "${collection_config}" \
>&log.txt
else
peer chaincode upgrade \
@ -574,6 +583,8 @@ chaincodeUpgrade () {
-n ${name} \
-v ${version} \
-c ${args} \
-P "${policy}" \
--collections-config "${collection_config}" \
--tls \
--cafile ${ORDERER_TLS_CA} \
>&log.txt

View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
# This script will start the eventsclient
# Importing useful functions
if [ -f ./func.sh ]; then
source ./func.sh
elif [ -f scripts/func.sh ]; then
source scripts/func.sh
fi
echo_g "=== Testing eventsclient in a loop ==="
CORE_PEER_LOCALMSPID=${ORG1MSP} \
CORE_PEER_MSPCONFIGPATH=${ORG1_ADMIN_MSP} \
eventsclient \
-server=${ORG1_PEER0_URL} \
-channelID=${APP_CHANNEL} \
-filtered=true \
-tls=true \
-clientKey=${ORG1_ADMIN_TLS_CLIENT_KEY} \
-clientCert=${ORG1_ADMIN_TLS_CLIENT_CERT} \
-rootCert=${ORG1_ADMIN_TLS_CA_CERT}

View File

@ -18,9 +18,6 @@ do
for peer in "${PEERS[@]}"
do
chaincodeInstall $org $peer ${CC_NAME} ${CC_INIT_VERSION} ${CC_PATH}
# test for sideDB feature
chaincodeInstall $org $peer ${CC_MARBLES_NAME} ${CC_INIT_VERSION} ${CC_MARBLES_PATH}
done
done

View File

@ -18,9 +18,6 @@ echo_b "=== Instantiating chaincode on channel ${APP_CHANNEL}... ==="
chaincodeInstantiate "${APP_CHANNEL}" 1 0 ${CC_NAME} ${CC_INIT_VERSION} ${CC_INIT_ARGS}
#chaincodeInstantiate "${APP_CHANNEL}" 2 0 ${CC_NAME} ${CC_INIT_VERSION} ${CC_INIT_ARGS}
# test sideDB feature
chaincodeInstantiate "${APP_CHANNEL}" 1 0 ${CC_MARBLES_NAME} ${CC_INIT_VERSION} ${CC_MARBLES_INIT_ARGS} ${CC_MARBLES_COLLECTION_CONFIG}
echo_g "=== Instantiate chaincode on channel ${APP_CHANNEL} done ==="
echo

View File

@ -34,20 +34,4 @@ chaincodeInvoke ${APP_CHANNEL} 2 1 ${CC_NAME} ${CC_INVOKE_ARGS}
echo_b "Query chaincode on org1/peer0 4peers..."
chaincodeQuery ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_QUERY_ARGS} 80
# sideDB testing
# both org1 and org2 can invoke, but gossip is the problem to cross org
echo_b "Invoke chaincode with collection on org1/peer0"
chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS}
# both org1 and org2 can do normal read
echo_b "Query chaincode with collection collectionMarbles on org1/peer1"
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
# only org1 can do detailed read
echo_b "Query chaincode with collection collectionMarblePrivateDetails on org1/peer1"
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS}
echo_g "=== Chaincode invoke/query completed ==="
echo

View File

@ -0,0 +1,72 @@
#!/bin/bash
# test sideDB feature: https://jira.hyperledger.org/browse/FAB-10231
# Importing useful functions for cc testing
if [ -f ./func.sh ]; then
source ./func.sh
elif [ -f scripts/func.sh ]; then
source scripts/func.sh
fi
## Install chaincode on all peers
CC_NAME=${CC_MARBLES_NAME}
CC_PATH=${CC_MARBLES_PATH}
CC_INIT_ARGS=${CC_MARBLES_INIT_ARGS}
echo_b "=== Testing the private data feature ==="
echo_b "=== Installing chaincode ${CC_NAME} on all 4 peers... ==="
for org in "${ORGS[@]}"
do
for peer in "${PEERS[@]}"
do
chaincodeInstall $org $peer ${CC_NAME} ${CC_INIT_VERSION} ${CC_PATH}
done
done
echo_g "=== Install chaincode done ==="
# test sideDB feature
chaincodeInstantiate "${APP_CHANNEL}" 1 0 ${CC_NAME} ${CC_INIT_VERSION} ${CC_INIT_ARGS} ${CC_MARBLES_COLLECTION_CONFIG}
echo_g "=== Instantiate chaincode done ==="
sleep 2
# both org1 and org2 can invoke, but gossip is the problem to cross org
echo_b "Invoke chaincode with collection on org1/peer0"
chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS}
echo_g "=== Invoke chaincode done ==="
# both org1 and org2 can do normal read
echo_b "Query chaincode with collection collectionMarbles on org1/peer1"
chaincodeQuery ${APP_CHANNEL} 2 0 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
echo_g "=== Query read chaincode done ==="
# only org1 can do detailed read
echo_b "Query chaincode with collection collectionMarblePrivateDetails on org1/peer1"
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS}
echo_g "=== Query read details chaincode done ==="
echo_b "Install chaincode with new collection config"
for org in "${ORGS[@]}"
do
for peer in "${PEERS[@]}"
do
chaincodeInstall $org $peer ${CC_NAME} ${CC_UPGRADE_VERSION} ${CC_PATH}
done
done
echo_g "Install chaincode with new collection config done"
echo_b "Update chaincode with new collection on org1/peer0"
chaincodeUpgrade ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_UPGRADE_VERSION} ${CC_INIT_ARGS} ${CC_MARBLES_COLLECTION_CONFIG_NEW}
echo_g "Update chaincode with new collection on org1/peer0 done"
echo_b "Invoke chaincode with new key and new collection on org1/peer0"
chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS_2}
echo_g "=== Invoke chaincode done ==="
# now both org1 and org2 should be able to readpvtdetails of new data, noticed the read of old data is available since v1.3.0
echo_b "Query chaincode with new key and new collection collectionMarblePrivateDetails on org1/peer1"
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS_2}
echo_g "=== Query read details chaincode done ==="
echo_g "=== Testing the private data feature done ==="

View File

@ -12,12 +12,31 @@ fi
#chaincodeInstantiate "${APP_CHANNEL}" 1 0 ${CC_MARBLES_NAME} ${CC_INIT_VERSION} ${CC_MARBLES_INIT_ARGS} ${CC_MARBLES_COLLECTION_CONFIG}
# both org1 and org2 can invoke
chaincodeInvoke ${APP_CHANNEL} 2 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS}
#chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS}
#chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS}
#chaincodeQuery ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS}
#chaincodeQuery ${APP_CHANNEL} 2 0 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
chaincodeQuery ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS_2}
exit
chaincodeQuery ${APP_CHANNEL} 2 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
exit
chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_INVOKE_ARGS}
exit
#chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_INVOKE_ARGS}
chaincodeQuery ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
# both org1 and org2 can do normal read
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
#chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
# only org1 can do detailed read
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS}
#chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS}
echo

View File

@ -16,23 +16,28 @@ PEERS=( 0 1 )
#: "${ORGS:=( 1 2 )}"
#: "${PEERS:=( 0 1 )}"
# MSP related paths
ORDERER_TLS_CA=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
ORDERER_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp
ORG1MSP="Org1MSP"
ORG2MSP="Org2MSP"
ORG3MSP="Org3MSP"
# MSP related paths
ORDERER_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp
ORDERER_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp
ORG1_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
ORG1_PEER0_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.Org1.example.com/msp
ORG2_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
# cert related path
ORDERER_TLS_CA=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
ORDERER_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt
ORG1_PEER0_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
ORG1_PEER1_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
ORG1_ADMIN_TLS_CLIENT_KEY=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/client.key
ORG1_ADMIN_TLS_CLIENT_CERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/client.crt
ORG1_ADMIN_TLS_CA_CERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/ca.crt
ORG2_PEER0_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
ORG2_PEER1_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
ORDERER_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp
ORG1_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
ORG2_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
ORG1MSP=Org1MSP
ORG2MSP=Org2MSP
ORG3MSP=Org3MSP
# Node URLS
ORDERER_URL="orderer.example.com:7050"
ORG1_PEER0_URL="peer0.org1.example.com:7051"
@ -61,10 +66,14 @@ CC_MARBLES_NAME="marblesp"
CC_MARBLES_PATH="examples/chaincode/go/marbles02_private/go"
CC_MARBLES_INIT_ARGS='{"Args":["init"]}'
CC_MARBLES_UPGRADE_ARGS='{"Args":["upgrade",""]}'
CC_MARBLES_INVOKE_INIT_ARGS='{"Args":["initMarble","marble1","blue","35","tom","99"]}' # price is in collectionMarblePrivateDetails
CC_MARBLES_INVOKE_INIT_ARGS='{"Args":["initMarble","marble1","blue","10","tom","100"]}' # price is in collectionMarblePrivateDetails
CC_MARBLES_INVOKE_INIT_ARGS_2='{"Args":["initMarble","marble2","blue","10","tom","100"]}' # price is in collectionMarblePrivateDetails
CC_MARBLES_INVOKE_TRANSFER_ARGS='{"Args":["transferMarble","marble1","jerry"]}' # price is in collectionMarblePrivateDetails
CC_MARBLES_QUERY_READ_ARGS='{"Args":["readMarble","marble1"]}' # this requires 'collectionMarbles' collection
CC_MARBLES_QUERY_READPVTDETAILS_ARGS='{"Args":["readMarblePrivateDetails","marble1"]}' # this requires 'collectionMarblePrivateDetails' collection
CC_MARBLES_QUERY_READPVTDETAILS_ARGS_2='{"Args":["readMarblePrivateDetails","marble2"]}' # this requires 'collectionMarblePrivateDetails' collection
CC_MARBLES_COLLECTION_CONFIG="/go/src/examples/chaincode/go/marbles02_private/collections_config.json"
CC_MARBLES_COLLECTION_CONFIG_NEW="/go/src/examples/chaincode/go/marbles02_private/collections_config_new.json"
# unique chaincode params
CC_NAME=${CC_02_NAME}

View File

@ -556,14 +556,13 @@
},
"ChannelRestrictions": {
"mod_policy": "Admins",
"value": {
"max_count": "0"
},
"value": null,
"version": "0"
},
"ConsensusType": {
"mod_policy": "Admins",
"value": {
"metadata": null,
"type": "solo"
},
"version": "0"
@ -686,22 +685,7 @@
"values": {
"MSP": {
"mod_policy": "",
"value": {
"config": {
"admins": [],
"crypto_config": null,
"fabric_node_ous": null,
"intermediate_certs": [],
"name": "",
"organizational_unit_identifiers": [],
"revocation_list": [],
"root_certs": [],
"signing_identity": null,
"tls_intermediate_certs": [],
"tls_root_certs": []
},
"type": 0
},
"value": null,
"version": "0"
}
},
@ -758,22 +742,7 @@
},
"MSP": {
"mod_policy": "",
"value": {
"config": {
"admins": [],
"crypto_config": null,
"fabric_node_ous": null,
"intermediate_certs": [],
"name": "",
"organizational_unit_identifiers": [],
"revocation_list": [],
"root_certs": [],
"signing_identity": null,
"tls_intermediate_certs": [],
"tls_root_certs": []
},
"type": 0
},
"value": null,
"version": "0"
}
},
@ -794,13 +763,13 @@
},
"signatures": [
{
"signature": "MEUCIQD6+6sk1nvO6ImCuhdQSgGFnPCaXEaNH6hoVGK68sulIwIgUz4Jezgfj7nfRuZfY9w6/W3I2VZNxsO94AUYYNIbMro=",
"signature": "MEUCIQDMbr2yIB2j6V2rjnFMX33MyBd4SkXT17ibWo6LGRfF8AIgGUiu1zdLGWOd7adU9yYExoNptbqA7UB/Z5KQraxkGdo=",
"signature_header": {
"creator": {
"id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNLekNDQWRHZ0F3SUJBZ0lSQUxubTYxMDlHNnhqQUNYTXN4VTkvZW93Q2dZSUtvWkl6ajBFQXdJd2N6RUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhHVEFYQmdOVkJBb1RFRzl5WnpJdVpYaGhiWEJzWlM1amIyMHhIREFhQmdOVkJBTVRFMk5oCkxtOXlaekl1WlhoaGJYQnNaUzVqYjIwd0hoY05NVGd3TmpJeU1ETXlNakk0V2hjTk1qZ3dOakU1TURNeU1qSTQKV2pCc01Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQk1LUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnhNTgpVMkZ1SUVaeVlXNWphWE5qYnpFUE1BMEdBMVVFQ3hNR1kyeHBaVzUwTVI4d0hRWURWUVFEREJaQlpHMXBia0J2CmNtY3lMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWEV4OXFIcHkKby9hamFESStNRzc0TXVMcDVoL0c0QXh0THN5YnlNeXFTT1VCcjRpdWJZcllZUHFUQlVVS2xKdGNnSmc0Q0l1Zgp0TkRmb0V2b2ZVNHpMcU5OTUVzd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEClZSMGpCQ1F3SW9BZ3I0K0g4VzlpRmhxTXAraFBuSEJCMVo4RE1OazRjeFpnT1liK2N5NmVYNG93Q2dZSUtvWkkKemowRUF3SURTQUF3UlFJaEFLZE5ZdVJUU3FPeTAxbXBsU1dJZXkzT20wd3dCL0UrdWhLK3BXSXdFdUZqQWlBVgpUcFZYYXEzQlU5TEszai9sblU1VkZKeHV3aHdhMU9MNHBZT0xMTkZtK1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"mspid": "Org2MSP"
},
"nonce": "QqO3Kx3RM2efPD3VEA9a7lAsLW4jr81L"
"nonce": "P3DVBXJ+RqKLlWDLeFHx0YAvaiksh6t9"
}
}
]
@ -810,7 +779,7 @@
"channel_id": "businesschannel",
"epoch": "0",
"extension": null,
"timestamp": "2018-08-22T08:15:29Z",
"timestamp": "2018-08-23T13:46:08Z",
"tls_cert_hash": null,
"tx_id": "",
"type": 2,
@ -821,11 +790,11 @@
"id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNLekNDQWRHZ0F3SUJBZ0lSQUxubTYxMDlHNnhqQUNYTXN4VTkvZW93Q2dZSUtvWkl6ajBFQXdJd2N6RUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhHVEFYQmdOVkJBb1RFRzl5WnpJdVpYaGhiWEJzWlM1amIyMHhIREFhQmdOVkJBTVRFMk5oCkxtOXlaekl1WlhoaGJYQnNaUzVqYjIwd0hoY05NVGd3TmpJeU1ETXlNakk0V2hjTk1qZ3dOakU1TURNeU1qSTQKV2pCc01Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQk1LUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnhNTgpVMkZ1SUVaeVlXNWphWE5qYnpFUE1BMEdBMVVFQ3hNR1kyeHBaVzUwTVI4d0hRWURWUVFEREJaQlpHMXBia0J2CmNtY3lMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWEV4OXFIcHkKby9hamFESStNRzc0TXVMcDVoL0c0QXh0THN5YnlNeXFTT1VCcjRpdWJZcllZUHFUQlVVS2xKdGNnSmc0Q0l1Zgp0TkRmb0V2b2ZVNHpMcU5OTUVzd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEClZSMGpCQ1F3SW9BZ3I0K0g4VzlpRmhxTXAraFBuSEJCMVo4RE1OazRjeFpnT1liK2N5NmVYNG93Q2dZSUtvWkkKemowRUF3SURTQUF3UlFJaEFLZE5ZdVJUU3FPeTAxbXBsU1dJZXkzT20wd3dCL0UrdWhLK3BXSXdFdUZqQWlBVgpUcFZYYXEzQlU5TEszai9sblU1VkZKeHV3aHdhMU9MNHBZT0xMTkZtK1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"mspid": "Org2MSP"
},
"nonce": "GvM5UJnt+6Y+czQEQ+SKwmmUd77n0g5d"
"nonce": "2VrS+qDl7ufIKtwHBCAKIScvH73sY5UY"
}
}
},
"signature": "MEQCIA/EDQEiUSxOFctPEtpbptyGH4VjyLSgf2firrabnfSZAiAO8+ZMKe3ahdcd80dZgO8aa4Rec32X2L3ixwX2VPn1gg=="
"signature": "MEQCIHk3uzdda/kl1S4Wrm88YxGI/Xqgj4UXCGuE92j72EQoAiByNIOgyuY5r9SHnelCps/Th8g3ICZ2ed83MoHo3stiWA=="
}
},
"header": {
@ -833,7 +802,7 @@
"channel_id": "businesschannel",
"epoch": "0",
"extension": null,
"timestamp": "2018-08-22T08:15:29Z",
"timestamp": "2018-08-23T13:46:08Z",
"tls_cert_hash": null,
"tx_id": "",
"type": 1,
@ -844,23 +813,23 @@
"id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNERENDQWJPZ0F3SUJBZ0lSQUsvRHNMajlMa2xoSk1PTmRPQndPVG93Q2dZSUtvWkl6ajBFQXdJd2FURUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhGREFTQmdOVkJBb1RDMlY0WVcxd2JHVXVZMjl0TVJjd0ZRWURWUVFERXc1allTNWxlR0Z0CmNHeGxMbU52YlRBZUZ3MHhPREEyTWpJd016SXlNamhhRncweU9EQTJNVGt3TXpJeU1qaGFNRmd4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxVFlXNGdSbkpoYm1OcApjMk52TVJ3d0dnWURWUVFERXhOdmNtUmxjbVZ5TG1WNFlXMXdiR1V1WTI5dE1Ga3dFd1lIS29aSXpqMENBUVlJCktvWkl6ajBEQVFjRFFnQUVxdFI1OHd6NnpYemtBeTRtMmZySmo5ZWtQVWVhdHJuQnVzM01YeklhN0FYRXdOS0MKUFdhRXdYUm54dmpLM2wybS81b3dMQmphMmV6VDQ0djN3K3BBb2FOTk1Fc3dEZ1lEVlIwUEFRSC9CQVFEQWdlQQpNQXdHQTFVZEV3RUIvd1FDTUFBd0t3WURWUjBqQkNRd0lvQWdVUUh2aGNUa2M1TU93TTdNTVVpRVNRMU56WlZNCnkrKzdpNkhPS0xXcUhKUXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdiTG5pZGhKTTY1T2orcXVsakpjenlMeWMKUWpwRVhNVHZjVnJIU0NCWTB4b0NJQzV4ZTVwOW1wKy95ejE2RHNPajR2ZzBYaTRTRDAySTBLSGorcldhbllpWQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"mspid": "OrdererMSP"
},
"nonce": "pYOsCGagwuD0Kaf4t84WTja7NHj2RJSK"
"nonce": "d09pHP/X/CiunSheZ1DKxOa9kzomKwwG"
}
}
},
"signature": "MEUCIQCJFXqotH8aUOCa60SX+zszDH7K7Z2zRpIrrbhlLVjiJgIgXgwHHrtgRNEVp72jKGxGecFplAsW+RBvoFvQLTmojeU="
"signature": "MEUCIQCPTqNbs3kO5RHVJspXn2OCtM21JQaj6Cib2vu7NB474QIgUVChAqe7Gn8Lr4KD39E46fky5PTx9e+zR+XeeyIV8yc="
}
]
},
"header": {
"data_hash": "J3VDIpQWi/Muf8AlIWsFpzhyqrLq+6msRK1BbrbvCvg=",
"data_hash": "gEOrHlN/Rmp8aHKj/6iS4CqOt7KekYVIz1yYjdPYH7g=",
"number": "2",
"previous_hash": "2cl/mlirmKL0vnG8Xgi297s2+XM9fIsbfCtakVrdhSU="
"previous_hash": "c+F7YWqb2UDX9NGHusvNxq5XZBORCOrXAsIN7VfodT4="
},
"metadata": {
"metadata": [
"EvgGCq0GCpAGCgpPcmRlcmVyTVNQEoEGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNERENDQWJPZ0F3SUJBZ0lSQUsvRHNMajlMa2xoSk1PTmRPQndPVG93Q2dZSUtvWkl6ajBFQXdJd2FURUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhGREFTQmdOVkJBb1RDMlY0WVcxd2JHVXVZMjl0TVJjd0ZRWURWUVFERXc1allTNWxlR0Z0CmNHeGxMbU52YlRBZUZ3MHhPREEyTWpJd016SXlNamhhRncweU9EQTJNVGt3TXpJeU1qaGFNRmd4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxVFlXNGdSbkpoYm1OcApjMk52TVJ3d0dnWURWUVFERXhOdmNtUmxjbVZ5TG1WNFlXMXdiR1V1WTI5dE1Ga3dFd1lIS29aSXpqMENBUVlJCktvWkl6ajBEQVFjRFFnQUVxdFI1OHd6NnpYemtBeTRtMmZySmo5ZWtQVWVhdHJuQnVzM01YeklhN0FYRXdOS0MKUFdhRXdYUm54dmpLM2wybS81b3dMQmphMmV6VDQ0djN3K3BBb2FOTk1Fc3dEZ1lEVlIwUEFRSC9CQVFEQWdlQQpNQXdHQTFVZEV3RUIvd1FDTUFBd0t3WURWUjBqQkNRd0lvQWdVUUh2aGNUa2M1TU93TTdNTVVpRVNRMU56WlZNCnkrKzdpNkhPS0xXcUhKUXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdiTG5pZGhKTTY1T2orcXVsakpjenlMeWMKUWpwRVhNVHZjVnJIU0NCWTB4b0NJQzV4ZTVwOW1wKy95ejE2RHNPajR2ZzBYaTRTRDAySTBLSGorcldhbllpWQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChIYQxdPiE1cdfIfReCVPZzwmsml/OL2yJJuEkYwRAIgFDW4czu02Z/49RF1MZKR/xWpT7Rd1RH1lwhzfbQb8NcCIFgtlVulJp5v1K58eJP9SbU0vaC+WP0mrcoyQP6/2ztZ",
"CgIIAhL5BgqtBgqQBgoKT3JkZXJlck1TUBKBBi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDRERDQ0FiT2dBd0lCQWdJUkFLL0RzTGo5TGtsaEpNT05kT0J3T1Rvd0NnWUlLb1pJemowRUF3SXdhVEVMCk1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ1RDa05oYkdsbWIzSnVhV0V4RmpBVUJnTlZCQWNURFZOaGJpQkcKY21GdVkybHpZMjh4RkRBU0JnTlZCQW9UQzJWNFlXMXdiR1V1WTI5dE1SY3dGUVlEVlFRREV3NWpZUzVsZUdGdApjR3hsTG1OdmJUQWVGdzB4T0RBMk1qSXdNekl5TWpoYUZ3MHlPREEyTVRrd016SXlNamhhTUZneEN6QUpCZ05WCkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saE1SWXdGQVlEVlFRSEV3MVRZVzRnUm5KaGJtTnAKYzJOdk1Sd3dHZ1lEVlFRREV4TnZjbVJsY21WeUxtVjRZVzF3YkdVdVkyOXRNRmt3RXdZSEtvWkl6ajBDQVFZSQpLb1pJemowREFRY0RRZ0FFcXRSNTh3ejZ6WHprQXk0bTJmckpqOWVrUFVlYXRybkJ1czNNWHpJYTdBWEV3TktDClBXYUV3WFJueHZqSzNsMm0vNW93TEJqYTJlelQ0NHYzdytwQW9hTk5NRXN3RGdZRFZSMFBBUUgvQkFRREFnZUEKTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEVlIwakJDUXdJb0FnVVFIdmhjVGtjNU1Pd003TU1VaUVTUTFOelpWTQp5Kys3aTZIT0tMV3FISlF3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnYkxuaWRoSk02NU9qK3F1bGpKY3p5THljClFqcEVYTVR2Y1ZySFNDQlkweG9DSUM1eGU1cDltcCsveXoxNkRzT2o0dmcwWGk0U0QwMkkwS0hqK3JXYW5ZaVkKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSGIaPk4dndbqVK3zEQhnA91k0wJ9PCUoCBhJHMEUCIQDV4aBZ5nV1+pcsG/HzwxzKXh/AmcsaX+jQUSTfGYhOfAIgVth8ZCz69iIbg4+vSM7lcOHVSrhoTdPquRKtJMNVDo4=",
"EvgGCq0GCpAGCgpPcmRlcmVyTVNQEoEGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNERENDQWJPZ0F3SUJBZ0lSQUsvRHNMajlMa2xoSk1PTmRPQndPVG93Q2dZSUtvWkl6ajBFQXdJd2FURUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhGREFTQmdOVkJBb1RDMlY0WVcxd2JHVXVZMjl0TVJjd0ZRWURWUVFERXc1allTNWxlR0Z0CmNHeGxMbU52YlRBZUZ3MHhPREEyTWpJd016SXlNamhhRncweU9EQTJNVGt3TXpJeU1qaGFNRmd4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxVFlXNGdSbkpoYm1OcApjMk52TVJ3d0dnWURWUVFERXhOdmNtUmxjbVZ5TG1WNFlXMXdiR1V1WTI5dE1Ga3dFd1lIS29aSXpqMENBUVlJCktvWkl6ajBEQVFjRFFnQUVxdFI1OHd6NnpYemtBeTRtMmZySmo5ZWtQVWVhdHJuQnVzM01YeklhN0FYRXdOS0MKUFdhRXdYUm54dmpLM2wybS81b3dMQmphMmV6VDQ0djN3K3BBb2FOTk1Fc3dEZ1lEVlIwUEFRSC9CQVFEQWdlQQpNQXdHQTFVZEV3RUIvd1FDTUFBd0t3WURWUjBqQkNRd0lvQWdVUUh2aGNUa2M1TU93TTdNTVVpRVNRMU56WlZNCnkrKzdpNkhPS0xXcUhKUXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdiTG5pZGhKTTY1T2orcXVsakpjenlMeWMKUWpwRVhNVHZjVnJIU0NCWTB4b0NJQzV4ZTVwOW1wKy95ejE2RHNPajR2ZzBYaTRTRDAySTBLSGorcldhbllpWQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChIYLndVlh2UcZGLPFe+kUPZKcjAJk/AVRasEkYwRAIgfvmvFbvv9S2ccH9DSoXumthACm581wLSYHR4AIeBYtMCIBgB33uqem/hzBadyI6F7oJ2njMEXkhx5br2jCx6Duvz",
"CgIIAhL5BgqtBgqQBgoKT3JkZXJlck1TUBKBBi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDRERDQ0FiT2dBd0lCQWdJUkFLL0RzTGo5TGtsaEpNT05kT0J3T1Rvd0NnWUlLb1pJemowRUF3SXdhVEVMCk1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ1RDa05oYkdsbWIzSnVhV0V4RmpBVUJnTlZCQWNURFZOaGJpQkcKY21GdVkybHpZMjh4RkRBU0JnTlZCQW9UQzJWNFlXMXdiR1V1WTI5dE1SY3dGUVlEVlFRREV3NWpZUzVsZUdGdApjR3hsTG1OdmJUQWVGdzB4T0RBMk1qSXdNekl5TWpoYUZ3MHlPREEyTVRrd016SXlNamhhTUZneEN6QUpCZ05WCkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saE1SWXdGQVlEVlFRSEV3MVRZVzRnUm5KaGJtTnAKYzJOdk1Sd3dHZ1lEVlFRREV4TnZjbVJsY21WeUxtVjRZVzF3YkdVdVkyOXRNRmt3RXdZSEtvWkl6ajBDQVFZSQpLb1pJemowREFRY0RRZ0FFcXRSNTh3ejZ6WHprQXk0bTJmckpqOWVrUFVlYXRybkJ1czNNWHpJYTdBWEV3TktDClBXYUV3WFJueHZqSzNsMm0vNW93TEJqYTJlelQ0NHYzdytwQW9hTk5NRXN3RGdZRFZSMFBBUUgvQkFRREFnZUEKTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEVlIwakJDUXdJb0FnVVFIdmhjVGtjNU1Pd003TU1VaUVTUTFOelpWTQp5Kys3aTZIT0tMV3FISlF3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnYkxuaWRoSk02NU9qK3F1bGpKY3p5THljClFqcEVYTVR2Y1ZySFNDQlkweG9DSUM1eGU1cDltcCsveXoxNkRzT2o0dmcwWGk0U0QwMkkwS0hqK3JXYW5ZaVkKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSGFjqoYj7C0YvTMLIkg+wz/IwBeZ9ulMvthJHMEUCIQCbwJusBA+1cQFrMfugBpH9A8mnjDE4v2XVM3ECKgkfHgIgXqjysnqV7D9Dc1lxvYStsSy9IoeyUl93029d86op038=",
"",
""
]

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -173,6 +173,18 @@ test_fetch_blocks: # test fetching channel blocks fetch
@echo "Test fetching block files"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/test_fetch_blocks.sh"
test_eventsclient: # test get event notification in a loop
@echo "Test fetching event notification"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/start_eventsclient.sh"
test_sidedb: # test sideDB/private data feature
@echo "Test sideDB"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/test_sideDB.sh"
temp: # test temp instructions, used for experiment
@echo "Test experimental instructions"
@docker exec -it fabric-cli bash -c "cd /tmp; bash scripts/test_temp.sh"
################## Env setup related, no need to see usually ################
setup: # setup the environment
@ -221,6 +233,9 @@ logs_save: # save logs
logs_view: # view logs
less $(LOG_PATH)/dev_peer.log
elk: # insert logs into elk
# curl -XDELETE http://localhost:9200/logstash-\*
nc localhost 5000 < $(LOG_PATH)/dev_all.log
gen_config: # generate config artifacts
if [ "$(HLF_MODE)" = "kafka" ]; then \
bash scripts/gen_config.sh kafka; \

View File

@ -190,13 +190,13 @@ services:
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.Org1.example.com/msp
volumes:
- ./scripts:/tmp/scripts
- ./crypto-config.yaml:/etc/hyperledger/fabric/crypto-config.yaml
- ./crypto-config:/etc/hyperledger/fabric/crypto-config
- ./solo/channel-artifacts:/tmp/channel-artifacts
- ./solo/configtx.yaml:/etc/hyperledger/fabric/configtx.yaml
- ./examples:/opt/gopath/src/github.com/hyperledger/fabric/examples
- ./solo/channel-artifacts:/tmp/channel-artifacts
- ./examples:/opt/gopath/src/examples
command: bash -c 'while true; do sleep 1; block-listener -events-address=peer0.org1.example.com:7053 -events-mspdir=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp/ -events-mspid=Org1MSP; done'
#command: bash -c 'while true; do sleep 20170504; done'

View File

@ -64,7 +64,8 @@ services:
- CORE_LOGGING_FORMAT=%{color}[%{id:03x} %{time:01-02 15:04:05.00 MST}] [%{longpkg}] %{callpath} -> %{level:.4s}%{color:reset} %{message}
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=v120_default # uncomment this to use specific network
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false # whether this node is the group leader, default to false
- CORE_PEER_GOSSIP_ORGLEADER=false # whether this node is the org leader, default to false
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=0.0.0.0:7051 # external addr for peers in other orgs
- CORE_PEER_PROFILE_ENABLED=false
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt

View File

@ -0,0 +1,16 @@
[
{
"name": "collectionMarbles",
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
"requiredPeerCount": 0,
"maxPeerCount": 3,
"blockToLive":99999
},
{
"name": "collectionMarblePrivateDetails",
"policy": "OR('Org1MSP.member')",
"requiredPeerCount": 0,
"maxPeerCount": 3,
"blockToLive":3
}
]

View File

@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}

View File

@ -0,0 +1,634 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
// ====CHAINCODE EXECUTION SAMPLES (CLI) ==================
// ==== Invoke marbles ====
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble","marble1","blue","35","tom","99"]}'
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble","marble2","red","50","tom","102"]}'
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble","marble3","blue","70","tom","103"]}'
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["transferMarble","marble2","jerry"]}'
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["delete","marble1"]}'
// ==== Query marbles ====
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarble","marble1"]}'
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["getMarblesByRange","marble1","marble3"]}'
// Rich Query (Only supported if CouchDB is used as state database):
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["queryMarblesByOwner","tom"]}'
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}'
// INDEXES TO SUPPORT COUCHDB RICH QUERIES
//
// Indexes in CouchDB are required in order to make JSON queries efficient and are required for
// any JSON query with a sort. As of Hyperledger Fabric 1.1, indexes may be packaged alongside
// chaincode in a META-INF/statedb/couchdb/indexes directory. Or for indexes on private data
// collections, in a META-INF/statedb/couchdb/collections/<collection_name>/indexes directory.
// Each index must be defined in its own text file with extension *.json with the index
// definition formatted in JSON following the CouchDB index JSON syntax as documented at:
// http://docs.couchdb.org/en/2.1.1/api/database/find.html#db-index
//
// This marbles02_private example chaincode demonstrates a packaged index which you
// can find in META-INF/statedb/couchdb/collection/collectionMarbles/indexes/indexOwner.json.
// For deployment of chaincode to production environments, it is recommended
// to define any indexes alongside chaincode so that the chaincode and supporting indexes
// are deployed automatically as a unit, once the chaincode has been installed on a peer and
// instantiated on a channel. See Hyperledger Fabric documentation for more details.
//
// If you have access to the your peer's CouchDB state database in a development environment,
// you may want to iteratively test various indexes in support of your chaincode queries. You
// can use the CouchDB Fauxton interface or a command line curl utility to create and update
// indexes. Then once you finalize an index, include the index definition alongside your
// chaincode in the META-INF/statedb/couchdb/indexes directory or
// META-INF/statedb/couchdb/collections/<collection_name>/indexes directory, for packaging
// and deployment to managed environments.
//
// In the examples below you can find index definitions that support marbles02_private
// chaincode queries, along with the syntax that you can use in development environments
// to create the indexes in the CouchDB Fauxton interface.
//
//Example hostname:port configurations to access CouchDB.
//
//To access CouchDB docker container from within another docker container or from vagrant environments:
// http://couchdb:5984/
//
//Inside couchdb docker container
// http://127.0.0.1:5984/
// Index for docType, owner.
// Note that docType and owner fields must be prefixed with the "data" wrapper
//
// Index definition for use with Fauxton interface
// {"index":{"fields":["data.docType","data.owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
// Index for docType, owner, size (descending order).
// Note that docType, owner and size fields must be prefixed with the "data" wrapper
//
// Index definition for use with Fauxton interface
// {"index":{"fields":[{"data.size":"desc"},{"data.docType":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortDesc","type":"json"}
// Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database):
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}'
// Rich Query with index design doc specified only (Only supported if CouchDB is used as state database):
// peer chaincode query -C mychannel -n marblesp -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":{\"$eq\":\"marble\"},\"owner\":{\"$eq\":\"tom\"},\"size\":{\"$gt\":0}},\"fields\":[\"docType\",\"owner\",\"size\"],\"sort\":[{\"size\":\"desc\"}],\"use_index\":\"_design/indexSizeSortDoc\"}"]}'
package main
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}
type marble struct {
ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database
Name string `json:"name"` //the fieldtags are needed to keep case from bouncing around
Color string `json:"color"`
Size int `json:"size"`
Owner string `json:"owner"`
}
type marblePrivateDetails struct {
ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database
Name string `json:"name"` //the fieldtags are needed to keep case from bouncing around
Price int `json:"price"`
}
// ===================================================================================
// Main
// ===================================================================================
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
// Init initializes chaincode
// ===========================
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success(nil)
}
// Invoke - Our entry point for Invocations
// ========================================
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
fmt.Println("invoke is running " + function)
// Handle different functions
switch function {
case "initMarble":
//create a new marble
return t.initMarble(stub, args)
case "readMarble":
//read a marble
return t.readMarble(stub, args)
case "readMarblePrivateDetails":
//read a marble private details
return t.readMarblePrivateDetails(stub, args)
case "transferMarble":
//change owner of a specific marble
return t.transferMarble(stub, args)
case "transferMarblesBasedOnColor":
//transfer all marbles of a certain color
return t.transferMarblesBasedOnColor(stub, args)
case "delete":
//delete a marble
return t.delete(stub, args)
case "queryMarblesByOwner":
//find marbles for owner X using rich query
return t.queryMarblesByOwner(stub, args)
case "queryMarbles":
//find marbles based on an ad hoc rich query
return t.queryMarbles(stub, args)
case "getMarblesByRange":
//get marbles based on range query
return t.getMarblesByRange(stub, args)
default:
//error
fmt.Println("invoke did not find func: " + function)
return shim.Error("Received unknown function invocation")
}
}
// ============================================================
// initMarble - create a new marble, store into chaincode state
// ============================================================
func (t *SimpleChaincode) initMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var err error
// 0-name 1-color 2-size 3-owner 4-price
// "asdf", "blue", "35", "bob", "99"
if len(args) != 5 {
return shim.Error("Incorrect number of arguments. Expecting 5")
}
// ==== Input sanitation ====
fmt.Println("- start init marble")
if len(args[0]) == 0 {
return shim.Error("1st argument must be a non-empty string")
}
if len(args[1]) == 0 {
return shim.Error("2nd argument must be a non-empty string")
}
if len(args[2]) == 0 {
return shim.Error("3rd argument must be a non-empty string")
}
if len(args[3]) == 0 {
return shim.Error("4th argument must be a non-empty string")
}
if len(args[4]) == 0 {
return shim.Error("5th argument must be a non-empty string")
}
marbleName := args[0]
color := strings.ToLower(args[1])
owner := strings.ToLower(args[3])
size, err := strconv.Atoi(args[2])
if err != nil {
return shim.Error("3rd argument must be a numeric string")
}
price, err := strconv.Atoi(args[4])
if err != nil {
return shim.Error("5th argument must be a numeric string")
}
// ==== Check if marble already exists ====
marbleAsBytes, err := stub.GetPrivateData("collectionMarbles", marbleName)
if err != nil {
return shim.Error("Failed to get marble: " + err.Error())
} else if marbleAsBytes != nil {
fmt.Println("This marble already exists: " + marbleName)
return shim.Error("This marble already exists: " + marbleName)
}
// ==== Create marble object and marshal to JSON ====
objectType := "marble"
marble := &marble{objectType, marbleName, color, size, owner}
marbleJSONasBytes, err := json.Marshal(marble)
if err != nil {
return shim.Error(err.Error())
}
//Alternatively, build the marble json string manually if you don't want to use struct marshalling
//marbleJSONasString := `{"docType":"Marble", "name": "` + marbleName + `", "color": "` + color + `", "size": ` + strconv.Itoa(size) + `, "owner": "` + owner + `"}`
//marbleJSONasBytes := []byte(str)
// === Save marble to state ===
err = stub.PutPrivateData("collectionMarbles", marbleName, marbleJSONasBytes)
if err != nil {
return shim.Error(err.Error())
}
// ==== Save marble private details ====
objectType = "marblePrivateDetails"
marblePrivateDetails := &marblePrivateDetails{objectType, marbleName, price}
marblePrivateDetailsBytes, err := json.Marshal(marblePrivateDetails)
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutPrivateData("collectionMarblePrivateDetails", marbleName, marblePrivateDetailsBytes)
if err != nil {
return shim.Error(err.Error())
}
// ==== Index the marble to enable color-based range queries, e.g. return all blue marbles ====
// An 'index' is a normal key/value entry in state.
// The key is a composite key, with the elements that you want to range query on listed first.
// In our case, the composite key is based on indexName~color~name.
// This will enable very efficient state range queries based on composite keys matching indexName~color~*
indexName := "color~name"
colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marble.Color, marble.Name})
if err != nil {
return shim.Error(err.Error())
}
// Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble.
// Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value
value := []byte{0x00}
stub.PutPrivateData("collectionMarbles", colorNameIndexKey, value)
// ==== Marble saved and indexed. Return success ====
fmt.Println("- end init marble")
return shim.Success(nil)
}
// ===============================================
// readMarble - read a marble from chaincode state
// ===============================================
func (t *SimpleChaincode) readMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var name, jsonResp string
var err error
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting name of the marble to query")
}
name = args[0]
valAsbytes, err := stub.GetPrivateData("collectionMarbles", name) //get the marble from chaincode state
if err != nil {
jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}"
return shim.Error(jsonResp)
} else if valAsbytes == nil {
jsonResp = "{\"Error\":\"Marble does not exist: " + name + "\"}"
return shim.Error(jsonResp)
}
return shim.Success(valAsbytes)
}
// ===============================================
// readMarblereadMarblePrivateDetails - read a marble private details from chaincode state
// ===============================================
func (t *SimpleChaincode) readMarblePrivateDetails(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var name, jsonResp string
var err error
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting name of the marble to query")
}
name = args[0]
valAsbytes, err := stub.GetPrivateData("collectionMarblePrivateDetails", name) //get the marble private details from chaincode state
if err != nil {
jsonResp = "{\"Error\":\"Failed to get private details for " + name + ": " + err.Error() + "\"}"
return shim.Error(jsonResp)
} else if valAsbytes == nil {
jsonResp = "{\"Error\":\"Marble private details does not exist: " + name + "\"}"
return shim.Error(jsonResp)
}
return shim.Success(valAsbytes)
}
// ==================================================
// delete - remove a marble key/value pair from state
// ==================================================
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var jsonResp string
var marbleJSON marble
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
marbleName := args[0]
// to maintain the color~name index, we need to read the marble first and get its color
valAsbytes, err := stub.GetPrivateData("collectionMarbles", marbleName) //get the marble from chaincode state
if err != nil {
jsonResp = "{\"Error\":\"Failed to get state for " + marbleName + "\"}"
return shim.Error(jsonResp)
} else if valAsbytes == nil {
jsonResp = "{\"Error\":\"Marble does not exist: " + marbleName + "\"}"
return shim.Error(jsonResp)
}
err = json.Unmarshal([]byte(valAsbytes), &marbleJSON)
if err != nil {
jsonResp = "{\"Error\":\"Failed to decode JSON of: " + marbleName + "\"}"
return shim.Error(jsonResp)
}
err = stub.DelPrivateData("collectionMarbles", marbleName) //remove the marble from chaincode state
if err != nil {
return shim.Error("Failed to delete state:" + err.Error())
}
// maintain the index
indexName := "color~name"
colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marbleJSON.Color, marbleJSON.Name})
if err != nil {
return shim.Error(err.Error())
}
// Delete index entry to state.
err = stub.DelPrivateData("collectionMarbles", colorNameIndexKey)
if err != nil {
return shim.Error("Failed to delete state:" + err.Error())
}
// Delete private details of marble
err = stub.DelPrivateData("collectionMarblePrivateDetails", marbleName)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
// ===========================================================
// transfer a marble by setting a new owner name on the marble
// ===========================================================
func (t *SimpleChaincode) transferMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// 0 1
// "name", "bob"
if len(args) < 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
marbleName := args[0]
newOwner := strings.ToLower(args[1])
fmt.Println("- start transferMarble ", marbleName, newOwner)
marbleAsBytes, err := stub.GetPrivateData("collectionMarbles", marbleName)
if err != nil {
return shim.Error("Failed to get marble:" + err.Error())
} else if marbleAsBytes == nil {
return shim.Error("Marble does not exist")
}
marbleToTransfer := marble{}
err = json.Unmarshal(marbleAsBytes, &marbleToTransfer) //unmarshal it aka JSON.parse()
if err != nil {
return shim.Error(err.Error())
}
marbleToTransfer.Owner = newOwner //change the owner
marbleJSONasBytes, _ := json.Marshal(marbleToTransfer)
err = stub.PutPrivateData("collectionMarbles", marbleName, marbleJSONasBytes) //rewrite the marble
if err != nil {
return shim.Error(err.Error())
}
fmt.Println("- end transferMarble (success)")
return shim.Success(nil)
}
// ===========================================================================================
// getMarblesByRange performs a range query based on the start and end keys provided.
// Read-only function results are not typically submitted to ordering. If the read-only
// results are submitted to ordering, or if the query is used in an update transaction
// and submitted to ordering, then the committing peers will re-execute to guarantee that
// result sets are stable between endorsement time and commit time. The transaction is
// invalidated by the committing peers if the result set has changed between endorsement
// time and commit time.
// Therefore, range queries are a safe option for performing update transactions based on query results.
// ===========================================================================================
func (t *SimpleChaincode) getMarblesByRange(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) < 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
startKey := args[0]
endKey := args[1]
resultsIterator, err := stub.GetPrivateDataByRange("collectionMarbles", startKey, endKey)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
// buffer is a JSON array containing QueryResults
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(queryResponse.Key)
buffer.WriteString("\"")
buffer.WriteString(", \"Record\":")
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- getMarblesByRange queryResult:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
// ==== Example: GetStateByPartialCompositeKey/RangeQuery =========================================
// transferMarblesBasedOnColor will transfer marbles of a given color to a certain new owner.
// Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'.
// Committing peers will re-execute range queries to guarantee that result sets are stable
// between endorsement time and commit time. The transaction is invalidated by the
// committing peers if the result set has changed between endorsement time and commit time.
// Therefore, range queries are a safe option for performing update transactions based on query results.
// ===========================================================================================
func (t *SimpleChaincode) transferMarblesBasedOnColor(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// 0 1
// "color", "bob"
if len(args) < 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
color := args[0]
newOwner := strings.ToLower(args[1])
fmt.Println("- start transferMarblesBasedOnColor ", color, newOwner)
// Query the color~name index by color
// This will execute a key range query on all keys starting with 'color'
coloredMarbleResultsIterator, err := stub.GetPrivateDataByPartialCompositeKey("collectionMarbles", "color~name", []string{color})
if err != nil {
return shim.Error(err.Error())
}
defer coloredMarbleResultsIterator.Close()
// Iterate through result set and for each marble found, transfer to newOwner
var i int
for i = 0; coloredMarbleResultsIterator.HasNext(); i++ {
// Note that we don't get the value (2nd return variable), we'll just get the marble name from the composite key
responseRange, err := coloredMarbleResultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// get the color and name from color~name composite key
objectType, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key)
if err != nil {
return shim.Error(err.Error())
}
returnedColor := compositeKeyParts[0]
returnedMarbleName := compositeKeyParts[1]
fmt.Printf("- found a marble from index:%s color:%s name:%s\n", objectType, returnedColor, returnedMarbleName)
// Now call the transfer function for the found marble.
// Re-use the same function that is used to transfer individual marbles
response := t.transferMarble(stub, []string{returnedMarbleName, newOwner})
// if the transfer failed break out of loop and return error
if response.Status != shim.OK {
return shim.Error("Transfer failed: " + response.Message)
}
}
responsePayload := fmt.Sprintf("Transferred %d %s marbles to %s", i, color, newOwner)
fmt.Println("- end transferMarblesBasedOnColor: " + responsePayload)
return shim.Success([]byte(responsePayload))
}
// =======Rich queries =========================================================================
// Two examples of rich queries are provided below (parameterized query and ad hoc query).
// Rich queries pass a query string to the state database.
// Rich queries are only supported by state database implementations
// that support rich query (e.g. CouchDB).
// The query string is in the syntax of the underlying state database.
// With rich queries there is no guarantee that the result set hasn't changed between
// endorsement time and commit time, aka 'phantom reads'.
// Therefore, rich queries should not be used in update transactions, unless the
// application handles the possibility of result set changes between endorsement and commit time.
// Rich queries can be used for point-in-time queries against a peer.
// ============================================================================================
// ===== Example: Parameterized rich query =================================================
// queryMarblesByOwner queries for marbles based on a passed in owner.
// This is an example of a parameterized query where the query logic is baked into the chaincode,
// and accepting a single query parameter (owner).
// Only available on state databases that support rich query (e.g. CouchDB)
// =========================================================================================
func (t *SimpleChaincode) queryMarblesByOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// 0
// "bob"
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
owner := strings.ToLower(args[0])
queryString := fmt.Sprintf("{\"selector\":{\"docType\":\"marble\",\"owner\":\"%s\"}}", owner)
queryResults, err := getQueryResultForQueryString(stub, queryString)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(queryResults)
}
// ===== Example: Ad hoc rich query ========================================================
// queryMarbles uses a query string to perform a query for marbles.
// Query string matching state database syntax is passed in and executed as is.
// Supports ad hoc queries that can be defined at runtime by the client.
// If this is not desired, follow the queryMarblesForOwner example for parameterized queries.
// Only available on state databases that support rich query (e.g. CouchDB)
// =========================================================================================
func (t *SimpleChaincode) queryMarbles(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// 0
// "queryString"
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
queryString := args[0]
queryResults, err := getQueryResultForQueryString(stub, queryString)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(queryResults)
}
// =========================================================================================
// getQueryResultForQueryString executes the passed in query string.
// Result set is built and returned as a byte array containing the JSON results.
// =========================================================================================
func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) {
fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString)
resultsIterator, err := stub.GetPrivateDataQueryResult("collectionMarbles", queryString)
if err != nil {
return nil, err
}
defer resultsIterator.Close()
// buffer is a JSON array containing QueryRecords
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(queryResponse.Key)
buffer.WriteString("\"")
buffer.WriteString(", \"Record\":")
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String())
return buffer.Bytes(), nil
}

View File

@ -46,12 +46,14 @@ setOrdererEnvs () {
# Set global env variables for fabric cli, after setting:
# client is the admin as given org
# TLS root cert is configured to given peer's
# TLS root cert is configured to given peer's tls ca
# remote peer address is configured to given peer's
# CORE_PEER_LOCALMSPID=Org1MSP
# CORE_PEER_ADDRESS=peer0.org1.example.com:7051
# CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
# CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
# CORE_PEER_LOCALMSPID=Org1MSP # local msp id to use
# CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp # local msp path to use
# CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt # local trusted tls ca cert
# CORE_PEER_ADDRESS=peer0.org1.example.com:7051 # remote peer to send proposal to
# Usage: setEnvs org peer
setEnvs () {
local org=$1 # 1 or 2
@ -366,7 +368,8 @@ chaincodeInstall () {
local version=$4
local path=$5
[ -z $org ] && [ -z $peer ] && [ -z $name ] && [ -z $version ] && [ -z $path ] && echo_r "input param invalid" && exit -1
echo "=== Install Chaincode $name:$version ($path) on org ${org}/peer $peer === "
echo "=== Install Chaincode on org ${org}/peer ${peer} === "
echo "name=${name}, version=${version}, path=${path}"
setEnvs $org $peer
peer chaincode install \
-n ${name} \
@ -382,15 +385,29 @@ chaincodeInstall () {
# Instantiate chaincode on specifized peer node
# chaincodeInstantiate channel org peer name version args
chaincodeInstantiate () {
if [ "$#" -gt 8 -a "$#" -lt 6 ]; then
echo "Wrong param number for chaincode instantaite"
exit -1
fi
local channel=$1
local org=$2
local peer=$3
local name=$4
local version=$5
local args=$6
[ -z $channel ] && [ -z $org ] && [ -z $peer ] && [ -z $name ] && [ -z $version ] && [ -z $args ] && echo_r "input param invalid" && exit -1
local collection_config="" # collection config file path for sideDB
local policy="OR ('Org1MSP.member','Org2MSP.member')" # endorsement policy
if [ ! -z "$7" ]; then
collection_config=$7
fi
if [ ! -z "$8" ]; then
policy=$8
fi
setEnvs $org $peer
echo "=== chaincodeInstantiate for channel ${channel} on org $org/peer $peer ===="
echo "name=${name}, version=${version}, args=${args}, collection_config=${collection_config}, policy=${policy}"
# while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
# lets supply it directly as we know it using the "-o" option
if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
@ -400,7 +417,8 @@ chaincodeInstantiate () {
-n ${name} \
-v ${version} \
-c ${args} \
-P "OR ('Org1MSP.member','Org2MSP.member')" \
-P "${policy}" \
--collections-config "${collection_config}" \
>&log.txt
else
peer chaincode instantiate \
@ -409,7 +427,8 @@ chaincodeInstantiate () {
-n ${name} \
-v ${version} \
-c ${args} \
-P "OR ('Org1MSP.member','Org2MSP.member')" \
-P "${policy}" \
--collections-config "${collection_config}" \
--tls \
--cafile ${ORDERER_TLS_CA} \
>&log.txt
@ -429,7 +448,8 @@ chaincodeInvoke () {
local name=$4
local args=$5
[ -z $channel ] && [ -z $org ] && [ -z $peer ] && [ -z $name ] && [ -z $args ] && echo_r "input param invalid" && exit -1
echo "=== Invoke transaction on peer$peer in channel ${channel} === "
echo "=== chaincodeInvoke to orderer by id of org${org}/peer${peer} === "
echo "channel=${channel}, name=${name}, args=${args}"
setEnvs $org $peer
# while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
# lets supply it directly as we know it using the "-o" option
@ -465,7 +485,8 @@ chaincodeQuery () {
local args=$5
[ -z $channel ] && [ -z $org ] && [ -z $peer ] && [ -z $name ] && [ -z $args ] && echo_r "input param invalid" && exit -1
[ $# -gt 5 ] && local expected_result=$6
echo "=== Querying on org $org/peer $peer in channel ${channel}... === "
echo "=== chaincodeQuery to org $org/peer $peer === "
echo "channel=${channel}, name=${name}, args=${args}"
local rc=1
local starttime=$(date +%s)
@ -487,6 +508,8 @@ chaincodeQuery () {
let rc=1
echo_b "$VALUE != ${expected_result}, will retry"
fi
else
cat log.txt
fi
if [ $rc -ne 0 ]; then
cat log.txt
@ -496,9 +519,9 @@ chaincodeQuery () {
# rc==0, or timeout
if [ $rc -eq 0 ]; then
echo "=== Query on peer$peer in channel ${channel} is successful === "
echo "=== Query on org $org/peer$peer in channel ${channel} is successful === "
else
echo_r "=== Query result on peer$peer is INVALID, run `make stop clean` to clean ==="
echo_r "=== Query on org $org/peer$peer is INVALID, run `make stop clean` to clean ==="
exit 1
fi
}
@ -530,7 +553,8 @@ chaincodeUpgrade () {
local version=$5
local args=$6
[ -z $channel ] && [ -z $org ] && [ -z $peer ] && [ -z $name ] && [ -z $version ] && [ -z $args ] && echo_r "input param invalid" && exit -1
echo "=== Upgrade chaincode to version $version on org ${org}/peer $peer in channel ${channel} === "
echo "=== chaincodeUpgrade to orderer by id of org ${org}/peer $peer === "
echo "channel=${channel}, name=${name}, args=${args}"
setEnvs $org $peer
# while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),

View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
# This script will start the eventsclient
# Importing useful functions
if [ -f ./func.sh ]; then
source ./func.sh
elif [ -f scripts/func.sh ]; then
source scripts/func.sh
fi
echo_g "=== Testing eventsclient in a loop ==="
CORE_PEER_LOCALMSPID=${ORG1MSP} \
CORE_PEER_MSPCONFIGPATH=${ORG1_ADMIN_MSP} \
eventsclient \
-server=${ORG1_PEER0_URL} \
-channelID=${APP_CHANNEL} \
-filtered=true \
-tls=true \
-clientKey=${ORG1_ADMIN_TLS_CLIENT_KEY} \
-clientCert=${ORG1_ADMIN_TLS_CLIENT_CERT} \
-rootCert=${ORG1_ADMIN_TLS_CA_CERT}

View File

@ -14,8 +14,9 @@ CC_INIT_ARGS=${CC_INIT_ARGS:-$CC_02_INIT_ARGS}
# (once for each channel is enough, we make it concurrent here)
echo_b "=== Instantiating chaincode on channel ${APP_CHANNEL}... ==="
# Instantiate at org1.peer0 and org2.peer0, actually it can be triggered once per channel
chaincodeInstantiate "${APP_CHANNEL}" 1 0 ${CC_NAME} ${CC_INIT_VERSION} ${CC_INIT_ARGS}
chaincodeInstantiate "${APP_CHANNEL}" 2 0 ${CC_NAME} ${CC_INIT_VERSION} ${CC_INIT_ARGS}
#chaincodeInstantiate "${APP_CHANNEL}" 2 0 ${CC_NAME} ${CC_INIT_VERSION} ${CC_INIT_ARGS}
echo_g "=== Instantiate chaincode on channel ${APP_CHANNEL} done ==="

View File

@ -14,27 +14,24 @@ CC_QUERY_ARGS=${CC_QUERY_ARGS:-$CC_02_QUERY_ARGS}
#Query on chaincode on Peer0/Org1
echo_g "=== Testing Chaincode invoke/query ==="
echo_b "Querying chaincode ${CC_NAME} on peer org2/peer0..."
# Non-side-DB testing
echo_b "Query chaincode ${CC_NAME} on peer org2/peer0..."
chaincodeQuery ${APP_CHANNEL} 2 1 ${CC_NAME} ${CC_QUERY_ARGS} 100
#Invoke on chaincode on Peer0/Org1
echo_b "Sending invoke transaction (transfer 10) representing org1/peer0..."
echo_b "Invoke transaction (transfer 10) by org1/peer0..."
chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_INVOKE_ARGS}
#Query on chaincode on Peer1/Org2, check if the result is 90
echo_b "Querying chaincode on peer 1 and 3..."
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_NAME} ${CC_QUERY_ARGS} 90
echo_b "Query chaincode on org2/peer1..."
chaincodeQuery ${APP_CHANNEL} 2 1 ${CC_NAME} ${CC_QUERY_ARGS} 90
#Invoke on chaincode on Peer1/Org2
echo_b "Sending invoke transaction on org2/peer3..."
echo_b "Send invoke transaction on org2/peer1..."
chaincodeInvoke ${APP_CHANNEL} 2 1 ${CC_NAME} ${CC_INVOKE_ARGS}
#Query on chaincode on Peer1/Org2, check if the result is 80
echo_b "Querying chaincode on all 4peers..."
echo_b "Query chaincode on org1/peer0 4peers..."
chaincodeQuery ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_QUERY_ARGS} 80
chaincodeQuery ${APP_CHANNEL} 2 0 ${CC_NAME} ${CC_QUERY_ARGS} 80
echo_g "=== Chaincode invoke/query completed ==="
echo

View File

@ -0,0 +1,60 @@
#!/bin/bash
# test sideDB feature: https://jira.hyperledger.org/browse/FAB-10231
# Importing useful functions for cc testing
if [ -f ./func.sh ]; then
source ./func.sh
elif [ -f scripts/func.sh ]; then
source scripts/func.sh
fi
## Install chaincode on all peers
CC_NAME=${CC_MARBLES_NAME}
CC_PATH=${CC_MARBLES_PATH}
CC_INIT_ARGS=${CC_MARBLES_INIT_ARGS}
echo_b "=== Installing chaincode ${CC_NAME} on all 4 peers... ==="
for org in "${ORGS[@]}"
do
for peer in "${PEERS[@]}"
do
chaincodeInstall $org $peer ${CC_NAME} ${CC_INIT_VERSION} ${CC_PATH}
done
done
echo_g "=== Install chaincode done ==="
# test sideDB feature
chaincodeInstantiate "${APP_CHANNEL}" 1 0 ${CC_NAME} ${CC_INIT_VERSION} ${CC_INIT_ARGS} ${CC_MARBLES_COLLECTION_CONFIG}
echo_g "=== Instantiate chaincode done ==="
# sideDB testing
# both org1 and org2 can invoke, but gossip is the problem to cross org
echo_b "Invoke chaincode with collection on org1/peer0"
chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS}
echo_g "=== Invoke chaincode done ==="
# both org1 and org2 can do normal read
echo_b "Query chaincode with collection collectionMarbles on org1/peer1"
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
echo_g "=== Query read chaincode done ==="
# only org1 can do detailed read
echo_b "Query chaincode with collection collectionMarblePrivateDetails on org1/peer1"
chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS}
echo_g "=== Query read details chaincode done ==="
echo_b "Update chaincode with new collection config"
for org in "${ORGS[@]}"
do
for peer in "${PEERS[@]}"
do
chaincodeInstall $org $peer ${CC_NAME} ${CC_UPGRADE_VERSION} ${CC_PATH}
done
done
chaincodeUpgrade ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_UPGRADE_VERSION} ${CC_INIT_ARGS} ${CC_MARBLES_COLLECTION_CONFIG_NEW}
echo

View File

@ -0,0 +1,34 @@
#!/bin/bash
# Importing useful functions for cc testing
if [ -f ./func.sh ]; then
source ./func.sh
elif [ -f scripts/func.sh ]; then
source scripts/func.sh
fi
# test sideDB feature
#chaincodeInstantiate "${APP_CHANNEL}" 1 0 ${CC_MARBLES_NAME} ${CC_INIT_VERSION} ${CC_MARBLES_INIT_ARGS} ${CC_MARBLES_COLLECTION_CONFIG}
# both org1 and org2 can invoke
#chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_INVOKE_INIT_ARGS}
chaincodeQuery ${APP_CHANNEL} 2 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
exit
chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_INVOKE_ARGS}
exit
#chaincodeInvoke ${APP_CHANNEL} 1 0 ${CC_NAME} ${CC_INVOKE_ARGS}
chaincodeQuery ${APP_CHANNEL} 1 0 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
# both org1 and org2 can do normal read
#chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READ_ARGS}
# only org1 can do detailed read
#chaincodeQuery ${APP_CHANNEL} 1 1 ${CC_MARBLES_NAME} ${CC_MARBLES_QUERY_READPVTDETAILS_ARGS}
echo

View File

@ -16,23 +16,28 @@ PEERS=( 0 1 )
#: "${ORGS:=( 1 2 )}"
#: "${PEERS:=( 0 1 )}"
# MSP related paths
ORDERER_TLS_CA=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
ORDERER_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp
ORG1MSP="Org1MSP"
ORG2MSP="Org2MSP"
ORG3MSP="Org3MSP"
# MSP related paths
ORDERER_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp
ORDERER_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp
ORG1_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
ORG1_PEER0_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.Org1.example.com/msp
ORG2_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
# cert related path
ORDERER_TLS_CA=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
ORDERER_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt
ORG1_PEER0_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
ORG1_PEER1_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
ORG1_ADMIN_TLS_CLIENT_KEY=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/client.key
ORG1_ADMIN_TLS_CLIENT_CERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/client.crt
ORG1_ADMIN_TLS_CA_CERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/ca.crt
ORG2_PEER0_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
ORG2_PEER1_TLS_ROOTCERT=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
ORDERER_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp
ORG1_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
ORG2_ADMIN_MSP=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
ORG1MSP=Org1MSP
ORG2MSP=Org2MSP
ORG3MSP=Org3MSP
# Node URLS
ORDERER_URL="orderer.example.com:7050"
ORG1_PEER0_URL="peer0.org1.example.com:7051"
@ -56,6 +61,18 @@ CC_MAP_UPGRADE_ARGS='{"Args":["upgrade",""]}'
CC_MAP_INVOKE_ARGS='{"Args":["invoke","put","key","value"]}'
CC_MAP_QUERY_ARGS='{"Args":["get","key"]}'
# Chaincode marbles related
CC_MARBLES_NAME="marblesp"
CC_MARBLES_PATH="examples/chaincode/go/marbles02_private/go"
CC_MARBLES_INIT_ARGS='{"Args":["init"]}'
CC_MARBLES_UPGRADE_ARGS='{"Args":["upgrade",""]}'
CC_MARBLES_INVOKE_INIT_ARGS='{"Args":["initMarble","marble1","blue","10","tom","100"]}' # price is in collectionMarblePrivateDetails
CC_MARBLES_INVOKE_TRANSFER_ARGS='{"Args":["transferMarble","marble1","jerry"]}' # price is in collectionMarblePrivateDetails
CC_MARBLES_QUERY_READ_ARGS='{"Args":["readMarble","marble1"]}' # this requires 'collectionMarbles' collection
CC_MARBLES_QUERY_READPVTDETAILS_ARGS='{"Args":["readMarblePrivateDetails","marble1"]}' # this requires 'collectionMarblePrivateDetails' collection
CC_MARBLES_COLLECTION_CONFIG="/go/src/examples/chaincode/go/marbles02_private/collections_config.json"
CC_MARBLES_COLLECTION_CONFIG_NEW="/go/src/examples/chaincode/go/marbles02_private/collections_config_new.json"
# unique chaincode params
CC_NAME=${CC_02_NAME}
CC_PATH=${CC_02_PATH}

View File

@ -723,13 +723,13 @@
},
"signatures": [
{
"signature": "MEUCIQCk7iQxlkvbjS9FPzjGktfJaZEVN7Ygbx207ZLeGbgXPwIgDNEmTIviGIYF1rKKlGwnll5vxVaK37pU+DDf1Imf8ks=",
"signature": "MEUCIQDuNmIqggw8AjkrrsXe0iyjiraE3yPbYmIxSRtkM0l2pAIgHL1BLNSWwR2oaBav34TBi1snwB7tKUmcBrznhdf8Ack=",
"signature_header": {
"creator": {
"id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNLekNDQWRHZ0F3SUJBZ0lSQUxubTYxMDlHNnhqQUNYTXN4VTkvZW93Q2dZSUtvWkl6ajBFQXdJd2N6RUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhHVEFYQmdOVkJBb1RFRzl5WnpJdVpYaGhiWEJzWlM1amIyMHhIREFhQmdOVkJBTVRFMk5oCkxtOXlaekl1WlhoaGJYQnNaUzVqYjIwd0hoY05NVGd3TmpJeU1ETXlNakk0V2hjTk1qZ3dOakU1TURNeU1qSTQKV2pCc01Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQk1LUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnhNTgpVMkZ1SUVaeVlXNWphWE5qYnpFUE1BMEdBMVVFQ3hNR1kyeHBaVzUwTVI4d0hRWURWUVFEREJaQlpHMXBia0J2CmNtY3lMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWEV4OXFIcHkKby9hamFESStNRzc0TXVMcDVoL0c0QXh0THN5YnlNeXFTT1VCcjRpdWJZcllZUHFUQlVVS2xKdGNnSmc0Q0l1Zgp0TkRmb0V2b2ZVNHpMcU5OTUVzd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEClZSMGpCQ1F3SW9BZ3I0K0g4VzlpRmhxTXAraFBuSEJCMVo4RE1OazRjeFpnT1liK2N5NmVYNG93Q2dZSUtvWkkKemowRUF3SURTQUF3UlFJaEFLZE5ZdVJUU3FPeTAxbXBsU1dJZXkzT20wd3dCL0UrdWhLK3BXSXdFdUZqQWlBVgpUcFZYYXEzQlU5TEszai9sblU1VkZKeHV3aHdhMU9MNHBZT0xMTkZtK1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"mspid": "Org2MSP"
},
"nonce": "bgSKgyQC4IKa+WaXnbZCfiNnAVOyIR/y"
"nonce": "ne/SsoLxWJlmS/5RjbO0EyZpCEjJzDtD"
}
}
]
@ -738,7 +738,7 @@
"channel_header": {
"channel_id": "businesschannel",
"epoch": "0",
"timestamp": "2018-08-21T02:29:14.000Z",
"timestamp": "2018-08-23T07:11:58.000Z",
"tx_id": "",
"type": 2,
"version": 0
@ -748,18 +748,18 @@
"id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNLekNDQWRHZ0F3SUJBZ0lSQUxubTYxMDlHNnhqQUNYTXN4VTkvZW93Q2dZSUtvWkl6ajBFQXdJd2N6RUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhHVEFYQmdOVkJBb1RFRzl5WnpJdVpYaGhiWEJzWlM1amIyMHhIREFhQmdOVkJBTVRFMk5oCkxtOXlaekl1WlhoaGJYQnNaUzVqYjIwd0hoY05NVGd3TmpJeU1ETXlNakk0V2hjTk1qZ3dOakU1TURNeU1qSTQKV2pCc01Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQk1LUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnhNTgpVMkZ1SUVaeVlXNWphWE5qYnpFUE1BMEdBMVVFQ3hNR1kyeHBaVzUwTVI4d0hRWURWUVFEREJaQlpHMXBia0J2CmNtY3lMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWEV4OXFIcHkKby9hamFESStNRzc0TXVMcDVoL0c0QXh0THN5YnlNeXFTT1VCcjRpdWJZcllZUHFUQlVVS2xKdGNnSmc0Q0l1Zgp0TkRmb0V2b2ZVNHpMcU5OTUVzd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEClZSMGpCQ1F3SW9BZ3I0K0g4VzlpRmhxTXAraFBuSEJCMVo4RE1OazRjeFpnT1liK2N5NmVYNG93Q2dZSUtvWkkKemowRUF3SURTQUF3UlFJaEFLZE5ZdVJUU3FPeTAxbXBsU1dJZXkzT20wd3dCL0UrdWhLK3BXSXdFdUZqQWlBVgpUcFZYYXEzQlU5TEszai9sblU1VkZKeHV3aHdhMU9MNHBZT0xMTkZtK1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"mspid": "Org2MSP"
},
"nonce": "6kBztZTDO4DrK6+CjJtkv1HDiMw1A6kU"
"nonce": "0nTGPcwHoG/gjt2Ek6IgpGz/P3YaWVjr"
}
}
},
"signature": "MEQCIBhbIhOkL61lq5uNndmVdocv5d1DGpz2NLAEMMHpWO1dAiBKO3kOSgVHO1YvsOm7HKh8NbUJsTMJvHOXrWqzOPQ/hw=="
"signature": "MEUCIQDeHuFpcNeNuKGA4z2saSim5n8LloC5RUl9yijurd6SggIgKtiHDZBO5QvCSwzdFCOw0jj/tCCzRbbIOsSmBDfnupQ="
}
},
"header": {
"channel_header": {
"channel_id": "businesschannel",
"epoch": "0",
"timestamp": "2018-08-21T02:29:14.000Z",
"timestamp": "2018-08-23T07:11:59.000Z",
"tx_id": "",
"type": 1,
"version": 0
@ -769,23 +769,23 @@
"id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNERENDQWJPZ0F3SUJBZ0lSQUsvRHNMajlMa2xoSk1PTmRPQndPVG93Q2dZSUtvWkl6ajBFQXdJd2FURUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhGREFTQmdOVkJBb1RDMlY0WVcxd2JHVXVZMjl0TVJjd0ZRWURWUVFERXc1allTNWxlR0Z0CmNHeGxMbU52YlRBZUZ3MHhPREEyTWpJd016SXlNamhhRncweU9EQTJNVGt3TXpJeU1qaGFNRmd4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxVFlXNGdSbkpoYm1OcApjMk52TVJ3d0dnWURWUVFERXhOdmNtUmxjbVZ5TG1WNFlXMXdiR1V1WTI5dE1Ga3dFd1lIS29aSXpqMENBUVlJCktvWkl6ajBEQVFjRFFnQUVxdFI1OHd6NnpYemtBeTRtMmZySmo5ZWtQVWVhdHJuQnVzM01YeklhN0FYRXdOS0MKUFdhRXdYUm54dmpLM2wybS81b3dMQmphMmV6VDQ0djN3K3BBb2FOTk1Fc3dEZ1lEVlIwUEFRSC9CQVFEQWdlQQpNQXdHQTFVZEV3RUIvd1FDTUFBd0t3WURWUjBqQkNRd0lvQWdVUUh2aGNUa2M1TU93TTdNTVVpRVNRMU56WlZNCnkrKzdpNkhPS0xXcUhKUXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdiTG5pZGhKTTY1T2orcXVsakpjenlMeWMKUWpwRVhNVHZjVnJIU0NCWTB4b0NJQzV4ZTVwOW1wKy95ejE2RHNPajR2ZzBYaTRTRDAySTBLSGorcldhbllpWQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"mspid": "OrdererMSP"
},
"nonce": "uE5F/9yenxH9pOcUpsxJnt+4yYyJGMU/"
"nonce": "TV1XmKw3eEyErMf662uUg+nzGrgRJxvt"
}
}
},
"signature": "MEUCIQChL9p5PwsXF8Z/2Gv+yvf15qizFK2gyMj/XiAyFQIZHgIgLvkY5i/T+Gp2GbIndl/AbEQHT+GWL/XqFMYWn/bRGLM="
"signature": "MEUCIQDIOVKHnO8+eZ9sz3y/qlDGLykc2hbzd3bIso00yZFnqQIgYQfl+nGA/A3HEY67YvcFzeNP5UjQfXcW4wu1h4NCz5s="
}
]
},
"header": {
"data_hash": "07Q1mCAvVfnPcogJDgPJoSfD7gy5/G79PxqvCXTzQw8=",
"data_hash": "eJEoGaLC/otWYapt5Yw3SrgvG0tecxR8YJAzB+Pitvc=",
"number": "2",
"previous_hash": "Ac2CBLzq6lh3ZeKKdsjj4gLQ2Weypx7LqiL8CaXg2m4="
"previous_hash": "MQYPFHlV+oNkC61ZmkNOITPD6kdrPQf8RpIpIaOcmYg="
},
"metadata": {
"metadata": [
"EvgGCq0GCpAGCgpPcmRlcmVyTVNQEoEGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNERENDQWJPZ0F3SUJBZ0lSQUsvRHNMajlMa2xoSk1PTmRPQndPVG93Q2dZSUtvWkl6ajBFQXdJd2FURUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhGREFTQmdOVkJBb1RDMlY0WVcxd2JHVXVZMjl0TVJjd0ZRWURWUVFERXc1allTNWxlR0Z0CmNHeGxMbU52YlRBZUZ3MHhPREEyTWpJd016SXlNamhhRncweU9EQTJNVGt3TXpJeU1qaGFNRmd4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxVFlXNGdSbkpoYm1OcApjMk52TVJ3d0dnWURWUVFERXhOdmNtUmxjbVZ5TG1WNFlXMXdiR1V1WTI5dE1Ga3dFd1lIS29aSXpqMENBUVlJCktvWkl6ajBEQVFjRFFnQUVxdFI1OHd6NnpYemtBeTRtMmZySmo5ZWtQVWVhdHJuQnVzM01YeklhN0FYRXdOS0MKUFdhRXdYUm54dmpLM2wybS81b3dMQmphMmV6VDQ0djN3K3BBb2FOTk1Fc3dEZ1lEVlIwUEFRSC9CQVFEQWdlQQpNQXdHQTFVZEV3RUIvd1FDTUFBd0t3WURWUjBqQkNRd0lvQWdVUUh2aGNUa2M1TU93TTdNTVVpRVNRMU56WlZNCnkrKzdpNkhPS0xXcUhKUXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdiTG5pZGhKTTY1T2orcXVsakpjenlMeWMKUWpwRVhNVHZjVnJIU0NCWTB4b0NJQzV4ZTVwOW1wKy95ejE2RHNPajR2ZzBYaTRTRDAySTBLSGorcldhbllpWQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChIYvNXh8oSmqB9G2Bmajd3lsQBN1iUQOcSAEkYwRAIgGAiEoFIjrCq7I828dff0z2CJOKSnYeG4jEEjHEmA3u0CIH+bkkraQHUJxwNYta7SdSsJ7G4e0l+h2v5qJ9aX2HGr",
"CgIIAhL5BgqtBgqQBgoKT3JkZXJlck1TUBKBBi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDRERDQ0FiT2dBd0lCQWdJUkFLL0RzTGo5TGtsaEpNT05kT0J3T1Rvd0NnWUlLb1pJemowRUF3SXdhVEVMCk1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ1RDa05oYkdsbWIzSnVhV0V4RmpBVUJnTlZCQWNURFZOaGJpQkcKY21GdVkybHpZMjh4RkRBU0JnTlZCQW9UQzJWNFlXMXdiR1V1WTI5dE1SY3dGUVlEVlFRREV3NWpZUzVsZUdGdApjR3hsTG1OdmJUQWVGdzB4T0RBMk1qSXdNekl5TWpoYUZ3MHlPREEyTVRrd016SXlNamhhTUZneEN6QUpCZ05WCkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saE1SWXdGQVlEVlFRSEV3MVRZVzRnUm5KaGJtTnAKYzJOdk1Sd3dHZ1lEVlFRREV4TnZjbVJsY21WeUxtVjRZVzF3YkdVdVkyOXRNRmt3RXdZSEtvWkl6ajBDQVFZSQpLb1pJemowREFRY0RRZ0FFcXRSNTh3ejZ6WHprQXk0bTJmckpqOWVrUFVlYXRybkJ1czNNWHpJYTdBWEV3TktDClBXYUV3WFJueHZqSzNsMm0vNW93TEJqYTJlelQ0NHYzdytwQW9hTk5NRXN3RGdZRFZSMFBBUUgvQkFRREFnZUEKTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEVlIwakJDUXdJb0FnVVFIdmhjVGtjNU1Pd003TU1VaUVTUTFOelpWTQp5Kys3aTZIT0tMV3FISlF3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnYkxuaWRoSk02NU9qK3F1bGpKY3p5THljClFqcEVYTVR2Y1ZySFNDQlkweG9DSUM1eGU1cDltcCsveXoxNkRzT2o0dmcwWGk0U0QwMkkwS0hqK3JXYW5ZaVkKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSGKlVoi/uZpH9p2usn5viEL8KBMIVe3J5iBJHMEUCIQDoJX+jd90k8lNEwASr8Dj3OLHKwFWWc88f+C6GzUhxRgIgY0kT3cVnQjWVsoevthBtNcz6YkNpI0GUiTDJ6ISa1bI=",
"EvgGCq0GCpAGCgpPcmRlcmVyTVNQEoEGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNERENDQWJPZ0F3SUJBZ0lSQUsvRHNMajlMa2xoSk1PTmRPQndPVG93Q2dZSUtvWkl6ajBFQXdJd2FURUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhGREFTQmdOVkJBb1RDMlY0WVcxd2JHVXVZMjl0TVJjd0ZRWURWUVFERXc1allTNWxlR0Z0CmNHeGxMbU52YlRBZUZ3MHhPREEyTWpJd016SXlNamhhRncweU9EQTJNVGt3TXpJeU1qaGFNRmd4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxVFlXNGdSbkpoYm1OcApjMk52TVJ3d0dnWURWUVFERXhOdmNtUmxjbVZ5TG1WNFlXMXdiR1V1WTI5dE1Ga3dFd1lIS29aSXpqMENBUVlJCktvWkl6ajBEQVFjRFFnQUVxdFI1OHd6NnpYemtBeTRtMmZySmo5ZWtQVWVhdHJuQnVzM01YeklhN0FYRXdOS0MKUFdhRXdYUm54dmpLM2wybS81b3dMQmphMmV6VDQ0djN3K3BBb2FOTk1Fc3dEZ1lEVlIwUEFRSC9CQVFEQWdlQQpNQXdHQTFVZEV3RUIvd1FDTUFBd0t3WURWUjBqQkNRd0lvQWdVUUh2aGNUa2M1TU93TTdNTVVpRVNRMU56WlZNCnkrKzdpNkhPS0xXcUhKUXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdiTG5pZGhKTTY1T2orcXVsakpjenlMeWMKUWpwRVhNVHZjVnJIU0NCWTB4b0NJQzV4ZTVwOW1wKy95ejE2RHNPajR2ZzBYaTRTRDAySTBLSGorcldhbllpWQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChIYookGAHnghPSXPwjAFj/AlPb25xa3pmKEEkYwRAIgECozAiQhEGJFam/6Fg8Bof29ub3bqk6wh86DvWBhuT4CIEYN3s6L+/bTvwelpwjb6zb1A3RW0IbRy994mJ1iYifD",
"CgIIAhL4BgqtBgqQBgoKT3JkZXJlck1TUBKBBi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDRERDQ0FiT2dBd0lCQWdJUkFLL0RzTGo5TGtsaEpNT05kT0J3T1Rvd0NnWUlLb1pJemowRUF3SXdhVEVMCk1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ1RDa05oYkdsbWIzSnVhV0V4RmpBVUJnTlZCQWNURFZOaGJpQkcKY21GdVkybHpZMjh4RkRBU0JnTlZCQW9UQzJWNFlXMXdiR1V1WTI5dE1SY3dGUVlEVlFRREV3NWpZUzVsZUdGdApjR3hsTG1OdmJUQWVGdzB4T0RBMk1qSXdNekl5TWpoYUZ3MHlPREEyTVRrd016SXlNamhhTUZneEN6QUpCZ05WCkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saE1SWXdGQVlEVlFRSEV3MVRZVzRnUm5KaGJtTnAKYzJOdk1Sd3dHZ1lEVlFRREV4TnZjbVJsY21WeUxtVjRZVzF3YkdVdVkyOXRNRmt3RXdZSEtvWkl6ajBDQVFZSQpLb1pJemowREFRY0RRZ0FFcXRSNTh3ejZ6WHprQXk0bTJmckpqOWVrUFVlYXRybkJ1czNNWHpJYTdBWEV3TktDClBXYUV3WFJueHZqSzNsMm0vNW93TEJqYTJlelQ0NHYzdytwQW9hTk5NRXN3RGdZRFZSMFBBUUgvQkFRREFnZUEKTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEVlIwakJDUXdJb0FnVVFIdmhjVGtjNU1Pd003TU1VaUVTUTFOelpWTQp5Kys3aTZIT0tMV3FISlF3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnYkxuaWRoSk02NU9qK3F1bGpKY3p5THljClFqcEVYTVR2Y1ZySFNDQlkweG9DSUM1eGU1cDltcCsveXoxNkRzT2o0dmcwWGk0U0QwMkkwS0hqK3JXYW5ZaVkKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSGK8xDVrCQFbNVkfoJ91h/tAoaUGltPzijBJGMEQCICG6/X6Lc9XMShQIG0+o+gvS4OWaVLkhUc3LsqX05KJ9AiAgh1LL/Fm7FRfgGoKH+BVmyf5pJj7bqext36eRHK5fKg==",
"",
""
]

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long