Finish sidedb feature
parent
78a440936b
commit
beb7610d52
|
@ -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"
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
|
||||
"requiredPeerCount": 0,
|
||||
"maxPeerCount": 3,
|
||||
"blockToLive":1000000
|
||||
"blockToLive":99999
|
||||
},
|
||||
{
|
||||
"name": "collectionMarblePrivateDetails",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 ==="
|
|
@ -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
|
|
@ -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}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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=",
|
||||
"",
|
||||
""
|
||||
]
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
|
@ -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; \
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
|
|
@ -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
|
||||
}
|
|
@ -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,18 +508,20 @@ chaincodeQuery () {
|
|||
let rc=1
|
||||
echo_b "$VALUE != ${expected_result}, will retry"
|
||||
fi
|
||||
fi
|
||||
if [ $rc -ne 0 ]; then
|
||||
else
|
||||
cat log.txt
|
||||
fi
|
||||
if [ $rc -ne 0 ]; then
|
||||
cat log.txt
|
||||
sleep 2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 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),
|
||||
|
|
|
@ -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}
|
||||
|
|
@ -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 ==="
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -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==",
|
||||
"",
|
||||
""
|
||||
]
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
Loading…
Reference in New Issue