├── 0.stopNetwork.sh ├── 1-1.hy-sample.sh ├── 1-2.startNetwork.sh ├── 2.addOrg3.sh ├── 3-1.installNetcon.sh ├── 3-2.installEstateBook.sh ├── 3-3.installEstateTax.sh ├── 4-0.stopAppcli.sh ├── 4.startAppcli.sh ├── LICENSE ├── README.md ├── appcode ├── docker-compose-appcli.yaml ├── fcc-client │ ├── README.md │ ├── babel.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ ├── guo.png │ │ │ ├── logo.png │ │ │ ├── logo.svg │ │ │ └── zhengwu.png │ │ ├── axios.js │ │ ├── main.js │ │ ├── plugins │ │ │ └── vuetify.js │ │ ├── router.js │ │ ├── views │ │ │ ├── Bigdata.vue │ │ │ ├── EstateBook.vue │ │ │ ├── EstateTax.vue │ │ │ └── Netcon.vue │ │ └── vue.config.js │ ├── vue.config.js │ └── yarn.lock └── fccserver │ └── src │ ├── ccservice │ ├── cccomm.go │ ├── ccestatebook.go │ ├── ccestatetax.go │ ├── ccnetcon.go │ └── common.go │ ├── comm │ └── webcomm.go │ ├── config.yaml │ ├── db │ ├── dbservice.go │ └── tbservice.go │ ├── fccserver │ ├── fccserver.go │ ├── middleware │ └── middleware.go │ ├── routers │ └── router.go │ └── service │ ├── cast.go │ ├── caste.go │ ├── estatebook.go │ ├── estatetax.go │ ├── netcon.go │ └── system.go └── chaincode ├── estatebook └── estatebook.go ├── estatetax └── estatetax.go └── netcon └── netcon.go /0.stopNetwork.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit on first error 4 | set -e 5 | 6 | function clearContainers () { 7 | CONTAINER_IDS=$(docker ps -aq) 8 | if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" == " " ]; then 9 | echo "---- No containers available for deletion ----" 10 | else 11 | docker rm -f $CONTAINER_IDS 12 | fi 13 | } 14 | 15 | function removeUnwantedImages() { 16 | DOCKER_IMAGE_IDS=$(docker images|awk '($1 ~ /dev-peer.*.example.*/) {print $3}') 17 | if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then 18 | echo "---- No images available for deletion ----" 19 | else 20 | docker rmi -f $DOCKER_IMAGE_IDS 21 | fi 22 | } 23 | 24 | clearContainers 25 | removeUnwantedImages 26 | 27 | cd ../first-network 28 | echo y | ./byfn.sh down 29 | 30 | cd ../fcc 31 | echo network stoped . 32 | -------------------------------------------------------------------------------- /1-1.hy-sample.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright IBM Corp. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | # if version not passed in, default to latest released version 9 | VERSION=1.4.4 10 | # if ca version not passed in, default to latest released version 11 | CA_VERSION=1.4.4 12 | # current version of thirdparty images (couchdb, kafka and zookeeper) released 13 | THIRDPARTY_IMAGE_VERSION=0.4.18 14 | ARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')") 15 | MARCH=$(uname -m) 16 | 17 | printHelp() { 18 | echo "Usage: bootstrap.sh [version [ca_version [thirdparty_version]]] [options]" 19 | echo 20 | echo "options:" 21 | echo "-h : this help" 22 | echo "-d : bypass docker image download" 23 | echo "-s : bypass fabric-samples repo clone" 24 | echo "-b : bypass download of platform-specific binaries" 25 | echo 26 | echo "e.g. bootstrap.sh 1.4.4 -s" 27 | echo "would download docker images and binaries for version 1.4.4" 28 | } 29 | 30 | # dockerPull() pulls docker images from fabric and chaincode repositories 31 | # note, if a docker image doesn't exist for a requested release, it will simply 32 | # be skipped, since this script doesn't terminate upon errors. 33 | 34 | dockerPull() { 35 | image_tag=$1 36 | shift 37 | while [[ $# -gt 0 ]] 38 | do 39 | image_name="$1" 40 | echo "====> hyperledger/fabric-$image_name:$image_tag" 41 | docker pull "hyperledger/fabric-$image_name:$image_tag" 42 | docker tag "hyperledger/fabric-$image_name:$image_tag" "hyperledger/fabric-$image_name" 43 | shift 44 | done 45 | } 46 | 47 | cloneSamplesRepo() { 48 | # clone (if needed) hyperledger/fabric-samples and checkout corresponding 49 | # version to the binaries and docker images to be downloaded 50 | if [ -d first-network ]; then 51 | # if we are in the fabric-samples repo, checkout corresponding version 52 | echo "===> Checking out v${VERSION} of hyperledger/fabric-samples" 53 | git checkout v${VERSION} 54 | elif [ -d fabric-samples ]; then 55 | # if fabric-samples repo already cloned and in current directory, 56 | # cd fabric-samples and checkout corresponding version 57 | echo "===> Checking out v${VERSION} of hyperledger/fabric-samples" 58 | cd fabric-samples && git checkout v${VERSION} 59 | else 60 | echo "===> Cloning hyperledger/fabric-samples repo and checkout v${VERSION}" 61 | git clone -b master https://github.com/hyperledger/fabric-samples.git && cd fabric-samples && git checkout v${VERSION} 62 | fi 63 | } 64 | 65 | # This will download the .tar.gz 66 | download() { 67 | local BINARY_FILE=$1 68 | local URL=$2 69 | echo "===> Downloading: " "${URL}" 70 | curl -s -L "${URL}" | tar xz || rc=$? 71 | if [ -n "$rc" ]; then 72 | echo "==> There was an error downloading the binary file." 73 | return 22 74 | else 75 | echo "==> Done." 76 | fi 77 | } 78 | 79 | pullBinaries() { 80 | echo "===> Downloading version ${FABRIC_TAG} platform specific fabric binaries" 81 | download "${BINARY_FILE}" "https://github.com/hyperledger/fabric/releases/download/v${VERSION}/${BINARY_FILE}" 82 | if [ $? -eq 22 ]; then 83 | echo 84 | echo "------> ${FABRIC_TAG} platform specific fabric binary is not available to download <----" 85 | echo 86 | exit 87 | fi 88 | 89 | echo "===> Downloading version ${CA_TAG} platform specific fabric-ca-client binary" 90 | download "${CA_BINARY_FILE}" "https://github.com/hyperledger/fabric-ca/releases/download/v${CA_VERSION}/${CA_BINARY_FILE}" 91 | if [ $? -eq 22 ]; then 92 | echo 93 | echo "------> ${CA_TAG} fabric-ca-client binary is not available to download (Available from 1.1.0-rc1) <----" 94 | echo 95 | exit 96 | fi 97 | } 98 | 99 | pullDockerImages() { 100 | command -v docker >& /dev/null 101 | NODOCKER=$? 102 | if [ "${NODOCKER}" == 0 ]; then 103 | FABRIC_IMAGES=(peer orderer ccenv tools) 104 | case "$VERSION" in 105 | 1.*) 106 | FABRIC_IMAGES+=(javaenv) 107 | shift 108 | ;; 109 | 2.*) 110 | FABRIC_IMAGES+=(nodeenv baseos javaenv) 111 | shift 112 | ;; 113 | esac 114 | echo "FABRIC_IMAGES:" "${FABRIC_IMAGES[@]}" 115 | echo "===> Pulling fabric Images" 116 | dockerPull "${FABRIC_TAG}" "${FABRIC_IMAGES[@]}" 117 | echo "===> Pulling fabric ca Image" 118 | CA_IMAGE=(ca) 119 | dockerPull "${CA_TAG}" "${CA_IMAGE[@]}" 120 | echo "===> Pulling thirdparty docker images" 121 | THIRDPARTY_IMAGES=(zookeeper kafka couchdb) 122 | dockerPull "${THIRDPARTY_TAG}" "${THIRDPARTY_IMAGES[@]}" 123 | echo 124 | echo "===> List out hyperledger docker images" 125 | docker images | grep hyperledger 126 | else 127 | echo "=========================================================" 128 | echo "Docker not installed, bypassing download of Fabric images" 129 | echo "=========================================================" 130 | fi 131 | } 132 | 133 | DOCKER=true 134 | SAMPLES=true 135 | BINARIES=true 136 | 137 | # Parse commandline args pull out 138 | # version and/or ca-version strings first 139 | if [ -n "$1" ] && [ "${1:0:1}" != "-" ]; then 140 | VERSION=$1;shift 141 | if [ -n "$1" ] && [ "${1:0:1}" != "-" ]; then 142 | CA_VERSION=$1;shift 143 | if [ -n "$1" ] && [ "${1:0:1}" != "-" ]; then 144 | THIRDPARTY_IMAGE_VERSION=$1;shift 145 | fi 146 | fi 147 | fi 148 | 149 | # prior to 1.2.0 architecture was determined by uname -m 150 | if [[ $VERSION =~ ^1\.[0-1]\.* ]]; then 151 | export FABRIC_TAG=${MARCH}-${VERSION} 152 | export CA_TAG=${MARCH}-${CA_VERSION} 153 | export THIRDPARTY_TAG=${MARCH}-${THIRDPARTY_IMAGE_VERSION} 154 | else 155 | # starting with 1.2.0, multi-arch images will be default 156 | : "${CA_TAG:="$CA_VERSION"}" 157 | : "${FABRIC_TAG:="$VERSION"}" 158 | : "${THIRDPARTY_TAG:="$THIRDPARTY_IMAGE_VERSION"}" 159 | fi 160 | 161 | BINARY_FILE=hyperledger-fabric-${ARCH}-${VERSION}.tar.gz 162 | CA_BINARY_FILE=hyperledger-fabric-ca-${ARCH}-${CA_VERSION}.tar.gz 163 | 164 | # then parse opts 165 | while getopts "h?dsb" opt; do 166 | case "$opt" in 167 | h|\?) 168 | printHelp 169 | exit 0 170 | ;; 171 | d) DOCKER=false 172 | ;; 173 | s) SAMPLES=false 174 | ;; 175 | b) BINARIES=false 176 | ;; 177 | esac 178 | done 179 | 180 | if [ "$SAMPLES" == "true" ]; then 181 | echo 182 | echo "Clone hyperledger/fabric-samples repo" 183 | echo 184 | cloneSamplesRepo 185 | fi 186 | if [ "$BINARIES" == "true" ]; then 187 | echo 188 | echo "Pull Hyperledger Fabric binaries" 189 | echo 190 | pullBinaries 191 | fi 192 | if [ "$DOCKER" == "true" ]; then 193 | echo 194 | echo "Pull Hyperledger Fabric docker images" 195 | echo 196 | pullDockerImages 197 | fi 198 | -------------------------------------------------------------------------------- /1-2.startNetwork.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright IBM Corp All Rights Reserved 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | # Exit on first error 8 | set -e 9 | 10 | # launch network; create channel and join peer to channel 11 | function clearContainers () { 12 | CONTAINER_IDS=$(docker ps -aq) 13 | if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" == " " ]; then 14 | echo "---- No containers available for deletion ----" 15 | else 16 | docker rm -f $CONTAINER_IDS 17 | fi 18 | } 19 | 20 | # Delete any images that were generated as a part of this setup 21 | # specifically the following images are often left behind: 22 | # TODO list generated image naming patterns 23 | function removeUnwantedImages() { 24 | DOCKER_IMAGE_IDS=$(docker images|awk '($1 ~ /dev-peer.*.example.*/) {print $3}') 25 | if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then 26 | echo "---- No images available for deletion ----" 27 | else 28 | docker rmi -f $DOCKER_IMAGE_IDS 29 | fi 30 | } 31 | 32 | clearContainers 33 | removeUnwantedImages 34 | 35 | cd ../first-network 36 | 37 | echo y | ./byfn.sh down 38 | echo y | ./byfn.sh up -a -n -s couchdb 39 | 40 | cd ../fcc 41 | echo network started . 42 | -------------------------------------------------------------------------------- /2.addOrg3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo 3 | echo =========================================== 4 | echo === add Org3 to network 5 | echo ========================================== 6 | echo 7 | 8 | CHANNEL_NAME="mychannel" 9 | 10 | echo 11 | echo "========= Creating config transaction to add org3 to network =========== " 12 | echo 13 | 14 | echo "Generate the Org3 Crypto Material" 15 | cd ../first-network/org3-artifacts 16 | ../../bin/cryptogen generate --config=./org3-crypto.yaml 17 | export FABRIC_CFG_PATH=$PWD && ../../bin/configtxgen -printOrg Org3MSP > ../channel-artifacts/org3.json 18 | cp -r crypto-config/peerOrganizations/org3.example.com/ ../crypto-config/peerOrganizations/ 19 | cd ../../fcc 20 | 21 | echo "add org3 join channel ...." 22 | export IMAGE_TAG=1.4.3 && export COMPOSE_PROJECT_NAME=net && docker-compose -f ../first-network/docker-compose-org3.yaml up -d 23 | docker exec cli /opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/step1org3.sh 24 | docker exec cli /opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/step2org3.sh 25 | -------------------------------------------------------------------------------- /3-1.installNetcon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CC_RUNTIME_LANGUAGE=golang 4 | CC_SRC_PATH=github.com/chaincode/netcon 5 | 6 | CONFIG_ROOT=/opt/gopath/src/github.com/hyperledger/fabric/peer 7 | ORG1_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 8 | ORG1_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 9 | ORG2_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 10 | ORG2_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 11 | ORG3_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp 12 | ORG3_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt 13 | ORDERER_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 14 | set -x 15 | 16 | echo y |cp chaincode/netcon/netcon.go ../chaincode/netcon/ 17 | 18 | echo "Installing smart contract on peer0.org1.example.com" 19 | docker exec \ 20 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 21 | -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ 22 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 23 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ 24 | cli \ 25 | peer chaincode install \ 26 | -n netcon \ 27 | -v 1.0 \ 28 | -p "$CC_SRC_PATH" \ 29 | -l "$CC_RUNTIME_LANGUAGE" 30 | 31 | echo "Installing smart contract on peer1.org1.example.com" 32 | docker exec \ 33 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 34 | -e CORE_PEER_ADDRESS=peer1.org1.example.com:8051 \ 35 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 36 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ 37 | cli \ 38 | peer chaincode install \ 39 | -n netcon \ 40 | -v 1.0 \ 41 | -p "$CC_SRC_PATH" \ 42 | -l "$CC_RUNTIME_LANGUAGE" 43 | 44 | echo "Installing smart contract on peer0.org2.example.com" 45 | docker exec \ 46 | -e CORE_PEER_LOCALMSPID=Org2MSP \ 47 | -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ 48 | -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ 49 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ 50 | cli \ 51 | peer chaincode install \ 52 | -n netcon \ 53 | -v 1.0 \ 54 | -p "$CC_SRC_PATH" \ 55 | -l "$CC_RUNTIME_LANGUAGE" 56 | 57 | echo "Installing smart contract on peer1.org2.example.com" 58 | docker exec \ 59 | -e CORE_PEER_LOCALMSPID=Org2MSP \ 60 | -e CORE_PEER_ADDRESS=peer1.org2.example.com:10051 \ 61 | -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ 62 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ 63 | cli \ 64 | peer chaincode install \ 65 | -n netcon \ 66 | -v 1.0 \ 67 | -p "$CC_SRC_PATH" \ 68 | -l "$CC_RUNTIME_LANGUAGE" 69 | 70 | echo "Installing smart contract on peer0.org3.example.com" 71 | docker exec \ 72 | -e CORE_PEER_LOCALMSPID=Org3MSP \ 73 | -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 \ 74 | -e CORE_PEER_MSPCONFIGPATH=${ORG3_MSPCONFIGPATH} \ 75 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG3_TLS_ROOTCERT_FILE} \ 76 | cli \ 77 | peer chaincode install \ 78 | -n netcon \ 79 | -v 1.0 \ 80 | -p "$CC_SRC_PATH" \ 81 | -l "$CC_RUNTIME_LANGUAGE" 82 | 83 | echo "Installing smart contract on peer1.org3.example.com" 84 | docker exec \ 85 | -e CORE_PEER_LOCALMSPID=Org3MSP \ 86 | -e CORE_PEER_ADDRESS=peer1.org3.example.com:12051 \ 87 | -e CORE_PEER_MSPCONFIGPATH=${ORG3_MSPCONFIGPATH} \ 88 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG3_TLS_ROOTCERT_FILE} \ 89 | cli \ 90 | peer chaincode install \ 91 | -n netcon \ 92 | -v 1.0 \ 93 | -p "$CC_SRC_PATH" \ 94 | -l "$CC_RUNTIME_LANGUAGE" 95 | 96 | echo "Instantiating smart contract on mychannel" 97 | docker exec \ 98 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 99 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 100 | cli \ 101 | peer chaincode instantiate \ 102 | -o orderer.example.com:7050 \ 103 | -C mychannel \ 104 | -n netcon \ 105 | -l "$CC_RUNTIME_LANGUAGE" \ 106 | -v 1.0 \ 107 | -c '{"Args":[]}' \ 108 | -P "AND('Org1MSP.member','Org2MSP.member')" \ 109 | --tls \ 110 | --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ 111 | --peerAddresses peer0.org1.example.com:7051 \ 112 | --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} 113 | 114 | echo "Waiting for instantiation request to be committed ..." 115 | sleep 10 116 | 117 | echo "Submitting init transaction to smart contract on mychannel" 118 | echo "The transaction is sent to all of the peers so that chaincode is built before receiving the following requests" 119 | docker exec \ 120 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 121 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 122 | cli \ 123 | peer chaincode invoke \ 124 | -o orderer.example.com:7050 \ 125 | -C mychannel \ 126 | -n netcon \ 127 | -c '{"function":"queryAll","Args":[]}' \ 128 | --waitForEvent \ 129 | --tls \ 130 | --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ 131 | # --peerAddresses peer0.org1.example.com:7051 \ 132 | # --peerAddresses peer1.org1.example.com:8051 \ 133 | # --peerAddresses peer0.org2.example.com:9051 \ 134 | # --peerAddresses peer1.org2.example.com:10051 \ 135 | # --peerAddresses peer0.org3.example.com:11051 \ 136 | # --peerAddresses peer1.org3.example.com:12051 \ 137 | # --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ 138 | # --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ 139 | # --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} \ 140 | # --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} \ 141 | # --tlsRootCertFiles ${ORG3_TLS_ROOTCERT_FILE} \ 142 | # --tlsRootCertFiles ${ORG3_TLS_ROOTCERT_FILE} 143 | 144 | echo "List all instantiated chaincode in channal mychannel..." 145 | docker exec \ 146 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 147 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 148 | cli \ 149 | peer chaincode list --instantiated -C mychannel 150 | 151 | set +x 152 | -------------------------------------------------------------------------------- /3-2.installEstateBook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CC_RUNTIME_LANGUAGE=golang 4 | CC_SRC_PATH=github.com/chaincode/estatebook 5 | 6 | CONFIG_ROOT=/opt/gopath/src/github.com/hyperledger/fabric/peer 7 | ORG1_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 8 | ORG1_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 9 | ORG2_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 10 | ORG2_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 11 | ORG3_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp 12 | ORG3_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt 13 | ORDERER_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 14 | set -x 15 | 16 | echo y |cp chaincode/estatebook/estatebook.go ../chaincode/estatebook/ 17 | 18 | echo "Installing smart contract on peer0.org1.example.com" 19 | docker exec \ 20 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 21 | -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ 22 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 23 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ 24 | cli \ 25 | peer chaincode install \ 26 | -n estatebook \ 27 | -v 1.0 \ 28 | -p "$CC_SRC_PATH" \ 29 | -l "$CC_RUNTIME_LANGUAGE" 30 | 31 | echo "Installing smart contract on peer1.org1.example.com" 32 | docker exec \ 33 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 34 | -e CORE_PEER_ADDRESS=peer1.org1.example.com:8051 \ 35 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 36 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ 37 | cli \ 38 | peer chaincode install \ 39 | -n estatebook \ 40 | -v 1.0 \ 41 | -p "$CC_SRC_PATH" \ 42 | -l "$CC_RUNTIME_LANGUAGE" 43 | 44 | echo "Installing smart contract on peer0.org2.example.com" 45 | docker exec \ 46 | -e CORE_PEER_LOCALMSPID=Org2MSP \ 47 | -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ 48 | -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ 49 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ 50 | cli \ 51 | peer chaincode install \ 52 | -n estatebook \ 53 | -v 1.0 \ 54 | -p "$CC_SRC_PATH" \ 55 | -l "$CC_RUNTIME_LANGUAGE" 56 | 57 | echo "Installing smart contract on peer1.org2.example.com" 58 | docker exec \ 59 | -e CORE_PEER_LOCALMSPID=Org2MSP \ 60 | -e CORE_PEER_ADDRESS=peer1.org2.example.com:10051 \ 61 | -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ 62 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ 63 | cli \ 64 | peer chaincode install \ 65 | -n estatebook \ 66 | -v 1.0 \ 67 | -p "$CC_SRC_PATH" \ 68 | -l "$CC_RUNTIME_LANGUAGE" 69 | 70 | echo "Installing smart contract on peer0.org3.example.com" 71 | docker exec \ 72 | -e CORE_PEER_LOCALMSPID=Org3MSP \ 73 | -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 \ 74 | -e CORE_PEER_MSPCONFIGPATH=${ORG3_MSPCONFIGPATH} \ 75 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG3_TLS_ROOTCERT_FILE} \ 76 | cli \ 77 | peer chaincode install \ 78 | -n estatebook \ 79 | -v 1.0 \ 80 | -p "$CC_SRC_PATH" \ 81 | -l "$CC_RUNTIME_LANGUAGE" 82 | 83 | echo "Installing smart contract on peer1.org3.example.com" 84 | docker exec \ 85 | -e CORE_PEER_LOCALMSPID=Org3MSP \ 86 | -e CORE_PEER_ADDRESS=peer1.org3.example.com:12051 \ 87 | -e CORE_PEER_MSPCONFIGPATH=${ORG3_MSPCONFIGPATH} \ 88 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG3_TLS_ROOTCERT_FILE} \ 89 | cli \ 90 | peer chaincode install \ 91 | -n estatebook \ 92 | -v 1.0 \ 93 | -p "$CC_SRC_PATH" \ 94 | -l "$CC_RUNTIME_LANGUAGE" 95 | 96 | echo "Instantiating smart contract on mychannel" 97 | docker exec \ 98 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 99 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 100 | cli \ 101 | peer chaincode instantiate \ 102 | -o orderer.example.com:7050 \ 103 | -C mychannel \ 104 | -n estatebook \ 105 | -l "$CC_RUNTIME_LANGUAGE" \ 106 | -v 1.0 \ 107 | -c '{"Args":[]}' \ 108 | -P "AND('Org1MSP.member','Org2MSP.member')" \ 109 | --tls \ 110 | --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ 111 | --peerAddresses peer0.org1.example.com:7051 \ 112 | --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} 113 | 114 | echo "Waiting for instantiation request to be committed ..." 115 | sleep 10 116 | 117 | echo "Submitting init transaction to smart contract on mychannel" 118 | echo "The transaction is sent to all of the peers so that chaincode is built before receiving the following requests" 119 | docker exec \ 120 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 121 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 122 | cli \ 123 | peer chaincode invoke \ 124 | -o orderer.example.com:7050 \ 125 | -C mychannel \ 126 | -n estatebook \ 127 | -c '{"function":"queryAll","Args":[]}' \ 128 | --waitForEvent \ 129 | --tls \ 130 | --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ 131 | # --peerAddresses peer0.org1.example.com:7051 \ 132 | # --peerAddresses peer1.org1.example.com:8051 \ 133 | # --peerAddresses peer0.org2.example.com:9051 \ 134 | # --peerAddresses peer1.org2.example.com:10051 \ 135 | # --peerAddresses peer0.org3.example.com:11051 \ 136 | # --peerAddresses peer1.org3.example.com:12051 \ 137 | # --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ 138 | # --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ 139 | # --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} \ 140 | # --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} \ 141 | # --tlsRootCertFiles ${ORG3_TLS_ROOTCERT_FILE} \ 142 | # --tlsRootCertFiles ${ORG3_TLS_ROOTCERT_FILE} 143 | 144 | echo "List all instantiated chaincode in channal mychannel..." 145 | docker exec \ 146 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 147 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 148 | cli \ 149 | peer chaincode list --instantiated -C mychannel 150 | 151 | set +x 152 | -------------------------------------------------------------------------------- /3-3.installEstateTax.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CC_RUNTIME_LANGUAGE=golang 4 | CC_SRC_PATH=github.com/chaincode/estatetax 5 | 6 | CONFIG_ROOT=/opt/gopath/src/github.com/hyperledger/fabric/peer 7 | ORG1_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 8 | ORG1_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 9 | ORG2_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 10 | ORG2_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 11 | ORG3_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp 12 | ORG3_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt 13 | ORDERER_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 14 | set -x 15 | 16 | echo y |cp chaincode/estatetax/estatetax.go ../chaincode/estatetax/ 17 | 18 | echo "Installing smart contract on peer0.org1.example.com" 19 | docker exec \ 20 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 21 | -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ 22 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 23 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ 24 | cli \ 25 | peer chaincode install \ 26 | -n estatetax \ 27 | -v 1.0 \ 28 | -p "$CC_SRC_PATH" \ 29 | -l "$CC_RUNTIME_LANGUAGE" 30 | 31 | echo "Installing smart contract on peer1.org1.example.com" 32 | docker exec \ 33 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 34 | -e CORE_PEER_ADDRESS=peer1.org1.example.com:8051 \ 35 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 36 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ 37 | cli \ 38 | peer chaincode install \ 39 | -n estatetax \ 40 | -v 1.0 \ 41 | -p "$CC_SRC_PATH" \ 42 | -l "$CC_RUNTIME_LANGUAGE" 43 | 44 | echo "Installing smart contract on peer0.org2.example.com" 45 | docker exec \ 46 | -e CORE_PEER_LOCALMSPID=Org2MSP \ 47 | -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ 48 | -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ 49 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ 50 | cli \ 51 | peer chaincode install \ 52 | -n estatetax \ 53 | -v 1.0 \ 54 | -p "$CC_SRC_PATH" \ 55 | -l "$CC_RUNTIME_LANGUAGE" 56 | 57 | echo "Installing smart contract on peer1.org2.example.com" 58 | docker exec \ 59 | -e CORE_PEER_LOCALMSPID=Org2MSP \ 60 | -e CORE_PEER_ADDRESS=peer1.org2.example.com:10051 \ 61 | -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ 62 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ 63 | cli \ 64 | peer chaincode install \ 65 | -n estatetax \ 66 | -v 1.0 \ 67 | -p "$CC_SRC_PATH" \ 68 | -l "$CC_RUNTIME_LANGUAGE" 69 | 70 | echo "Installing smart contract on peer0.org3.example.com" 71 | docker exec \ 72 | -e CORE_PEER_LOCALMSPID=Org3MSP \ 73 | -e CORE_PEER_ADDRESS=peer0.org3.example.com:11051 \ 74 | -e CORE_PEER_MSPCONFIGPATH=${ORG3_MSPCONFIGPATH} \ 75 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG3_TLS_ROOTCERT_FILE} \ 76 | cli \ 77 | peer chaincode install \ 78 | -n estatetax \ 79 | -v 1.0 \ 80 | -p "$CC_SRC_PATH" \ 81 | -l "$CC_RUNTIME_LANGUAGE" 82 | 83 | echo "Installing smart contract on peer1.org3.example.com" 84 | docker exec \ 85 | -e CORE_PEER_LOCALMSPID=Org3MSP \ 86 | -e CORE_PEER_ADDRESS=peer1.org3.example.com:12051 \ 87 | -e CORE_PEER_MSPCONFIGPATH=${ORG3_MSPCONFIGPATH} \ 88 | -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG3_TLS_ROOTCERT_FILE} \ 89 | cli \ 90 | peer chaincode install \ 91 | -n estatetax \ 92 | -v 1.0 \ 93 | -p "$CC_SRC_PATH" \ 94 | -l "$CC_RUNTIME_LANGUAGE" 95 | 96 | echo "Instantiating smart contract on mychannel" 97 | docker exec \ 98 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 99 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 100 | cli \ 101 | peer chaincode instantiate \ 102 | -o orderer.example.com:7050 \ 103 | -C mychannel \ 104 | -n estatetax \ 105 | -l "$CC_RUNTIME_LANGUAGE" \ 106 | -v 1.0 \ 107 | -c '{"Args":[]}' \ 108 | -P "AND('Org1MSP.member','Org2MSP.member')" \ 109 | --tls \ 110 | --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ 111 | --peerAddresses peer0.org1.example.com:7051 \ 112 | --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} 113 | 114 | echo "Waiting for instantiation request to be committed ..." 115 | sleep 10 116 | 117 | echo "Submitting init transaction to smart contract on mychannel" 118 | echo "The transaction is sent to all of the peers so that chaincode is built before receiving the following requests" 119 | docker exec \ 120 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 121 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 122 | cli \ 123 | peer chaincode invoke \ 124 | -o orderer.example.com:7050 \ 125 | -C mychannel \ 126 | -n estatetax \ 127 | -c '{"function":"queryAll","Args":[]}' \ 128 | --waitForEvent \ 129 | --tls \ 130 | --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ 131 | # --peerAddresses peer0.org1.example.com:7051 \ 132 | # --peerAddresses peer1.org1.example.com:8051 \ 133 | # --peerAddresses peer0.org2.example.com:9051 \ 134 | # --peerAddresses peer1.org2.example.com:10051 \ 135 | # --peerAddresses peer0.org3.example.com:11051 \ 136 | # --peerAddresses peer1.org3.example.com:12051 \ 137 | # --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ 138 | # --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ 139 | # --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} \ 140 | # --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} \ 141 | # --tlsRootCertFiles ${ORG3_TLS_ROOTCERT_FILE} \ 142 | # --tlsRootCertFiles ${ORG3_TLS_ROOTCERT_FILE} 143 | 144 | echo "List all instantiated chaincode in channal mychannel..." 145 | docker exec \ 146 | -e CORE_PEER_LOCALMSPID=Org1MSP \ 147 | -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ 148 | cli \ 149 | peer chaincode list --instantiated -C mychannel 150 | 151 | set +x 152 | -------------------------------------------------------------------------------- /4-0.stopAppcli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd appcode 3 | docker-compose -f docker-compose-appcli.yaml down -v 4 | cd .. 5 | -------------------------------------------------------------------------------- /4.startAppcli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd appcode 3 | docker-compose -f docker-compose-appcli.yaml up -d 4 | cd .. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 以不动产登记业务为例,使用超级账本搭建政务数据区块链原型 2 | 3 | - ### 关于业务流程 4 | - 区域链(基于证书准入的联盟链)网络 5 | ![网络拓扑](http://xujf000.tk:28888/img/topo.png "网络拓扑") 6 | - 业务流程时序 7 | ![业务流程时序图](http://xujf000.tk:28888/img/flow.png "业务流程时序图") 8 | - ### 关于超级账本 9 | 关于区块链、超级账本、智能合约等概念,请自行谷哥和度娘。建议直接参考官网文档 https://hyperledger-fabric.readthedocs.io/en/release-1.4/ 10 | 11 | - ### 关于本例说明 12 | - 本例仅限搭建原型用于验证技术可行性目的,远达不到产品级可用; 13 | - 本例采用了3个组织,每组织2个节点,用于不动产、房管、税务三个部门做背书节点;3份智能合约(网签合同、纳税凭证、不动产权证书)跑在1个通道;状态数据库采用CouchDB; 14 | - 本例DEMO: http://xujf000.tk:28888/ (VPS,1CPU 1G MEM) 15 | 16 | - ### 如何搭建区块链并部署运行智能合约 17 | 本例采用1.4.3版本。以下步骤在centos7上完成,并适用于ubuntu/MACOS/WINDOWS等 18 | 1. 安装环境(go1.3以上,docker-ce,docker-compose,git) 19 | ```bash 20 | cd /opt 21 | wget https://dl.google.com/go/go1.13.4.linux-amd64.tar.gz 22 | tar zxvf go*.gz 23 | yum install -y yum-utils device-mapper-persistent-data lvm2 24 | wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo 25 | yum install -y docker-ce docker-compose git 26 | ``` 27 | 2. 下载超级账本官方超级账本网络示例 28 | 29 | 若带梯子,下载官方脚本执行: 30 | ```bash 31 | curl -sSL http://bit.ly/2ysbOFE | bash -s -- 1.4.3 1.4.3 0.4.15 32 | ``` 33 | 若无梯子,直接运行已下载的脚本执行: 34 | ```bash 35 | ./1-1.hy-sample.sh -- 1.4.3 1.4.3 0.4.15 36 | ``` 37 | 将会在当前/opt目录下生成fabric-samples目录,并自动下载命令工具和镜像。 38 | 39 | 3. 将fabric-samples/bin和/opt/go/bin 加入本地PATH 40 | 41 | 4. 下载本示例 42 | ```bash 43 | cd /opt/fabric-samples 44 | git clone https://github.com/fengzxu/fcc.git 45 | cd fcc 46 | ``` 47 | 5. 启动示例网络,创建区块链网络(2个组织,每组织2个节点) 48 | ```bash 49 | chmod +x *.sh 50 | ./1-2.startNetwork.sh 51 | ``` 52 | 完成后,结果显示: 53 | ```bash 54 | ========= All GOOD, BYFN execution completed =========== 55 | ``` 56 | 6. 加入第3个组织,2个节点 57 | ```bash 58 | ./2.addOrg3.sh 59 | ``` 60 | 完成后,结果显示: 61 | ```bash 62 | ========= Org3 is now halfway onto your first network ========= 63 | ``` 64 | 7. 部署政务智能合约,并实例化 65 | ```bash 66 | ./3-1.installNetcon.sh #合约:网签合同备案 67 | ./3-2.installEstateBook.sh #合约:不动产权证书 68 | ./3-3.installEstateTax.sh #合约:不动产业务缴税 69 | ``` 70 | 完成后,结果显示: 71 | ```bash 72 | Get instantiated chaincodes on channel mychannel: 73 | Name: estatebook, Version: 1.0, Path: github.com/chaincode/estatebook, Escc: escc, Vscc: vscc 74 | Name: estatetax, Version: 1.0, Path: github.com/chaincode/estatetax, Escc: escc, Vscc: vscc 75 | Name: netcon, Version: 1.0, Path: github.com/chaincode/netcon, Escc: escc, Vscc: vscc 76 | ``` 77 | 8. 编译后台。 代码位于appcode/fccserver/src 可自行编译,或直接使用已编译完成的可执行文件。 78 | ```bash 79 | chmod +x appcode/fccserver/src/fccserver 80 | ``` 81 | 启动后台容器 82 | ```bash 83 | ./4.startAppcli.sh 84 | docker logs -f appcli 85 | ``` 86 | 如果启动正常,会显示: 87 | ```bash 88 | [fcc-server] 2019/12/12 03:03:55 system db initiated successfully. 89 | [fcc-server] 2019/12/12 03:03:56 Chaincode client initialed successfully. 90 | [fcc-server] 2019/12/12 03:03:56 Server started on :1206 91 | ``` 92 | 9. 编译和部署前端。 前端采用VUE,也可使用其它前端框架或HTML。使用GNINX或其它WEB服务器部署编译后的前端代码。注:当前未使用登录和权限设置。 93 | ![DEMO](http://xujf000.tk:28888/img/demo.png "DEMO") 94 | 第一次操作数据上链时,区块链网络后端会根据背书节点和合约数量创建镜像并启动容器(本例为3*2) 大约耗时30-60秒,之后每次上链操作约1秒,查询小于1秒。 95 | 96 | 10. 重建后台容器或重建整个区块链网络: 97 | ```bash 98 | ./4-0.stopAppcli.sh #重建后台容器 99 | ./0.stopNetwork.sh #重建整个区块链网络 100 | ``` 101 | 102 | - ### 产品化需要注意的几个问题 103 | - 背书节点与查询节点:涉及合约数据的变更操作(新建、修改、删除)需要多个背书节点(AND、OR策略),查询合约和节点可在同一通道或不同通道; 104 | - 共识:需要采用KAFKA+ZK集群或ETCD集群; 105 | - 证书与权限:通过CA集群和MSP来管理发放不同权限的证书,考虑用证书或其它方式实现基于RBAC的权限控制; 106 | - 如果可以,采用国产加密算法; 107 | 108 | -------------------------------------------------------------------------------- /appcode/docker-compose-appcli.yaml: -------------------------------------------------------------------------------- 1 | # Copyright IBM Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | 6 | version: '2.1' 7 | 8 | networks: 9 | example.com: 10 | external: 11 | name: net_byfn 12 | 13 | volumes: 14 | appcli: 15 | 16 | services: 17 | appcli: 18 | container_name: appcli 19 | image: hyperledger/fabric-tools:1.4.3 20 | tty: true 21 | stdin_open: true 22 | # environment: 23 | # - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_byfn 24 | # - GOPATH=/opt/gopath 25 | # - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 26 | # - FABRIC_LOGGING_SPEC=DEBUG 27 | # - FABRIC_LOGGING_SPEC=INFO 28 | # - CORE_PEER_ID=appcli 29 | # - CA_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem 30 | # - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 31 | # - CORE_PEER_LOCALMSPID=Org1MSP 32 | # - CORE_PEER_TLS_ENABLED=true 33 | # - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt 34 | # - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key 35 | # - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 36 | # - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 37 | working_dir: /opt/ 38 | command: ./fccserver 39 | volumes: 40 | # - /var/run/:/host/var/run/ 41 | # - /opt/go/:/opt/go/ 42 | - ./fccserver/src/fccserver:/opt/fccserver 43 | - ./fccserver/src/config.yaml:/opt/config.yaml 44 | - ../../first-network/crypto-config/:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ 45 | # - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts 46 | ports: 47 | - 1206:1206 48 | networks: 49 | - example.com 50 | -------------------------------------------------------------------------------- /appcode/fcc-client/README.md: -------------------------------------------------------------------------------- 1 | # fcc-client 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | yarn run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | yarn run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /appcode/fcc-client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /appcode/fcc-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fcc-client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@fortawesome/fontawesome-free": "^5.8.2", 12 | "axios": "^0.19.0", 13 | "core-js": "^3.4.3", 14 | "querystring": "^0.2.0", 15 | "roboto-fontface": "*", 16 | "vue": "^2.6.10", 17 | "vue-router": "^3.1.3", 18 | "vuetify": "^2.1.0" 19 | }, 20 | "devDependencies": { 21 | "@vue/cli-plugin-babel": "^4.1.0", 22 | "@vue/cli-plugin-eslint": "^4.1.0", 23 | "@vue/cli-service": "^4.1.0", 24 | "babel-eslint": "^10.0.3", 25 | "eslint": "^5.16.0", 26 | "eslint-plugin-vue": "^5.0.0", 27 | "sass": "^1.19.0", 28 | "sass-loader": "^8.0.0", 29 | "vue-cli-plugin-vuetify": "^2.0.2", 30 | "vue-template-compiler": "^2.6.10", 31 | "vuetify-loader": "^1.3.0" 32 | }, 33 | "eslintConfig": { 34 | "root": true, 35 | "env": { 36 | "node": true 37 | }, 38 | "extends": [ 39 | "plugin:vue/essential", 40 | "eslint:recommended" 41 | ], 42 | "rules": {}, 43 | "parserOptions": { 44 | "parser": "babel-eslint" 45 | } 46 | }, 47 | "browserslist": [ 48 | "> 1%", 49 | "last 2 versions" 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /appcode/fcc-client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengzxu/fcc/aa2c77e2e2cfc650d30f4b9c432d2035517db545/appcode/fcc-client/public/favicon.ico -------------------------------------------------------------------------------- /appcode/fcc-client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 基于区块链的政务大数据 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/App.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/assets/guo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengzxu/fcc/aa2c77e2e2cfc650d30f4b9c432d2035517db545/appcode/fcc-client/src/assets/guo.png -------------------------------------------------------------------------------- /appcode/fcc-client/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengzxu/fcc/aa2c77e2e2cfc650d30f4b9c432d2035517db545/appcode/fcc-client/src/assets/logo.png -------------------------------------------------------------------------------- /appcode/fcc-client/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | Artboard 46 2 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/assets/zhengwu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengzxu/fcc/aa2c77e2e2cfc650d30f4b9c432d2035517db545/appcode/fcc-client/src/assets/zhengwu.png -------------------------------------------------------------------------------- /appcode/fcc-client/src/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | axios.interceptors.request.use( 3 | config => { 4 | return config; 5 | }, 6 | error => { 7 | return Promise.reject(error); 8 | }); 9 | 10 | axios.interceptors.response.use( 11 | response => { 12 | return response; 13 | }, 14 | error => { 15 | return Promise.reject(error); 16 | } 17 | ); 18 | export default axios; 19 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import vuetify from './plugins/vuetify'; 4 | import router from './router' 5 | import axios from './axios' 6 | import querystring from 'querystring' 7 | import 'roboto-fontface/css/roboto/roboto-fontface.css' 8 | import '@fortawesome/fontawesome-free/css/all.css' 9 | 10 | Vue.config.productionTip = false 11 | //set axios form-data 12 | Vue.prototype.$qs = querystring; 13 | Vue.prototype.$axios = axios 14 | 15 | new Vue({ 16 | vuetify, 17 | router, 18 | axios, 19 | render: h => h(App) 20 | }).$mount('#app') 21 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuetify from 'vuetify/lib'; 3 | 4 | Vue.use(Vuetify); 5 | 6 | export default new Vuetify({ 7 | icons: { 8 | iconfont: 'fa', 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | export default new Router({ 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'Netcon', 11 | component: () => import('@/views/Netcon.vue') 12 | }, 13 | { 14 | path: '/estatebook', 15 | name: 'Estatebook', 16 | component: () => import('@/views/EstateBook.vue') 17 | }, 18 | { 19 | path: '/bigdata', 20 | name: 'Bigdata', 21 | component: () => import('@/views/Bigdata.vue') 22 | }, 23 | { 24 | path: '/estatetax', 25 | name: 'EstateTax', 26 | component: () => import('@/views/EstateTax.vue') 27 | }, 28 | ] 29 | }) -------------------------------------------------------------------------------- /appcode/fcc-client/src/views/Bigdata.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 176 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/views/EstateBook.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 316 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/views/EstateTax.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 259 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/views/Netcon.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 282 | -------------------------------------------------------------------------------- /appcode/fcc-client/src/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | productionSourceMap: false, 3 | configureWebpack: { 4 | devServer: { 5 | proxy: { 6 | '/api': { 7 | target: 'http://localhost:1206', // 8 | changeOrigin: true, // 9 | pathRewrite: { 10 | '^/api': '/api' 11 | } 12 | } 13 | } 14 | } 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /appcode/fcc-client/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "transpileDependencies": [ 3 | "vuetify" 4 | ], 5 | productionSourceMap: false, 6 | configureWebpack: { 7 | devServer: { 8 | proxy: { 9 | '/api': { 10 | target: 'http://localhost:1206', // 11 | changeOrigin: true, // 12 | pathRewrite: { 13 | '^/api': '/api' 14 | } 15 | } 16 | } 17 | } 18 | }, 19 | } -------------------------------------------------------------------------------- /appcode/fccserver/src/ccservice/cccomm.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ccservice 18 | 19 | import ( 20 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 21 | "github.com/hyperledger/fabric-sdk-go/pkg/core/config" 22 | "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" 23 | "log" 24 | ) 25 | 26 | var ( 27 | ccFile = "./config.yaml" 28 | userName = "User1" 29 | orgName = "Org1" 30 | channelName = "mychannel" 31 | ccNetcon = "netcon" 32 | ccEstateBook = "estatebook" 33 | ccEstatetax = "estatetax" 34 | ) 35 | 36 | var sdk *fabsdk.FabricSDK 37 | var cclient *channel.Client 38 | 39 | func InitCCOnStart() error { 40 | sdk, err := fabsdk.New(config.FromFile(ccFile)) 41 | if err != nil { 42 | log.Println("WARN: init Chaincode SDK error:", err.Error()) 43 | return err 44 | } 45 | clientContext := sdk.ChannelContext(channelName, fabsdk.WithUser(userName), fabsdk.WithOrg(orgName)) 46 | if clientContext == nil { 47 | log.Println("WARN: init Chaincode clientContext error:", err.Error()) 48 | return err 49 | } else { 50 | cclient, err = channel.New(clientContext) 51 | if err != nil { 52 | log.Println("WARN: init Chaincode cclient error:", err.Error()) 53 | } 54 | } 55 | log.Println("Chaincode client initialed successfully.") 56 | return nil 57 | } 58 | 59 | func GetChannelClient() *channel.Client { 60 | return cclient 61 | } 62 | 63 | func CCinvoke(channelClient *channel.Client, ccname, fcn string, args []string) ([]byte, error) { 64 | var tempArgs [][]byte 65 | for i := 0; i < len(args); i++ { 66 | tempArgs = append(tempArgs, []byte(args[i])) 67 | } 68 | qrequest := channel.Request{ 69 | ChaincodeID: ccname, 70 | Fcn: fcn, 71 | Args: tempArgs, 72 | TransientMap: nil, 73 | InvocationChain: nil, 74 | } 75 | //log.Println("cc exec request:",qrequest.ChaincodeID,"\t",qrequest.Fcn,"\t",qrequest.Args) 76 | response, err := channelClient.Execute(qrequest) 77 | if err != nil { 78 | return nil, err 79 | } 80 | return response.Payload, nil 81 | } 82 | 83 | func CCquery(channelClient *channel.Client, ccname, fcn string, args []string) ([]byte, error) { 84 | var tempArgs [][]byte 85 | if args == nil { 86 | tempArgs = nil 87 | } else { 88 | for i := 0; i < len(args); i++ { 89 | tempArgs = append(tempArgs, []byte(args[i])) 90 | } 91 | } 92 | qrequest := channel.Request{ 93 | ChaincodeID: ccname, 94 | Fcn: fcn, 95 | Args: tempArgs, 96 | TransientMap: nil, 97 | InvocationChain: nil, 98 | } 99 | response, err := channelClient.Query(qrequest) 100 | if err != nil { 101 | return nil, err 102 | } 103 | return response.Payload, nil 104 | } 105 | -------------------------------------------------------------------------------- /appcode/fccserver/src/ccservice/ccestatebook.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ccservice 18 | 19 | import ( 20 | "comm" 21 | "encoding/json" 22 | ) 23 | 24 | type CEstateBook struct { 25 | BookID string `json:"bookid"` //不动产证书编号 26 | Owner string `json:"owner"` //户主 27 | Addr string `json:"addr"` //房屋地址 28 | Area int `json:"area"` //房屋面积 29 | } 30 | 31 | func EstateBookCreate(uuid, bookid, owener, addr, area string) (res comm.ResResult) { 32 | cclient = GetChannelClient() 33 | if cclient == nil { 34 | res.Code = 1 35 | res.Status = "Chaincode service uninitialed." 36 | return 37 | } 38 | //check if bookid exist 39 | res = EstateBookQueryByBookid(bookid) 40 | if res.Code > 0 { 41 | return 42 | } 43 | ns := res.Status.([]CEstateBook) 44 | if len(ns) > 0 { 45 | res.Code = 1 46 | res.Status = bookid + " already exited!" 47 | return 48 | } 49 | //new 50 | bs, err := CCinvoke(cclient, ccEstateBook, "create", 51 | []string{uuid, bookid, owener, addr, area}) 52 | if err != nil { 53 | res.Code = 1 54 | res.Status = err.Error() 55 | } else { 56 | res.Code = 0 57 | res.Status = string(bs) 58 | } 59 | return 60 | } 61 | 62 | func EstateBookQueryByBookid(bookid string) (res comm.ResResult) { 63 | cclient = GetChannelClient() 64 | if cclient == nil { 65 | res.Code = 1 66 | res.Status = "Chaincode service uninitialed." 67 | return 68 | } 69 | bs, err := CCquery(cclient, ccEstateBook, "queryByBookID", []string{bookid}) 70 | if err != nil { 71 | res.Code = 1 72 | res.Status = err.Error() 73 | } else { 74 | res.Code = 0 75 | str := string(bs) 76 | var books []CEstateBook 77 | err = json.Unmarshal([]byte(str), &books) 78 | if err != nil { 79 | res.Code = 1 80 | res.Status = err.Error() 81 | } else { 82 | res.Status = books 83 | } 84 | } 85 | return 86 | } 87 | 88 | func EstateBookQueryAll() (res comm.ResResult) { 89 | cclient = GetChannelClient() 90 | if cclient == nil { 91 | res.Code = 1 92 | res.Status = "Chaincode service uninitialed." 93 | return 94 | } 95 | bs, err := CCquery(cclient, ccEstateBook, "queryAll", nil) 96 | if err != nil { 97 | res.Code = 1 98 | res.Status = err.Error() 99 | } else { 100 | res.Code = 0 101 | str := string(bs) 102 | var cs []CEstateBook 103 | err = json.Unmarshal([]byte(str), &cs) 104 | if err != nil { 105 | res.Code = 1 106 | res.Status = err.Error() 107 | } else { 108 | res.Status = cs 109 | } 110 | } 111 | return 112 | } 113 | -------------------------------------------------------------------------------- /appcode/fccserver/src/ccservice/ccestatetax.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ccservice 18 | 19 | import ( 20 | "comm" 21 | "encoding/json" 22 | ) 23 | 24 | type CEstateTax struct { 25 | TaxID string `json:"taxid"` //核税编号 26 | BookID string `json:"bookid"` //不动产权证书编号 27 | Taxer string `json:"taxer"` //纳税人 28 | Area int `json:"area"` //房屋面积 29 | Tax int `json:"tax"` //纳税金额 30 | } 31 | 32 | func EstateTaxCreate(uuid, taxid, bookid, taxer, area, tax string) (res comm.ResResult) { 33 | cclient = GetChannelClient() 34 | if cclient == nil { 35 | res.Code = 1 36 | res.Status = "Chaincode service uninitialed." 37 | return 38 | } 39 | //check if taxid exist 40 | res = EstateTaxQueryByTaxid(taxid) 41 | if res.Code >0 { 42 | return 43 | } 44 | ns:=res.Status.([]CEstateTax) 45 | if len(ns)>0 { 46 | res.Code = 1 47 | res.Status = taxid+" already exited!" 48 | return 49 | } 50 | bs, err := CCinvoke(cclient, ccEstatetax, "create", 51 | []string{uuid, taxid, bookid, taxer, area, tax}) 52 | if err != nil { 53 | res.Code = 1 54 | res.Status = err.Error() 55 | } else { 56 | res.Code = 0 57 | res.Status = string(bs) 58 | } 59 | return 60 | } 61 | 62 | func EstateTaxQueryByTaxid(taxid string) (res comm.ResResult) { 63 | cclient = GetChannelClient() 64 | if cclient == nil { 65 | res.Code = 1 66 | res.Status = "Chaincode service uninitialed." 67 | return 68 | } 69 | bs, err := CCquery(cclient, ccEstatetax, "queryByTaxID", []string{taxid}) 70 | if err != nil { 71 | res.Code = 1 72 | res.Status = err.Error() 73 | } else { 74 | res.Code = 0 75 | str := string(bs) 76 | var cs []CEstateTax 77 | err = json.Unmarshal([]byte(str), &cs) 78 | if err != nil { 79 | res.Code = 1 80 | res.Status = err.Error() 81 | } else { 82 | res.Status = cs 83 | } 84 | } 85 | return 86 | } 87 | 88 | func EstateTaxQueryAll() (res comm.ResResult) { 89 | cclient = GetChannelClient() 90 | if cclient == nil { 91 | res.Code = 1 92 | res.Status = "Chaincode service uninitialed." 93 | return 94 | } 95 | bs, err := CCquery(cclient, ccEstatetax, "queryAll", nil) 96 | if err != nil { 97 | res.Code = 1 98 | res.Status = err.Error() 99 | } else { 100 | res.Code = 0 101 | str := string(bs) 102 | var cs []CEstateTax 103 | err = json.Unmarshal([]byte(str), &cs) 104 | if err != nil { 105 | res.Code = 1 106 | res.Status = err.Error() 107 | } else { 108 | res.Status = cs 109 | } 110 | } 111 | return 112 | } 113 | 114 | func EstateTaxQueryAllid() (res comm.ResResult) { 115 | res = EstateTaxQueryAll() 116 | if res.Code == 0 { 117 | ids := []string{} 118 | for _, con := range res.Status.([]CEstateTax) { 119 | ids = append(ids, con.TaxID) 120 | } 121 | res.Status = ids 122 | } 123 | return 124 | } 125 | -------------------------------------------------------------------------------- /appcode/fccserver/src/ccservice/ccnetcon.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ccservice 18 | 19 | import ( 20 | "comm" 21 | "encoding/json" 22 | ) 23 | 24 | type CNetcon struct { 25 | NetconID string `json:"netconid"` //合同编号 26 | ApplyA string `json:"applya"` //受让方(买方) 27 | ApplyB string `json:"applyb"` //转让方(卖方) 28 | Addr string `json:"addr"` //房屋地址 29 | Area int `json:"area"` //房屋面积 30 | Balance int `json:"balance"` //转让金额 31 | } 32 | 33 | func NetconCreate(uuid, netconid, applya, applyb, addr, area, balance string) (res comm.ResResult) { 34 | cclient = GetChannelClient() 35 | if cclient == nil { 36 | res.Code = 1 37 | res.Status = "Chaincode service uninitialed." 38 | return 39 | } 40 | //check if netconid exist 41 | res = NetconQueryByNetconid(netconid) 42 | if res.Code >0 { 43 | return 44 | } 45 | ns:=res.Status.([]CNetcon) 46 | if len(ns)>0 { 47 | res.Code = 1 48 | res.Status = netconid+" already exited!" 49 | return 50 | } 51 | //new 52 | bs, err := CCinvoke(cclient, ccNetcon, "create", 53 | []string{uuid, netconid, applya, applyb, addr, area, balance}) 54 | if err != nil { 55 | res.Code = 1 56 | res.Status = err.Error() 57 | } else { 58 | res.Code = 0 59 | res.Status = string(bs) 60 | } 61 | return 62 | } 63 | 64 | func NetconQueryByNetconid(netconid string) (res comm.ResResult) { 65 | cclient = GetChannelClient() 66 | if cclient == nil { 67 | res.Code = 1 68 | res.Status = "Chaincode service uninitialed." 69 | return 70 | } 71 | bs, err := CCquery(cclient, ccNetcon, "queryByNetconID", []string{netconid}) 72 | if err != nil { 73 | res.Code = 1 74 | res.Status = err.Error() 75 | } else { 76 | res.Code = 0 77 | //res.Status = string(bs) 78 | str := string(bs) 79 | var ns []CNetcon 80 | err = json.Unmarshal([]byte(str), &ns) 81 | if err != nil { 82 | res.Code = 1 83 | res.Status = err.Error() 84 | } else { 85 | res.Status = ns 86 | } 87 | } 88 | return 89 | } 90 | 91 | func NetconQueryAll() (res comm.ResResult) { 92 | cclient = GetChannelClient() 93 | if cclient == nil { 94 | res.Code = 1 95 | res.Status = "Chaincode service uninitialed." 96 | return 97 | } 98 | bs, err := CCquery(cclient, ccNetcon, "queryAll", nil) 99 | if err != nil { 100 | res.Code = 1 101 | res.Status = err.Error() 102 | } else { 103 | res.Code = 0 104 | str := string(bs) 105 | var cs []CNetcon 106 | err = json.Unmarshal([]byte(str), &cs) 107 | if err != nil { 108 | res.Code = 1 109 | res.Status = err.Error() 110 | }else { 111 | res.Status = cs 112 | } 113 | } 114 | return 115 | } 116 | 117 | func NetconGetAllCCid() (res comm.ResResult) { 118 | res = NetconQueryAll() 119 | if res.Code == 0 { 120 | ids := []string{} 121 | for _, con := range res.Status.([]CNetcon) { 122 | ids = append(ids, con.NetconID) 123 | } 124 | res.Status = ids 125 | } 126 | return 127 | } -------------------------------------------------------------------------------- /appcode/fccserver/src/ccservice/common.go: -------------------------------------------------------------------------------- 1 | package ccservice 2 | 3 | import ( 4 | "errors" 5 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 6 | "github.com/hyperledger/fabric-sdk-go/pkg/core/config" 7 | "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" 8 | ) 9 | 10 | var ( 11 | ccFile = "./config_test.yaml" 12 | userName = "User1" 13 | orgName = "Org1" 14 | channelName = "mychannel" 15 | ccNetcon = "netcon" 16 | ccEstateBook = "estatebook" 17 | ccEstatetax = "estatetax" 18 | ) 19 | 20 | var sdk *fabsdk.FabricSDK 21 | var cclient *channel.Client 22 | 23 | func GetSDK() (*fabsdk.FabricSDK, error) { 24 | if sdk != nil { 25 | return sdk, nil 26 | } 27 | sdk, err := fabsdk.New(config.FromFile(ccFile)) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return sdk, nil 32 | } 33 | 34 | func GetChannelClient() (*channel.Client, error) { 35 | if cclient != nil { 36 | return cclient, nil 37 | } 38 | sdk, err := GetSDK() 39 | if err != nil { 40 | return nil, err 41 | } 42 | clientContext := sdk.ChannelContext(channelName, fabsdk.WithUser(userName), fabsdk.WithOrg(orgName)) 43 | if clientContext == nil { 44 | return nil, errors.New("get clientContext failed!") 45 | } 46 | cclient, err = channel.New(clientContext) 47 | return cclient, err 48 | } 49 | 50 | func CCinvoke(channelClient *channel.Client, ccname, fcn string, args []string) ([]byte, error) { 51 | var tempArgs [][]byte 52 | for i := 0; i < len(args); i++ { 53 | tempArgs = append(tempArgs, []byte(args[i])) 54 | } 55 | qrequest := channel.Request{ 56 | ChaincodeID: ccname, 57 | Fcn: fcn, 58 | Args: tempArgs, 59 | TransientMap: nil, 60 | InvocationChain: nil, 61 | } 62 | response, err := channelClient.Execute(qrequest) 63 | if err != nil { 64 | return nil, err 65 | } 66 | return response.Payload, nil 67 | } 68 | 69 | func CCquery(channelClient *channel.Client, ccname, fcn string, args []string) ([]byte, error) { 70 | var tempArgs [][]byte 71 | if args == nil { 72 | tempArgs = nil 73 | } else { 74 | for i := 0; i < len(args); i++ { 75 | tempArgs = append(tempArgs, []byte(args[i])) 76 | } 77 | } 78 | qrequest := channel.Request{ 79 | ChaincodeID: ccname, 80 | Fcn: fcn, 81 | Args: tempArgs, 82 | TransientMap: nil, 83 | InvocationChain: nil, 84 | } 85 | response, err := channelClient.Query(qrequest) 86 | if err != nil { 87 | return nil, err 88 | } 89 | return response.Payload, nil 90 | } 91 | -------------------------------------------------------------------------------- /appcode/fccserver/src/comm/webcomm.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package comm 18 | 19 | type ResResult struct { 20 | Code int 21 | Status interface{} 22 | } 23 | 24 | -------------------------------------------------------------------------------- /appcode/fccserver/src/config.yaml: -------------------------------------------------------------------------------- 1 | version: 1.1.0 2 | 3 | client: 4 | organization: org1 5 | 6 | logging: 7 | level: info 8 | 9 | cryptoconfig: 10 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto 11 | credentialStore: 12 | path: /tmp/state-store 13 | cryptoStore: 14 | path: /tmp/msp 15 | 16 | BCCSP: 17 | security: 18 | enabled: true 19 | default: 20 | provider: "SW" 21 | hashAlgorithm: "SHA2" 22 | softVerify: true 23 | level: 256 24 | 25 | tlsCerts: 26 | systemCertPool: true 27 | client: 28 | keyfile: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/User1@org1.example.com/tls/client.key 29 | certfile: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/User1@org1.example.com/tls/client.crt 30 | 31 | channels: 32 | _default: 33 | peers: 34 | peer0.org1.example.com: 35 | endorsingPeer: true 36 | chaincodeQuery: true 37 | ledgerQuery: true 38 | eventSource: true 39 | peer0.org2.example.com: 40 | endorsingPeer: true 41 | chaincodeQuery: true 42 | ledgerQuery: true 43 | eventSource: true 44 | peer0.org3.example.com: 45 | endorsingPeer: true 46 | chaincodeQuery: true 47 | ledgerQuery: true 48 | eventSource: true 49 | policies: 50 | queryChannelConfig: 51 | minResponses: 1 52 | maxTargets: 1 53 | retryOpts: 54 | attempts: 5 55 | initialBackoff: 500ms 56 | maxBackoff: 5s 57 | backoffFactor: 2.0 58 | selection: 59 | SortingStrategy: BlockHeightPriority 60 | Balancer: RoundRobin 61 | BlockHeightLagThreshold: 5 62 | eventService: 63 | resolverStrategy: MinBlockHeight 64 | balancer: RoundRobin 65 | blockHeightLagThreshold: 4 66 | reconnectBlockHeightLagThreshold: 8 67 | peerMonitorPeriod: 6s 68 | 69 | mychannel: 70 | # orderers: 71 | # - orderer.example.com 72 | 73 | peers: 74 | peer0.org1.example.com: 75 | # peer1.org1.example.com: 76 | peer0.org2.example.com: 77 | # peer1.org2.example.com: 78 | peer0.org3.example.com: 79 | # peer1.org3.example.com: 80 | 81 | 82 | 83 | organizations: 84 | org1: 85 | mspid: Org1MSP 86 | cryptoPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp 87 | peers: 88 | - peer0.org1.example.com 89 | - peer1.org1.example.com 90 | 91 | org2: 92 | mspid: Org2MSP 93 | cryptoPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp 94 | peers: 95 | - peer0.org2.example.com 96 | - peer1.org2.example.com 97 | 98 | org3: 99 | mspid: Org3MSP 100 | cryptoPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/users/User1@org3.example.com/msp 101 | peers: 102 | - peer0.org3.example.com 103 | - peer1.org3.example.com 104 | # certificateAuthorities: 105 | # - ca.org2.example.com 106 | 107 | # Orderer Org name 108 | ordererorg: 109 | mspID: OrdererMSP 110 | cryptoPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/users/User1@example.com/msp/ 111 | 112 | orderers: 113 | orderer.example.com: 114 | url: orderer.example.com:7050 115 | grpcOptions: 116 | ssl-target-name-override: orderer.example.com 117 | keep-alive-time: 0s 118 | keep-alive-timeout: 20s 119 | keep-alive-permit: false 120 | fail-fast: false 121 | allow-insecure: false 122 | 123 | tlsCACerts: 124 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem 125 | 126 | peers: 127 | _default: 128 | grpcOptions: 129 | keep-alive-time: 0s 130 | keep-alive-timeout: 20s 131 | keep-alive-permit: false 132 | fail-fast: false 133 | allow-insecure: false 134 | 135 | peer0.org1.example.com: 136 | url: peer0.org1.example.com:7051 137 | grpcOptions: 138 | ssl-target-name-override: peer0.org1.example.com 139 | tlsCACerts: 140 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem 141 | 142 | peer1.org1.example.com: 143 | url: peer1.org1.example.com:8051 144 | grpcOptions: 145 | ssl-target-name-override: peer1.org1.example.com 146 | tlsCACerts: 147 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem 148 | 149 | peer0.org2.example.com: 150 | url: peer0.org2.example.com:9051 151 | grpcOptions: 152 | ssl-target-name-override: peer0.org2.example.com 153 | tlsCACerts: 154 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem 155 | 156 | peer1.org2.example.com: 157 | url: peer1.org2.example.com:10051 158 | grpcOptions: 159 | ssl-target-name-override: peer1.org2.example.com 160 | tlsCACerts: 161 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem 162 | 163 | peer0.org3.example.com: 164 | url: peer0.org3.example.com:11051 165 | grpcOptions: 166 | ssl-target-name-override: peer0.org3.example.com 167 | tlsCACerts: 168 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/tlsca/tlsca.org3.example.com-cert.pem 169 | 170 | peer1.org3.example.com: 171 | url: peer1.org3.example.com:12051 172 | grpcOptions: 173 | ssl-target-name-override: peer1.org3.example.com 174 | tlsCACerts: 175 | path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/tlsca/tlsca.org3.example.com-cert.pem 176 | 177 | 178 | entityMatchers: 179 | orderer: 180 | - pattern: orderer(\w*).example.com:(\w*) 181 | urlSubstitutionExp: orderer${1}.example.com:${2} 182 | sslTargetOverrideUrlSubstitutionExp: orderer${1}.example.com 183 | mappedHost: orderer${1}.example.com 184 | -------------------------------------------------------------------------------- /appcode/fccserver/src/db/dbservice.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package db 18 | 19 | import ( 20 | "github.com/go-xorm/xorm" 21 | _ "github.com/mattn/go-sqlite3" 22 | "log" 23 | "time" 24 | ) 25 | 26 | var dbfile = "./server.db" 27 | var engins map[string]*xorm.Engine = make(map[string]*xorm.Engine) 28 | 29 | func SetEngin(orm *xorm.Engine, keys ...string) { 30 | if len(keys) == 0 { 31 | engins["default"] = orm 32 | } else { 33 | engins[keys[0]] = orm 34 | } 35 | } 36 | 37 | func GetEngin(keys ...string) (e *xorm.Engine) { 38 | if len(keys) == 0 { 39 | return engins["default"] 40 | } else { 41 | return engins[keys[0]] 42 | } 43 | } 44 | 45 | func InitDB() error { 46 | //init dabase 47 | orm, err := xorm.NewEngine("sqlite3", dbfile) 48 | if err != nil { 49 | log.Println("error on init db file:", err.Error()) 50 | return err 51 | } 52 | orm.DatabaseTZ = time.Local // 53 | orm.TZLocation = time.Local // 54 | orm.SetMaxIdleConns(10) 55 | orm.SetMaxOpenConns(30) 56 | orm.ShowSQL(false) 57 | SetEngin(orm) 58 | 59 | //init tables 60 | err = initTables(orm) 61 | if err != nil { 62 | log.Println("system db error:", err.Error()) 63 | } else { 64 | log.Println("system db initiated successfully.") 65 | } 66 | return err 67 | } 68 | 69 | func initTables(orm *xorm.Engine) (err error) { 70 | 71 | //create tables if not exits 72 | err = orm.CreateTables( 73 | &Netcon{}, 74 | &EstateBook{}, 75 | &EstateTax{}, 76 | ) 77 | return 78 | } 79 | -------------------------------------------------------------------------------- /appcode/fccserver/src/db/tbservice.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package db 18 | 19 | import ( 20 | "log" 21 | "strconv" 22 | "time" 23 | ) 24 | 25 | type Netcon struct { 26 | ID string `xorm:"pk 'id'"` 27 | CreateDT time.Time //生成时间 28 | NetconID string //合同编号 29 | ApplyA string //受让方(买方) 30 | ApplyB string //转让方(卖方) 31 | Addr string //房屋地址 32 | Area int //房屋面积 33 | Balance int //转让金额 34 | Operator string //操作人员 35 | IsCCed int //是否已上链 36 | } 37 | 38 | type EstateTax struct { 39 | ID string `xorm:"pk 'id'"` 40 | CreateDT time.Time //生成时间 41 | TaxID string //核税编号 42 | BookID string //不动产权证书编号 43 | Taxer string //纳税人 44 | Area int //房屋面积 45 | Tax int //纳税金额 46 | Operator string //操作人员 47 | IsCCed int //是否已上链 48 | } 49 | 50 | type EstateBook struct { 51 | ID string `xorm:"pk 'id'"` 52 | CreateDT time.Time //生成时间 53 | BookID string //不动产证书编号 54 | NetconID string //网签合同编号 55 | TaxID string //纳税凭证编号 56 | Owner string //户主 57 | Addr string //房屋地址 58 | Area int //房屋面积 59 | Operator string //操作人员 60 | IsCCed int //是否已上链 61 | } 62 | 63 | func NetconsAll() (netcons []Netcon, err error) { 64 | err = GetEngin().Find(&netcons) 65 | if err != nil { 66 | log.Println(err) 67 | } 68 | return 69 | } 70 | 71 | func NetconsCreate(netconid, applya, applyb, addr string, area, balance int, operator string) error { 72 | netcon := Netcon{ 73 | ID: strconv.FormatInt(time.Now().Unix(), 10), 74 | CreateDT: time.Now(), 75 | NetconID: netconid, 76 | ApplyA: applya, 77 | ApplyB: applyb, 78 | Addr: addr, 79 | Area: area, 80 | Balance: balance, 81 | Operator: operator, 82 | } 83 | _, err := GetEngin().Insert(&netcon) 84 | return err 85 | } 86 | 87 | func NetconsUpdateCC(uuid string, iscced int) (err error) { 88 | netcon := &Netcon{} 89 | ok, err := GetEngin().ID(uuid).Get(netcon) 90 | if ok { 91 | netcon.IsCCed = iscced 92 | _, err = GetEngin().ID(uuid).Cols("is_c_ced").Update(netcon) 93 | } 94 | return 95 | } 96 | 97 | func EstateBookAll() (books []EstateBook, err error) { 98 | err = GetEngin().Find(&books) 99 | if err != nil { 100 | log.Println("error on EstateBookAll:", err.Error()) 101 | } 102 | return 103 | } 104 | 105 | func EstateBookCreate(bookid, netconid, taxid, owner, addr string, area int, operator string) error { 106 | book := EstateBook{ 107 | ID: strconv.FormatInt(time.Now().Unix(), 10), 108 | CreateDT: time.Now(), 109 | BookID: bookid, 110 | NetconID: netconid, 111 | TaxID: taxid, 112 | Owner: owner, 113 | Addr: addr, 114 | Area: area, 115 | Operator: operator, 116 | } 117 | _, err := GetEngin().Insert(&book) 118 | return err 119 | } 120 | 121 | func EstateBookUpdateCC(uuid string, iscced int) (err error) { 122 | book := &EstateBook{} 123 | ok, err := GetEngin().ID(uuid).Get(book) 124 | if ok { 125 | book.IsCCed = iscced 126 | _, err = GetEngin().ID(book.ID).Cols("is_c_ced").Update(book) 127 | } 128 | return 129 | } 130 | 131 | func EstateTaxAll() (taxs []EstateTax, err error) { 132 | err = GetEngin().Find(&taxs) 133 | if err != nil { 134 | log.Println(err) 135 | } 136 | return 137 | } 138 | 139 | func EstateTaxCreate(taxid, taxer string, area, tax int, operator string) error { 140 | newtax := EstateTax{ 141 | CreateDT: time.Now(), 142 | ID: strconv.FormatInt(time.Now().Unix(), 10), 143 | TaxID: taxid, 144 | //BookID: bookid, 145 | Taxer: taxer, 146 | Area: area, 147 | Tax: tax, 148 | Operator: operator, 149 | } 150 | _, err := GetEngin().Insert(&newtax) 151 | return err 152 | } 153 | 154 | func EstateTaxUpdateCC(uuid string, iscced int) (err error) { 155 | tax := &EstateTax{} 156 | ok, err := GetEngin().ID(uuid).Get(tax) 157 | if ok { 158 | tax.IsCCed = iscced 159 | _, err = GetEngin().ID(tax.ID).Cols("is_c_ced").Update(tax) 160 | } 161 | return 162 | } 163 | -------------------------------------------------------------------------------- /appcode/fccserver/src/fccserver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengzxu/fcc/aa2c77e2e2cfc650d30f4b9c432d2035517db545/appcode/fccserver/src/fccserver -------------------------------------------------------------------------------- /appcode/fccserver/src/fccserver.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/gin-gonic/gin" 21 | "log" 22 | "middleware" 23 | "net/http" 24 | "routers" 25 | "service" 26 | "time" 27 | ) 28 | 29 | func main() { 30 | //initlog() 31 | 32 | log.SetPrefix("[fcc-server] ") 33 | //init system 34 | err := service.InitOnSystemStart() 35 | if err != nil { 36 | log.Println("error on init system:", err.Error()) 37 | return 38 | } 39 | //init http 40 | inithttp() 41 | //println("service started.") 42 | } 43 | 44 | func inithttp() { 45 | gin.SetMode(gin.ReleaseMode) 46 | app := gin.New() 47 | // recover 48 | app.Use(middleware.RecoveryMiddleware()) 49 | 50 | // routers 51 | routers.RegisterRouter(app) 52 | 53 | //go initHTTPServer(app) 54 | initHTTPServer(app) 55 | 56 | } 57 | 58 | func initHTTPServer(handler http.Handler) { 59 | port := ":1206" 60 | srv := &http.Server{ 61 | Addr: port, 62 | Handler: handler, 63 | ReadTimeout: 30 * time.Second, 64 | WriteTimeout: 10 * time.Second, 65 | IdleTimeout: 15 * time.Second, 66 | } 67 | log.Println("Server started on ", srv.Addr) 68 | srv.ListenAndServe() 69 | } 70 | -------------------------------------------------------------------------------- /appcode/fccserver/src/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package middleware 18 | 19 | import ( 20 | "comm" 21 | "github.com/gin-gonic/gin" 22 | ) 23 | 24 | // RecoveryMiddleware 25 | func RecoveryMiddleware() gin.HandlerFunc { 26 | return func(c *gin.Context) { 27 | defer func() { 28 | if err := recover(); err != nil { 29 | c.JSON(500, comm.ResResult{ 30 | Code: 1, 31 | Status: "interal error.", 32 | }) 33 | c.Abort() 34 | return 35 | } 36 | }() 37 | c.Next() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /appcode/fccserver/src/routers/router.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package routers 18 | 19 | import ( 20 | "ccservice" 21 | "github.com/gin-gonic/gin" 22 | "service" 23 | "strconv" 24 | ) 25 | 26 | func RegisterRouter(app *gin.Engine) { 27 | //public frontend files 28 | //app.StaticFS("/html", http.Dir("public")) 29 | 30 | //registe all route path 31 | registerPath(app) 32 | } 33 | 34 | func registerPath(app *gin.Engine) { 35 | 36 | //root 37 | app.GET("/", func(c *gin.Context) { 38 | c.JSON(200, "fcc server.") 39 | }) 40 | app.GET("/api", func(c *gin.Context) { 41 | c.JSON(200, "fcc api server.") 42 | }) 43 | 44 | //netcon 45 | preNetcon := app.Group("/api/netcon") 46 | preNetcon.POST("/create", func(c *gin.Context) { 47 | netconid := c.PostForm("netconid") 48 | applya := c.PostForm("applya") 49 | applyb := c.PostForm("applyb") 50 | addr := c.PostForm("addr") 51 | area, _ := strconv.Atoi(c.DefaultPostForm("area", "0")) 52 | balance, _ := strconv.Atoi(c.DefaultPostForm("balance", "0")) 53 | c.JSON(200, service.NetconCreate(netconid, applya, applyb, addr, area, balance)) 54 | }) 55 | preNetcon.POST("/tocc", func(c *gin.Context) { 56 | uuid := c.PostForm("uuid") 57 | netconid := c.PostForm("netconid") 58 | applya := c.PostForm("applya") 59 | applyb := c.PostForm("applyb") 60 | addr := c.PostForm("addr") 61 | area := c.PostForm("area") 62 | balance := c.PostForm("balance") 63 | c.JSON(200, service.NetconToCC(uuid, netconid, applya, applyb, addr, area, balance)) 64 | }) 65 | preNetcon.GET("/queryall", func(c *gin.Context) { 66 | c.JSON(200, service.NetconGetAll()) 67 | }) 68 | 69 | //cc-netcon 70 | preCCNetcon := app.Group("/api/cc/netcon") 71 | preCCNetcon.GET("/querybynetconid", func(c *gin.Context) { 72 | netconid := c.Query("netconid") 73 | c.JSON(200, ccservice.NetconQueryByNetconid(netconid)) 74 | }) 75 | preCCNetcon.GET("/queryall", func(c *gin.Context) { 76 | c.JSON(200, ccservice.NetconQueryAll()) 77 | }) 78 | preCCNetcon.GET("/queryallid", func(c *gin.Context) { 79 | c.JSON(200, ccservice.NetconGetAllCCid()) 80 | }) 81 | 82 | //estatebook 83 | preEstatebook := app.Group("/api/estatebook") 84 | preEstatebook.POST("/create", func(c *gin.Context) { 85 | bookid := c.PostForm("bookid") 86 | netconid := c.PostForm("netconid") 87 | taxid := c.PostForm("taxid") 88 | owner := c.PostForm("owner") 89 | addr := c.PostForm("addr") 90 | area, _ := strconv.Atoi(c.DefaultPostForm("area", "0")) 91 | c.JSON(200, service.EstateBookCreate(bookid, netconid, taxid, owner, addr, area)) 92 | }) 93 | preEstatebook.GET("/queryall", func(c *gin.Context) { 94 | c.JSON(200, service.EstateBookGetAll()) 95 | }) 96 | preEstatebook.POST("/tocc", func(c *gin.Context) { 97 | uuid := c.PostForm("uuid") 98 | bookid := c.PostForm("bookid") 99 | owner := c.PostForm("owner") 100 | area := c.PostForm("area") 101 | addr := c.PostForm("addr") 102 | c.JSON(200, service.EstateBookToCC(uuid, bookid, owner, addr, area)) 103 | }) 104 | 105 | //cc-estatebook 106 | preCCEstatebook := app.Group("/api/cc/estatebook") 107 | preCCEstatebook.GET("/querybybookid", func(c *gin.Context) { 108 | bookid := c.Query("bookid") 109 | c.JSON(200, ccservice.EstateBookQueryByBookid(bookid)) 110 | }) 111 | preCCEstatebook.GET("/queryall", func(c *gin.Context) { 112 | c.JSON(200, ccservice.EstateBookQueryAll()) 113 | }) 114 | 115 | //estatetax 116 | preEstatetax := app.Group("/api/estatetax") 117 | preEstatetax.POST("/create", func(c *gin.Context) { 118 | taxid := c.PostForm("taxid") 119 | taxer := c.PostForm("taxer") 120 | area, _ := strconv.Atoi(c.DefaultPostForm("area", "0")) 121 | tax, _ := strconv.Atoi(c.DefaultPostForm("tax", "0")) 122 | c.JSON(200, service.EstateTaxCreate(taxid, taxer, area, tax)) 123 | }) 124 | preEstatetax.POST("/tocc", func(c *gin.Context) { 125 | uuid := c.PostForm("uuid") 126 | taxid := c.PostForm("taxid") 127 | taxer := c.PostForm("taxer") 128 | area := c.PostForm("area") 129 | tax := c.PostForm("tax") 130 | c.JSON(200, service.EstateTaxToCC(uuid, taxid, taxer, area, tax)) 131 | }) 132 | preEstatetax.GET("/queryall", func(c *gin.Context) { 133 | c.JSON(200, service.EstateTaxGetAll()) 134 | }) 135 | 136 | //cc-estatetax 137 | preCCEstatetax := app.Group("/api/cc/estatetax") 138 | preCCEstatetax.GET("/querybytaxid", func(c *gin.Context) { 139 | taxid := c.Query("taxid") 140 | c.JSON(200, ccservice.EstateTaxQueryByTaxid(taxid)) 141 | }) 142 | preCCEstatetax.GET("/queryall", func(c *gin.Context) { 143 | c.JSON(200, ccservice.EstateTaxQueryAll()) 144 | }) 145 | preCCEstatetax.GET("/queryallid", func(c *gin.Context) { 146 | c.JSON(200, ccservice.EstateTaxQueryAllid()) 147 | }) 148 | } 149 | -------------------------------------------------------------------------------- /appcode/fccserver/src/service/cast.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "time" 4 | 5 | // ToBool casts an interface to a bool type. 6 | func ToBool(i interface{}) bool { 7 | v, _ := ToBoolE(i) 8 | return v 9 | } 10 | 11 | // ToTime casts an interface to a time.Time type. 12 | func ToTime(i interface{}) time.Time { 13 | v, _ := ToTimeE(i) 14 | return v 15 | } 16 | 17 | // ToDuration casts an interface to a time.Duration type. 18 | func ToDuration(i interface{}) time.Duration { 19 | v, _ := ToDurationE(i) 20 | return v 21 | } 22 | 23 | // ToFloat64 casts an interface to a float64 type. 24 | func ToFloat64(i interface{}) float64 { 25 | v, _ := ToFloat64E(i) 26 | return v 27 | } 28 | 29 | // ToFloat32 casts an interface to a float32 type. 30 | func ToFloat32(i interface{}) float32 { 31 | v, _ := ToFloat32E(i) 32 | return v 33 | } 34 | 35 | // ToInt64 casts an interface to an int64 type. 36 | func ToInt64(i interface{}) int64 { 37 | v, _ := ToInt64E(i) 38 | return v 39 | } 40 | 41 | // ToInt32 casts an interface to an int32 type. 42 | func ToInt32(i interface{}) int32 { 43 | v, _ := ToInt32E(i) 44 | return v 45 | } 46 | 47 | // ToInt16 casts an interface to an int16 type. 48 | func ToInt16(i interface{}) int16 { 49 | v, _ := ToInt16E(i) 50 | return v 51 | } 52 | 53 | // ToInt8 casts an interface to an int8 type. 54 | func ToInt8(i interface{}) int8 { 55 | v, _ := ToInt8E(i) 56 | return v 57 | } 58 | 59 | // ToInt casts an interface to an int type. 60 | func ToInt(i interface{}) int { 61 | v, _ := ToIntE(i) 62 | return v 63 | } 64 | 65 | // ToUint casts an interface to a uint type. 66 | func ToUint(i interface{}) uint { 67 | v, _ := ToUintE(i) 68 | return v 69 | } 70 | 71 | // ToUint64 casts an interface to a uint64 type. 72 | func ToUint64(i interface{}) uint64 { 73 | v, _ := ToUint64E(i) 74 | return v 75 | } 76 | 77 | // ToUint32 casts an interface to a uint32 type. 78 | func ToUint32(i interface{}) uint32 { 79 | v, _ := ToUint32E(i) 80 | return v 81 | } 82 | 83 | // ToUint16 casts an interface to a uint16 type. 84 | func ToUint16(i interface{}) uint16 { 85 | v, _ := ToUint16E(i) 86 | return v 87 | } 88 | 89 | // ToUint8 casts an interface to a uint8 type. 90 | func ToUint8(i interface{}) uint8 { 91 | v, _ := ToUint8E(i) 92 | return v 93 | } 94 | 95 | // ToString casts an interface to a string type. 96 | func ToString(i interface{}) string { 97 | v, _ := ToStringE(i) 98 | return v 99 | } 100 | 101 | // ToStringMapString casts an interface to a map[string]string type. 102 | func ToStringMapString(i interface{}) map[string]string { 103 | v, _ := ToStringMapStringE(i) 104 | return v 105 | } 106 | 107 | // ToStringMapStringSlice casts an interface to a map[string][]string type. 108 | func ToStringMapStringSlice(i interface{}) map[string][]string { 109 | v, _ := ToStringMapStringSliceE(i) 110 | return v 111 | } 112 | 113 | // ToStringMapBool casts an interface to a map[string]bool type. 114 | func ToStringMapBool(i interface{}) map[string]bool { 115 | v, _ := ToStringMapBoolE(i) 116 | return v 117 | } 118 | 119 | // ToStringMapInt casts an interface to a map[string]int type. 120 | func ToStringMapInt(i interface{}) map[string]int { 121 | v, _ := ToStringMapIntE(i) 122 | return v 123 | } 124 | 125 | // ToStringMapInt64 casts an interface to a map[string]int64 type. 126 | func ToStringMapInt64(i interface{}) map[string]int64 { 127 | v, _ := ToStringMapInt64E(i) 128 | return v 129 | } 130 | 131 | // ToStringMap casts an interface to a map[string]interface{} type. 132 | func ToStringMap(i interface{}) map[string]interface{} { 133 | v, _ := ToStringMapE(i) 134 | return v 135 | } 136 | 137 | // ToSlice casts an interface to a []interface{} type. 138 | func ToSlice(i interface{}) []interface{} { 139 | v, _ := ToSliceE(i) 140 | return v 141 | } 142 | 143 | // ToBoolSlice casts an interface to a []bool type. 144 | func ToBoolSlice(i interface{}) []bool { 145 | v, _ := ToBoolSliceE(i) 146 | return v 147 | } 148 | 149 | // ToStringSlice casts an interface to a []string type. 150 | func ToStringSlice(i interface{}) []string { 151 | v, _ := ToStringSliceE(i) 152 | return v 153 | } 154 | 155 | // ToIntSlice casts an interface to a []int type. 156 | func ToIntSlice(i interface{}) []int { 157 | v, _ := ToIntSliceE(i) 158 | return v 159 | } 160 | 161 | // ToDurationSlice casts an interface to a []time.Duration type. 162 | func ToDurationSlice(i interface{}) []time.Duration { 163 | v, _ := ToDurationSliceE(i) 164 | return v 165 | } 166 | -------------------------------------------------------------------------------- /appcode/fccserver/src/service/caste.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "html/template" 8 | "reflect" 9 | "strconv" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | var errNegativeNotAllowed = errors.New("unable to cast negative value") 15 | 16 | // ToTimeE casts an interface to a time.Time type. 17 | func ToTimeE(i interface{}) (tim time.Time, err error) { 18 | i = indirect(i) 19 | 20 | switch v := i.(type) { 21 | case time.Time: 22 | return v, nil 23 | case string: 24 | return StringToDate(v) 25 | case int: 26 | return time.Unix(int64(v), 0), nil 27 | case int64: 28 | return time.Unix(v, 0), nil 29 | case int32: 30 | return time.Unix(int64(v), 0), nil 31 | case uint: 32 | return time.Unix(int64(v), 0), nil 33 | case uint64: 34 | return time.Unix(int64(v), 0), nil 35 | case uint32: 36 | return time.Unix(int64(v), 0), nil 37 | default: 38 | return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i) 39 | } 40 | } 41 | 42 | // ToDurationE casts an interface to a time.Duration type. 43 | func ToDurationE(i interface{}) (d time.Duration, err error) { 44 | i = indirect(i) 45 | 46 | switch s := i.(type) { 47 | case time.Duration: 48 | return s, nil 49 | case int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8: 50 | d = time.Duration(ToInt64(s)) 51 | return 52 | case float32, float64: 53 | d = time.Duration(ToFloat64(s)) 54 | return 55 | case string: 56 | if strings.ContainsAny(s, "nsuµmh") { 57 | d, err = time.ParseDuration(s) 58 | } else { 59 | d, err = time.ParseDuration(s + "ns") 60 | } 61 | return 62 | default: 63 | err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i) 64 | return 65 | } 66 | } 67 | 68 | // ToBoolE casts an interface to a bool type. 69 | func ToBoolE(i interface{}) (bool, error) { 70 | i = indirect(i) 71 | 72 | switch b := i.(type) { 73 | case bool: 74 | return b, nil 75 | case nil: 76 | return false, nil 77 | case int: 78 | if i.(int) != 0 { 79 | return true, nil 80 | } 81 | return false, nil 82 | case string: 83 | return strconv.ParseBool(i.(string)) 84 | default: 85 | return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i) 86 | } 87 | } 88 | 89 | // ToFloat64E casts an interface to a float64 type. 90 | func ToFloat64E(i interface{}) (float64, error) { 91 | i = indirect(i) 92 | 93 | switch s := i.(type) { 94 | case float64: 95 | return s, nil 96 | case float32: 97 | return float64(s), nil 98 | case int: 99 | return float64(s), nil 100 | case int64: 101 | return float64(s), nil 102 | case int32: 103 | return float64(s), nil 104 | case int16: 105 | return float64(s), nil 106 | case int8: 107 | return float64(s), nil 108 | case uint: 109 | return float64(s), nil 110 | case uint64: 111 | return float64(s), nil 112 | case uint32: 113 | return float64(s), nil 114 | case uint16: 115 | return float64(s), nil 116 | case uint8: 117 | return float64(s), nil 118 | case string: 119 | v, err := strconv.ParseFloat(s, 64) 120 | if err == nil { 121 | return v, nil 122 | } 123 | return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) 124 | case bool: 125 | if s { 126 | return 1, nil 127 | } 128 | return 0, nil 129 | default: 130 | return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) 131 | } 132 | } 133 | 134 | // ToFloat32E casts an interface to a float32 type. 135 | func ToFloat32E(i interface{}) (float32, error) { 136 | i = indirect(i) 137 | 138 | switch s := i.(type) { 139 | case float64: 140 | return float32(s), nil 141 | case float32: 142 | return s, nil 143 | case int: 144 | return float32(s), nil 145 | case int64: 146 | return float32(s), nil 147 | case int32: 148 | return float32(s), nil 149 | case int16: 150 | return float32(s), nil 151 | case int8: 152 | return float32(s), nil 153 | case uint: 154 | return float32(s), nil 155 | case uint64: 156 | return float32(s), nil 157 | case uint32: 158 | return float32(s), nil 159 | case uint16: 160 | return float32(s), nil 161 | case uint8: 162 | return float32(s), nil 163 | case string: 164 | v, err := strconv.ParseFloat(s, 32) 165 | if err == nil { 166 | return float32(v), nil 167 | } 168 | return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) 169 | case bool: 170 | if s { 171 | return 1, nil 172 | } 173 | return 0, nil 174 | default: 175 | return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) 176 | } 177 | } 178 | 179 | // ToInt64E casts an interface to an int64 type. 180 | func ToInt64E(i interface{}) (int64, error) { 181 | i = indirect(i) 182 | 183 | switch s := i.(type) { 184 | case int: 185 | return int64(s), nil 186 | case int64: 187 | return s, nil 188 | case int32: 189 | return int64(s), nil 190 | case int16: 191 | return int64(s), nil 192 | case int8: 193 | return int64(s), nil 194 | case uint: 195 | return int64(s), nil 196 | case uint64: 197 | return int64(s), nil 198 | case uint32: 199 | return int64(s), nil 200 | case uint16: 201 | return int64(s), nil 202 | case uint8: 203 | return int64(s), nil 204 | case float64: 205 | return int64(s), nil 206 | case float32: 207 | return int64(s), nil 208 | case string: 209 | v, err := strconv.ParseInt(s, 0, 0) 210 | if err == nil { 211 | return v, nil 212 | } 213 | return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) 214 | case bool: 215 | if s { 216 | return 1, nil 217 | } 218 | return 0, nil 219 | case nil: 220 | return 0, nil 221 | default: 222 | return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) 223 | } 224 | } 225 | 226 | // ToInt32E casts an interface to an int32 type. 227 | func ToInt32E(i interface{}) (int32, error) { 228 | i = indirect(i) 229 | 230 | switch s := i.(type) { 231 | case int: 232 | return int32(s), nil 233 | case int64: 234 | return int32(s), nil 235 | case int32: 236 | return s, nil 237 | case int16: 238 | return int32(s), nil 239 | case int8: 240 | return int32(s), nil 241 | case uint: 242 | return int32(s), nil 243 | case uint64: 244 | return int32(s), nil 245 | case uint32: 246 | return int32(s), nil 247 | case uint16: 248 | return int32(s), nil 249 | case uint8: 250 | return int32(s), nil 251 | case float64: 252 | return int32(s), nil 253 | case float32: 254 | return int32(s), nil 255 | case string: 256 | v, err := strconv.ParseInt(s, 0, 0) 257 | if err == nil { 258 | return int32(v), nil 259 | } 260 | return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) 261 | case bool: 262 | if s { 263 | return 1, nil 264 | } 265 | return 0, nil 266 | case nil: 267 | return 0, nil 268 | default: 269 | return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) 270 | } 271 | } 272 | 273 | // ToInt16E casts an interface to an int16 type. 274 | func ToInt16E(i interface{}) (int16, error) { 275 | i = indirect(i) 276 | 277 | switch s := i.(type) { 278 | case int: 279 | return int16(s), nil 280 | case int64: 281 | return int16(s), nil 282 | case int32: 283 | return int16(s), nil 284 | case int16: 285 | return s, nil 286 | case int8: 287 | return int16(s), nil 288 | case uint: 289 | return int16(s), nil 290 | case uint64: 291 | return int16(s), nil 292 | case uint32: 293 | return int16(s), nil 294 | case uint16: 295 | return int16(s), nil 296 | case uint8: 297 | return int16(s), nil 298 | case float64: 299 | return int16(s), nil 300 | case float32: 301 | return int16(s), nil 302 | case string: 303 | v, err := strconv.ParseInt(s, 0, 0) 304 | if err == nil { 305 | return int16(v), nil 306 | } 307 | return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) 308 | case bool: 309 | if s { 310 | return 1, nil 311 | } 312 | return 0, nil 313 | case nil: 314 | return 0, nil 315 | default: 316 | return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) 317 | } 318 | } 319 | 320 | // ToInt8E casts an interface to an int8 type. 321 | func ToInt8E(i interface{}) (int8, error) { 322 | i = indirect(i) 323 | 324 | switch s := i.(type) { 325 | case int: 326 | return int8(s), nil 327 | case int64: 328 | return int8(s), nil 329 | case int32: 330 | return int8(s), nil 331 | case int16: 332 | return int8(s), nil 333 | case int8: 334 | return s, nil 335 | case uint: 336 | return int8(s), nil 337 | case uint64: 338 | return int8(s), nil 339 | case uint32: 340 | return int8(s), nil 341 | case uint16: 342 | return int8(s), nil 343 | case uint8: 344 | return int8(s), nil 345 | case float64: 346 | return int8(s), nil 347 | case float32: 348 | return int8(s), nil 349 | case string: 350 | v, err := strconv.ParseInt(s, 0, 0) 351 | if err == nil { 352 | return int8(v), nil 353 | } 354 | return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) 355 | case bool: 356 | if s { 357 | return 1, nil 358 | } 359 | return 0, nil 360 | case nil: 361 | return 0, nil 362 | default: 363 | return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) 364 | } 365 | } 366 | 367 | // ToIntE casts an interface to an int type. 368 | func ToIntE(i interface{}) (int, error) { 369 | i = indirect(i) 370 | 371 | switch s := i.(type) { 372 | case int: 373 | return s, nil 374 | case int64: 375 | return int(s), nil 376 | case int32: 377 | return int(s), nil 378 | case int16: 379 | return int(s), nil 380 | case int8: 381 | return int(s), nil 382 | case uint: 383 | return int(s), nil 384 | case uint64: 385 | return int(s), nil 386 | case uint32: 387 | return int(s), nil 388 | case uint16: 389 | return int(s), nil 390 | case uint8: 391 | return int(s), nil 392 | case float64: 393 | return int(s), nil 394 | case float32: 395 | return int(s), nil 396 | case string: 397 | v, err := strconv.ParseInt(s, 0, 0) 398 | if err == nil { 399 | return int(v), nil 400 | } 401 | return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i) 402 | case bool: 403 | if s { 404 | return 1, nil 405 | } 406 | return 0, nil 407 | case nil: 408 | return 0, nil 409 | default: 410 | return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i) 411 | } 412 | } 413 | 414 | // ToUintE casts an interface to a uint type. 415 | func ToUintE(i interface{}) (uint, error) { 416 | i = indirect(i) 417 | 418 | switch s := i.(type) { 419 | case string: 420 | v, err := strconv.ParseUint(s, 0, 0) 421 | if err == nil { 422 | return uint(v), nil 423 | } 424 | return 0, fmt.Errorf("unable to cast %#v to uint: %s", i, err) 425 | case int: 426 | if s < 0 { 427 | return 0, errNegativeNotAllowed 428 | } 429 | return uint(s), nil 430 | case int64: 431 | if s < 0 { 432 | return 0, errNegativeNotAllowed 433 | } 434 | return uint(s), nil 435 | case int32: 436 | if s < 0 { 437 | return 0, errNegativeNotAllowed 438 | } 439 | return uint(s), nil 440 | case int16: 441 | if s < 0 { 442 | return 0, errNegativeNotAllowed 443 | } 444 | return uint(s), nil 445 | case int8: 446 | if s < 0 { 447 | return 0, errNegativeNotAllowed 448 | } 449 | return uint(s), nil 450 | case uint: 451 | return s, nil 452 | case uint64: 453 | return uint(s), nil 454 | case uint32: 455 | return uint(s), nil 456 | case uint16: 457 | return uint(s), nil 458 | case uint8: 459 | return uint(s), nil 460 | case float64: 461 | if s < 0 { 462 | return 0, errNegativeNotAllowed 463 | } 464 | return uint(s), nil 465 | case float32: 466 | if s < 0 { 467 | return 0, errNegativeNotAllowed 468 | } 469 | return uint(s), nil 470 | case bool: 471 | if s { 472 | return 1, nil 473 | } 474 | return 0, nil 475 | case nil: 476 | return 0, nil 477 | default: 478 | return 0, fmt.Errorf("unable to cast %#v of type %T to uint", i, i) 479 | } 480 | } 481 | 482 | // ToUint64E casts an interface to a uint64 type. 483 | func ToUint64E(i interface{}) (uint64, error) { 484 | i = indirect(i) 485 | 486 | switch s := i.(type) { 487 | case string: 488 | v, err := strconv.ParseUint(s, 0, 64) 489 | if err == nil { 490 | return v, nil 491 | } 492 | return 0, fmt.Errorf("unable to cast %#v to uint64: %s", i, err) 493 | case int: 494 | if s < 0 { 495 | return 0, errNegativeNotAllowed 496 | } 497 | return uint64(s), nil 498 | case int64: 499 | if s < 0 { 500 | return 0, errNegativeNotAllowed 501 | } 502 | return uint64(s), nil 503 | case int32: 504 | if s < 0 { 505 | return 0, errNegativeNotAllowed 506 | } 507 | return uint64(s), nil 508 | case int16: 509 | if s < 0 { 510 | return 0, errNegativeNotAllowed 511 | } 512 | return uint64(s), nil 513 | case int8: 514 | if s < 0 { 515 | return 0, errNegativeNotAllowed 516 | } 517 | return uint64(s), nil 518 | case uint: 519 | return uint64(s), nil 520 | case uint64: 521 | return s, nil 522 | case uint32: 523 | return uint64(s), nil 524 | case uint16: 525 | return uint64(s), nil 526 | case uint8: 527 | return uint64(s), nil 528 | case float32: 529 | if s < 0 { 530 | return 0, errNegativeNotAllowed 531 | } 532 | return uint64(s), nil 533 | case float64: 534 | if s < 0 { 535 | return 0, errNegativeNotAllowed 536 | } 537 | return uint64(s), nil 538 | case bool: 539 | if s { 540 | return 1, nil 541 | } 542 | return 0, nil 543 | case nil: 544 | return 0, nil 545 | default: 546 | return 0, fmt.Errorf("unable to cast %#v of type %T to uint64", i, i) 547 | } 548 | } 549 | 550 | // ToUint32E casts an interface to a uint32 type. 551 | func ToUint32E(i interface{}) (uint32, error) { 552 | i = indirect(i) 553 | 554 | switch s := i.(type) { 555 | case string: 556 | v, err := strconv.ParseUint(s, 0, 32) 557 | if err == nil { 558 | return uint32(v), nil 559 | } 560 | return 0, fmt.Errorf("unable to cast %#v to uint32: %s", i, err) 561 | case int: 562 | if s < 0 { 563 | return 0, errNegativeNotAllowed 564 | } 565 | return uint32(s), nil 566 | case int64: 567 | if s < 0 { 568 | return 0, errNegativeNotAllowed 569 | } 570 | return uint32(s), nil 571 | case int32: 572 | if s < 0 { 573 | return 0, errNegativeNotAllowed 574 | } 575 | return uint32(s), nil 576 | case int16: 577 | if s < 0 { 578 | return 0, errNegativeNotAllowed 579 | } 580 | return uint32(s), nil 581 | case int8: 582 | if s < 0 { 583 | return 0, errNegativeNotAllowed 584 | } 585 | return uint32(s), nil 586 | case uint: 587 | return uint32(s), nil 588 | case uint64: 589 | return uint32(s), nil 590 | case uint32: 591 | return s, nil 592 | case uint16: 593 | return uint32(s), nil 594 | case uint8: 595 | return uint32(s), nil 596 | case float64: 597 | if s < 0 { 598 | return 0, errNegativeNotAllowed 599 | } 600 | return uint32(s), nil 601 | case float32: 602 | if s < 0 { 603 | return 0, errNegativeNotAllowed 604 | } 605 | return uint32(s), nil 606 | case bool: 607 | if s { 608 | return 1, nil 609 | } 610 | return 0, nil 611 | case nil: 612 | return 0, nil 613 | default: 614 | return 0, fmt.Errorf("unable to cast %#v of type %T to uint32", i, i) 615 | } 616 | } 617 | 618 | // ToUint16E casts an interface to a uint16 type. 619 | func ToUint16E(i interface{}) (uint16, error) { 620 | i = indirect(i) 621 | 622 | switch s := i.(type) { 623 | case string: 624 | v, err := strconv.ParseUint(s, 0, 16) 625 | if err == nil { 626 | return uint16(v), nil 627 | } 628 | return 0, fmt.Errorf("unable to cast %#v to uint16: %s", i, err) 629 | case int: 630 | if s < 0 { 631 | return 0, errNegativeNotAllowed 632 | } 633 | return uint16(s), nil 634 | case int64: 635 | if s < 0 { 636 | return 0, errNegativeNotAllowed 637 | } 638 | return uint16(s), nil 639 | case int32: 640 | if s < 0 { 641 | return 0, errNegativeNotAllowed 642 | } 643 | return uint16(s), nil 644 | case int16: 645 | if s < 0 { 646 | return 0, errNegativeNotAllowed 647 | } 648 | return uint16(s), nil 649 | case int8: 650 | if s < 0 { 651 | return 0, errNegativeNotAllowed 652 | } 653 | return uint16(s), nil 654 | case uint: 655 | return uint16(s), nil 656 | case uint64: 657 | return uint16(s), nil 658 | case uint32: 659 | return uint16(s), nil 660 | case uint16: 661 | return s, nil 662 | case uint8: 663 | return uint16(s), nil 664 | case float64: 665 | if s < 0 { 666 | return 0, errNegativeNotAllowed 667 | } 668 | return uint16(s), nil 669 | case float32: 670 | if s < 0 { 671 | return 0, errNegativeNotAllowed 672 | } 673 | return uint16(s), nil 674 | case bool: 675 | if s { 676 | return 1, nil 677 | } 678 | return 0, nil 679 | case nil: 680 | return 0, nil 681 | default: 682 | return 0, fmt.Errorf("unable to cast %#v of type %T to uint16", i, i) 683 | } 684 | } 685 | 686 | // ToUint8E casts an interface to a uint type. 687 | func ToUint8E(i interface{}) (uint8, error) { 688 | i = indirect(i) 689 | 690 | switch s := i.(type) { 691 | case string: 692 | v, err := strconv.ParseUint(s, 0, 8) 693 | if err == nil { 694 | return uint8(v), nil 695 | } 696 | return 0, fmt.Errorf("unable to cast %#v to uint8: %s", i, err) 697 | case int: 698 | if s < 0 { 699 | return 0, errNegativeNotAllowed 700 | } 701 | return uint8(s), nil 702 | case int64: 703 | if s < 0 { 704 | return 0, errNegativeNotAllowed 705 | } 706 | return uint8(s), nil 707 | case int32: 708 | if s < 0 { 709 | return 0, errNegativeNotAllowed 710 | } 711 | return uint8(s), nil 712 | case int16: 713 | if s < 0 { 714 | return 0, errNegativeNotAllowed 715 | } 716 | return uint8(s), nil 717 | case int8: 718 | if s < 0 { 719 | return 0, errNegativeNotAllowed 720 | } 721 | return uint8(s), nil 722 | case uint: 723 | return uint8(s), nil 724 | case uint64: 725 | return uint8(s), nil 726 | case uint32: 727 | return uint8(s), nil 728 | case uint16: 729 | return uint8(s), nil 730 | case uint8: 731 | return s, nil 732 | case float64: 733 | if s < 0 { 734 | return 0, errNegativeNotAllowed 735 | } 736 | return uint8(s), nil 737 | case float32: 738 | if s < 0 { 739 | return 0, errNegativeNotAllowed 740 | } 741 | return uint8(s), nil 742 | case bool: 743 | if s { 744 | return 1, nil 745 | } 746 | return 0, nil 747 | case nil: 748 | return 0, nil 749 | default: 750 | return 0, fmt.Errorf("unable to cast %#v of type %T to uint8", i, i) 751 | } 752 | } 753 | 754 | // From html/template/content.go 755 | // Copyright 2011 The Go Authors. All rights reserved. 756 | // indirect returns the value, after dereferencing as many times 757 | // as necessary to reach the base type (or nil). 758 | func indirect(a interface{}) interface{} { 759 | if a == nil { 760 | return nil 761 | } 762 | if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { 763 | // Avoid creating a reflect.Value if it's not a pointer. 764 | return a 765 | } 766 | v := reflect.ValueOf(a) 767 | for v.Kind() == reflect.Ptr && !v.IsNil() { 768 | v = v.Elem() 769 | } 770 | return v.Interface() 771 | } 772 | 773 | // From html/template/content.go 774 | // Copyright 2011 The Go Authors. All rights reserved. 775 | // indirectToStringerOrError returns the value, after dereferencing as many times 776 | // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer 777 | // or error, 778 | func indirectToStringerOrError(a interface{}) interface{} { 779 | if a == nil { 780 | return nil 781 | } 782 | 783 | var errorType = reflect.TypeOf((*error)(nil)).Elem() 784 | var fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() 785 | 786 | v := reflect.ValueOf(a) 787 | for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { 788 | v = v.Elem() 789 | } 790 | return v.Interface() 791 | } 792 | 793 | // ToStringE casts an interface to a string type. 794 | func ToStringE(i interface{}) (string, error) { 795 | i = indirectToStringerOrError(i) 796 | 797 | switch s := i.(type) { 798 | case string: 799 | return s, nil 800 | case bool: 801 | return strconv.FormatBool(s), nil 802 | case float64: 803 | return strconv.FormatFloat(s, 'f', -1, 64), nil 804 | case float32: 805 | return strconv.FormatFloat(float64(s), 'f', -1, 32), nil 806 | case int: 807 | return strconv.Itoa(s), nil 808 | case int64: 809 | return strconv.FormatInt(s, 10), nil 810 | case int32: 811 | return strconv.Itoa(int(s)), nil 812 | case int16: 813 | return strconv.FormatInt(int64(s), 10), nil 814 | case int8: 815 | return strconv.FormatInt(int64(s), 10), nil 816 | case uint: 817 | return strconv.FormatInt(int64(s), 10), nil 818 | case uint64: 819 | return strconv.FormatInt(int64(s), 10), nil 820 | case uint32: 821 | return strconv.FormatInt(int64(s), 10), nil 822 | case uint16: 823 | return strconv.FormatInt(int64(s), 10), nil 824 | case uint8: 825 | return strconv.FormatInt(int64(s), 10), nil 826 | case []byte: 827 | return string(s), nil 828 | case template.HTML: 829 | return string(s), nil 830 | case template.URL: 831 | return string(s), nil 832 | case template.JS: 833 | return string(s), nil 834 | case template.CSS: 835 | return string(s), nil 836 | case template.HTMLAttr: 837 | return string(s), nil 838 | case nil: 839 | return "", nil 840 | case fmt.Stringer: 841 | return s.String(), nil 842 | case error: 843 | return s.Error(), nil 844 | default: 845 | return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i) 846 | } 847 | } 848 | 849 | // ToStringMapStringE casts an interface to a map[string]string type. 850 | func ToStringMapStringE(i interface{}) (map[string]string, error) { 851 | var m = map[string]string{} 852 | 853 | switch v := i.(type) { 854 | case map[string]string: 855 | return v, nil 856 | case map[string]interface{}: 857 | for k, val := range v { 858 | m[ToString(k)] = ToString(val) 859 | } 860 | return m, nil 861 | case map[interface{}]string: 862 | for k, val := range v { 863 | m[ToString(k)] = ToString(val) 864 | } 865 | return m, nil 866 | case map[interface{}]interface{}: 867 | for k, val := range v { 868 | m[ToString(k)] = ToString(val) 869 | } 870 | return m, nil 871 | case string: 872 | err := jsonStringToObject(v, &m) 873 | return m, err 874 | default: 875 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]string", i, i) 876 | } 877 | } 878 | 879 | // ToStringMapStringSliceE casts an interface to a map[string][]string type. 880 | func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) { 881 | var m = map[string][]string{} 882 | 883 | switch v := i.(type) { 884 | case map[string][]string: 885 | return v, nil 886 | case map[string][]interface{}: 887 | for k, val := range v { 888 | m[ToString(k)] = ToStringSlice(val) 889 | } 890 | return m, nil 891 | case map[string]string: 892 | for k, val := range v { 893 | m[ToString(k)] = []string{val} 894 | } 895 | case map[string]interface{}: 896 | for k, val := range v { 897 | switch vt := val.(type) { 898 | case []interface{}: 899 | m[ToString(k)] = ToStringSlice(vt) 900 | case []string: 901 | m[ToString(k)] = vt 902 | default: 903 | m[ToString(k)] = []string{ToString(val)} 904 | } 905 | } 906 | return m, nil 907 | case map[interface{}][]string: 908 | for k, val := range v { 909 | m[ToString(k)] = ToStringSlice(val) 910 | } 911 | return m, nil 912 | case map[interface{}]string: 913 | for k, val := range v { 914 | m[ToString(k)] = ToStringSlice(val) 915 | } 916 | return m, nil 917 | case map[interface{}][]interface{}: 918 | for k, val := range v { 919 | m[ToString(k)] = ToStringSlice(val) 920 | } 921 | return m, nil 922 | case map[interface{}]interface{}: 923 | for k, val := range v { 924 | key, err := ToStringE(k) 925 | if err != nil { 926 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) 927 | } 928 | value, err := ToStringSliceE(val) 929 | if err != nil { 930 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) 931 | } 932 | m[key] = value 933 | } 934 | case string: 935 | err := jsonStringToObject(v, &m) 936 | return m, err 937 | default: 938 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) 939 | } 940 | return m, nil 941 | } 942 | 943 | // ToStringMapBoolE casts an interface to a map[string]bool type. 944 | func ToStringMapBoolE(i interface{}) (map[string]bool, error) { 945 | var m = map[string]bool{} 946 | 947 | switch v := i.(type) { 948 | case map[interface{}]interface{}: 949 | for k, val := range v { 950 | m[ToString(k)] = ToBool(val) 951 | } 952 | return m, nil 953 | case map[string]interface{}: 954 | for k, val := range v { 955 | m[ToString(k)] = ToBool(val) 956 | } 957 | return m, nil 958 | case map[string]bool: 959 | return v, nil 960 | case string: 961 | err := jsonStringToObject(v, &m) 962 | return m, err 963 | default: 964 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]bool", i, i) 965 | } 966 | } 967 | 968 | // ToStringMapE casts an interface to a map[string]interface{} type. 969 | func ToStringMapE(i interface{}) (map[string]interface{}, error) { 970 | var m = map[string]interface{}{} 971 | 972 | switch v := i.(type) { 973 | case map[interface{}]interface{}: 974 | for k, val := range v { 975 | m[ToString(k)] = val 976 | } 977 | return m, nil 978 | case map[string]interface{}: 979 | return v, nil 980 | case string: 981 | err := jsonStringToObject(v, &m) 982 | return m, err 983 | default: 984 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]interface{}", i, i) 985 | } 986 | } 987 | 988 | // ToStringMapIntE casts an interface to a map[string]int{} type. 989 | func ToStringMapIntE(i interface{}) (map[string]int, error) { 990 | var m = map[string]int{} 991 | if i == nil { 992 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i) 993 | } 994 | 995 | switch v := i.(type) { 996 | case map[interface{}]interface{}: 997 | for k, val := range v { 998 | m[ToString(k)] = ToInt(val) 999 | } 1000 | return m, nil 1001 | case map[string]interface{}: 1002 | for k, val := range v { 1003 | m[k] = ToInt(val) 1004 | } 1005 | return m, nil 1006 | case map[string]int: 1007 | return v, nil 1008 | case string: 1009 | err := jsonStringToObject(v, &m) 1010 | return m, err 1011 | } 1012 | 1013 | if reflect.TypeOf(i).Kind() != reflect.Map { 1014 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i) 1015 | } 1016 | 1017 | mVal := reflect.ValueOf(m) 1018 | v := reflect.ValueOf(i) 1019 | for _, keyVal := range v.MapKeys() { 1020 | val, err := ToIntE(v.MapIndex(keyVal).Interface()) 1021 | if err != nil { 1022 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i) 1023 | } 1024 | mVal.SetMapIndex(keyVal, reflect.ValueOf(val)) 1025 | } 1026 | return m, nil 1027 | } 1028 | 1029 | // ToStringMapInt64E casts an interface to a map[string]int64{} type. 1030 | func ToStringMapInt64E(i interface{}) (map[string]int64, error) { 1031 | var m = map[string]int64{} 1032 | if i == nil { 1033 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i) 1034 | } 1035 | 1036 | switch v := i.(type) { 1037 | case map[interface{}]interface{}: 1038 | for k, val := range v { 1039 | m[ToString(k)] = ToInt64(val) 1040 | } 1041 | return m, nil 1042 | case map[string]interface{}: 1043 | for k, val := range v { 1044 | m[k] = ToInt64(val) 1045 | } 1046 | return m, nil 1047 | case map[string]int64: 1048 | return v, nil 1049 | case string: 1050 | err := jsonStringToObject(v, &m) 1051 | return m, err 1052 | } 1053 | 1054 | if reflect.TypeOf(i).Kind() != reflect.Map { 1055 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i) 1056 | } 1057 | mVal := reflect.ValueOf(m) 1058 | v := reflect.ValueOf(i) 1059 | for _, keyVal := range v.MapKeys() { 1060 | val, err := ToInt64E(v.MapIndex(keyVal).Interface()) 1061 | if err != nil { 1062 | return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i) 1063 | } 1064 | mVal.SetMapIndex(keyVal, reflect.ValueOf(val)) 1065 | } 1066 | return m, nil 1067 | } 1068 | 1069 | // ToSliceE casts an interface to a []interface{} type. 1070 | func ToSliceE(i interface{}) ([]interface{}, error) { 1071 | var s []interface{} 1072 | 1073 | switch v := i.(type) { 1074 | case []interface{}: 1075 | return append(s, v...), nil 1076 | case []map[string]interface{}: 1077 | for _, u := range v { 1078 | s = append(s, u) 1079 | } 1080 | return s, nil 1081 | default: 1082 | return s, fmt.Errorf("unable to cast %#v of type %T to []interface{}", i, i) 1083 | } 1084 | } 1085 | 1086 | // ToBoolSliceE casts an interface to a []bool type. 1087 | func ToBoolSliceE(i interface{}) ([]bool, error) { 1088 | if i == nil { 1089 | return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) 1090 | } 1091 | 1092 | switch v := i.(type) { 1093 | case []bool: 1094 | return v, nil 1095 | } 1096 | 1097 | kind := reflect.TypeOf(i).Kind() 1098 | switch kind { 1099 | case reflect.Slice, reflect.Array: 1100 | s := reflect.ValueOf(i) 1101 | a := make([]bool, s.Len()) 1102 | for j := 0; j < s.Len(); j++ { 1103 | val, err := ToBoolE(s.Index(j).Interface()) 1104 | if err != nil { 1105 | return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) 1106 | } 1107 | a[j] = val 1108 | } 1109 | return a, nil 1110 | default: 1111 | return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) 1112 | } 1113 | } 1114 | 1115 | // ToStringSliceE casts an interface to a []string type. 1116 | func ToStringSliceE(i interface{}) ([]string, error) { 1117 | var a []string 1118 | 1119 | switch v := i.(type) { 1120 | case []interface{}: 1121 | for _, u := range v { 1122 | a = append(a, ToString(u)) 1123 | } 1124 | return a, nil 1125 | case []string: 1126 | return v, nil 1127 | case string: 1128 | return strings.Fields(v), nil 1129 | case interface{}: 1130 | str, err := ToStringE(v) 1131 | if err != nil { 1132 | return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i) 1133 | } 1134 | return []string{str}, nil 1135 | default: 1136 | return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i) 1137 | } 1138 | } 1139 | 1140 | // ToIntSliceE casts an interface to a []int type. 1141 | func ToIntSliceE(i interface{}) ([]int, error) { 1142 | if i == nil { 1143 | return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) 1144 | } 1145 | 1146 | switch v := i.(type) { 1147 | case []int: 1148 | return v, nil 1149 | } 1150 | 1151 | kind := reflect.TypeOf(i).Kind() 1152 | switch kind { 1153 | case reflect.Slice, reflect.Array: 1154 | s := reflect.ValueOf(i) 1155 | a := make([]int, s.Len()) 1156 | for j := 0; j < s.Len(); j++ { 1157 | val, err := ToIntE(s.Index(j).Interface()) 1158 | if err != nil { 1159 | return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) 1160 | } 1161 | a[j] = val 1162 | } 1163 | return a, nil 1164 | default: 1165 | return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) 1166 | } 1167 | } 1168 | 1169 | // ToDurationSliceE casts an interface to a []time.Duration type. 1170 | func ToDurationSliceE(i interface{}) ([]time.Duration, error) { 1171 | if i == nil { 1172 | return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) 1173 | } 1174 | 1175 | switch v := i.(type) { 1176 | case []time.Duration: 1177 | return v, nil 1178 | } 1179 | 1180 | kind := reflect.TypeOf(i).Kind() 1181 | switch kind { 1182 | case reflect.Slice, reflect.Array: 1183 | s := reflect.ValueOf(i) 1184 | a := make([]time.Duration, s.Len()) 1185 | for j := 0; j < s.Len(); j++ { 1186 | val, err := ToDurationE(s.Index(j).Interface()) 1187 | if err != nil { 1188 | return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) 1189 | } 1190 | a[j] = val 1191 | } 1192 | return a, nil 1193 | default: 1194 | return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) 1195 | } 1196 | } 1197 | 1198 | // StringToDate attempts to parse a string into a time.Time type using a 1199 | // predefined list of formats. If no suitable format is found, an error is 1200 | // returned. 1201 | func StringToDate(s string) (time.Time, error) { 1202 | return parseDateWith(s, []string{ 1203 | time.RFC3339, 1204 | "2006-01-02T15:04:05", // iso8601 without timezone 1205 | time.RFC1123Z, 1206 | time.RFC1123, 1207 | time.RFC822Z, 1208 | time.RFC822, 1209 | time.RFC850, 1210 | time.ANSIC, 1211 | time.UnixDate, 1212 | time.RubyDate, 1213 | "2006-01-02 15:04:05.999999999 -0700 MST", // Time.String() 1214 | "2006-01-02", 1215 | "02 Jan 2006", 1216 | "2006-01-02T15:04:05-0700", // RFC3339 without timezone hh:mm colon 1217 | "2006-01-02 15:04:05 -07:00", 1218 | "2006-01-02 15:04:05 -0700", 1219 | "2006-01-02 15:04:05Z07:00", // RFC3339 without T 1220 | "2006-01-02 15:04:05Z0700", // RFC3339 without T or timezone hh:mm colon 1221 | "2006-01-02 15:04:05", 1222 | time.Kitchen, 1223 | time.Stamp, 1224 | time.StampMilli, 1225 | time.StampMicro, 1226 | time.StampNano, 1227 | }) 1228 | } 1229 | 1230 | func parseDateWith(s string, dates []string) (d time.Time, e error) { 1231 | for _, dateType := range dates { 1232 | if d, e = time.Parse(dateType, s); e == nil { 1233 | return 1234 | } 1235 | } 1236 | return d, fmt.Errorf("unable to parse date: %s", s) 1237 | } 1238 | 1239 | // jsonStringToObject attempts to unmarshall a string as JSON into 1240 | // the object passed as pointer. 1241 | func jsonStringToObject(s string, v interface{}) error { 1242 | data := []byte(s) 1243 | return json.Unmarshal(data, v) 1244 | } 1245 | -------------------------------------------------------------------------------- /appcode/fccserver/src/service/estatebook.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package service 18 | 19 | import ( 20 | "ccservice" 21 | "comm" 22 | "db" 23 | ) 24 | 25 | func EstateBookGetAll() (res comm.ResResult) { 26 | books, err := db.EstateBookAll() 27 | if err != nil { 28 | res.Code = 1 29 | res.Status = err.Error() 30 | } else { 31 | res.Code = 0 32 | res.Status = books 33 | } 34 | return 35 | } 36 | 37 | func EstateBookCreate(bookid, netconid, taxid, owener, addr string, area int) (res comm.ResResult) { 38 | err := db.EstateBookCreate(bookid, netconid, taxid, owener, addr, area, GetOperator()) 39 | if err != nil { 40 | res.Code = 1 41 | res.Status = err.Error() 42 | } else { 43 | res.Code = 0 44 | } 45 | return 46 | } 47 | 48 | func EstateBookToCC(uuid, bookid, owner, addr, area string) (res comm.ResResult) { 49 | res = ccservice.EstateBookCreate(uuid, bookid,owner, addr, area) 50 | if res.Code == 0 { 51 | err := db.EstateBookUpdateCC(uuid, 1) 52 | if err != nil { 53 | res.Code = 1 54 | res.Status = "上链成功,但更新业务数据库中的上链标志失败:" + err.Error() 55 | } 56 | } 57 | return 58 | } 59 | 60 | -------------------------------------------------------------------------------- /appcode/fccserver/src/service/estatetax.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package service 18 | 19 | import ( 20 | "ccservice" 21 | "comm" 22 | "db" 23 | ) 24 | 25 | func EstateTaxGetAll() (res comm.ResResult) { 26 | taxs, err := db.EstateTaxAll() 27 | if err != nil { 28 | res.Code = 1 29 | res.Status = err.Error() 30 | } else { 31 | res.Code = 0 32 | res.Status = taxs 33 | } 34 | return 35 | } 36 | 37 | func EstateTaxCreate(taxid, taxer string, area, tax int) (res comm.ResResult) { 38 | err := db.EstateTaxCreate(taxid, taxer, area, tax, GetOperator()) 39 | if err != nil { 40 | res.Code = 1 41 | res.Status = err.Error() 42 | } else { 43 | res.Code = 0 44 | } 45 | return 46 | } 47 | 48 | func EstateTaxToCC(uuid, taxid, taxer, area, tax string) (res comm.ResResult) { 49 | res = ccservice.EstateTaxCreate(uuid, taxid, "", taxer, area, tax) 50 | if res.Code == 0 { 51 | err := db.EstateTaxUpdateCC(uuid, 1) 52 | if err != nil { 53 | res.Code = 1 54 | res.Status = "上链成功,但更新业务数据库中的上链标志失败:" + err.Error() 55 | } 56 | } 57 | return 58 | } 59 | -------------------------------------------------------------------------------- /appcode/fccserver/src/service/netcon.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package service 18 | 19 | import ( 20 | "ccservice" 21 | "comm" 22 | "db" 23 | ) 24 | 25 | func NetconGetAll() (res comm.ResResult) { 26 | netcons, err := db.NetconsAll() 27 | if err != nil { 28 | res.Code = 1 29 | res.Status = err.Error() 30 | } else { 31 | res.Code = 0 32 | res.Status = netcons 33 | } 34 | return 35 | } 36 | 37 | func NetconCreate(netconid, applya, applyb, addr string, area, balance int) (res comm.ResResult) { 38 | err := db.NetconsCreate(netconid, applya, applyb, addr, area, balance, GetOperator()) 39 | if err != nil { 40 | res.Code = 1 41 | res.Status = err.Error() 42 | } else { 43 | res.Code = 0 44 | } 45 | return 46 | } 47 | 48 | func NetconToCC(uuid, netconid, applya, applyb, addr, area, balance string) (res comm.ResResult) { 49 | res = ccservice.NetconCreate(uuid, netconid, applya, applyb, addr, area, balance) 50 | if res.Code == 0 { 51 | err := db.NetconsUpdateCC(uuid, 1) 52 | if err != nil { 53 | res.Code = 1 54 | res.Status = "上链成功,但更新业务数据库中的上链标志失败:" + err.Error() 55 | } 56 | } 57 | return 58 | } 59 | -------------------------------------------------------------------------------- /appcode/fccserver/src/service/system.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright xujf000@gmail.com .2020. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package service 18 | 19 | import ( 20 | "ccservice" 21 | "db" 22 | ) 23 | 24 | // InitOnSystemStart 25 | func InitOnSystemStart() (err error) { 26 | err = db.InitDB() 27 | if err != nil { 28 | return 29 | } 30 | //for now ,if Chaincode service initial failed ,don't break startup process. 31 | // give system a chance to reinitial on later. 32 | ccservice.InitCCOnStart() 33 | return nil 34 | } 35 | 36 | //get current operator 37 | func GetOperator() string { 38 | return "SystemOperator1" 39 | } 40 | -------------------------------------------------------------------------------- /chaincode/estatebook/estatebook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/hyperledger/fabric/core/chaincode/shim" 8 | peer "github.com/hyperledger/fabric/protos/peer" 9 | "strconv" 10 | ) 11 | 12 | // Define the Smart Contract structure 13 | type EstateBookContract struct { 14 | } 15 | 16 | type EstateBook struct { 17 | BookID string `json:"bookid"` //不动产证书编号 18 | Owner string `json:"owner"` //户主 19 | Addr string `json:"addr"` //房屋地址 20 | Area int `json:"area"` //房屋面积 21 | } 22 | 23 | type RecordsInfo struct { 24 | Size uint64 25 | Start string 26 | End string 27 | } 28 | 29 | var key_recordinfo = "recordeinfo" 30 | var evn_estatebook = "evn_estatebook" 31 | 32 | func (s *EstateBookContract) Init(APIstub shim.ChaincodeStubInterface) peer.Response { 33 | return shim.Success(nil) 34 | } 35 | 36 | func (s *EstateBookContract) Invoke(APIstub shim.ChaincodeStubInterface) peer.Response { 37 | function, args := APIstub.GetFunctionAndParameters() 38 | switch function { 39 | case "create": 40 | return s.create(APIstub, args) 41 | case "queryByBookID": 42 | return s.queryByBookID(APIstub, args) 43 | case "queryByPara": 44 | return s.queryByPara(APIstub, args) 45 | case "queryAll": 46 | return s.queryAll(APIstub, args) 47 | default: 48 | return shim.Error("Invalid Smart Contract function name.") 49 | } 50 | } 51 | 52 | func (s *EstateBookContract) create(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 53 | if len(args) != 5 { 54 | return shim.Error("Incorrect number of arguments. Expecting 5. ") 55 | } 56 | key := args[0] 57 | area, err := strconv.Atoi(args[4]) 58 | if err != nil { 59 | return shim.Error("area value wrong.") 60 | } 61 | estateBook := &EstateBook{ 62 | BookID: args[1], 63 | Owner: args[2], 64 | Addr: args[3], 65 | Area: area, 66 | } 67 | jsBytes, err := json.Marshal(estateBook) 68 | if err != nil { 69 | return shim.Error("marshal json error:" + err.Error()) 70 | } 71 | err = APIstub.PutState(key, jsBytes) 72 | if err != nil { 73 | return shim.Error("error on putstate:" + err.Error()) 74 | } 75 | //update recodeinfo 76 | recordInfo := &RecordsInfo{} 77 | rebs, err := APIstub.GetState(key_recordinfo) 78 | if len(rebs) == 0 { 79 | recordInfo.Size = 1 80 | recordInfo.Start = key 81 | recordInfo.End = key 82 | } else { 83 | err = json.Unmarshal(rebs, &recordInfo) 84 | if err != nil { 85 | return shim.Error("error on unmarsh recorderinfo:" + err.Error()) 86 | } 87 | recordInfo.Size = recordInfo.Size + 1 88 | recordInfo.End = key 89 | } 90 | rebs, err = json.Marshal(recordInfo) 91 | if err != nil { 92 | return shim.Error("error on marsh new recorderinfo:" + err.Error()) 93 | } 94 | err = APIstub.PutState(key_recordinfo, rebs) 95 | if err != nil { 96 | return shim.Error("error on put new recorderinfo:" + err.Error()) 97 | } 98 | //broadcast event 99 | err = APIstub.SetEvent(evn_estatebook, []byte("new estatebook created with key:"+key)) 100 | if err != nil { 101 | return shim.Error(err.Error()) 102 | } 103 | return shim.Success([]byte("new estatebook created with key:" + key)) 104 | } 105 | 106 | func (s *EstateBookContract) queryByBookID(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 107 | if len(args) != 1 { 108 | return shim.Error("Incorrect number of arguments. Expecting 1 ") 109 | } 110 | queryString := fmt.Sprintf("{\"selector\":{\"bookid\":\"%s\"}}", args[0]) 111 | qis, err := APIstub.GetQueryResult(queryString) 112 | if err != nil { 113 | return shim.Error("queryByBookID error:" + err.Error()) 114 | } 115 | defer qis.Close() 116 | var buffer bytes.Buffer 117 | buffer.WriteString("[") 118 | bArrayMemberAlreadyWritten := false 119 | for qis.HasNext() { 120 | queryResponse, err := qis.Next() 121 | if err != nil { 122 | return shim.Error(err.Error()) 123 | } 124 | if bArrayMemberAlreadyWritten == true { 125 | buffer.WriteString(",") 126 | } 127 | buffer.WriteString(string(queryResponse.Value)) 128 | bArrayMemberAlreadyWritten = true 129 | } 130 | buffer.WriteString("]") 131 | return shim.Success(buffer.Bytes()) 132 | } 133 | 134 | func (s *EstateBookContract) queryByPara(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 135 | if len(args) != 2 { 136 | return shim.Error("Incorrect number of arguments. Expecting 2 ") 137 | } 138 | queryString := fmt.Sprintf("{\"selector\":{\""+args[0]+"\":\"%s\"}}", args[1]) 139 | qis, err := APIstub.GetQueryResult(queryString) 140 | if err != nil { 141 | return shim.Error("queryByPara error:" + err.Error()) 142 | } 143 | defer qis.Close() 144 | resultsIterator, err := APIstub.GetQueryResult(queryString) 145 | if err != nil { 146 | return shim.Error(err.Error()) 147 | } 148 | defer resultsIterator.Close() 149 | 150 | var buffer bytes.Buffer 151 | buffer.WriteString("[") 152 | bArrayMemberAlreadyWritten := false 153 | for resultsIterator.HasNext() { 154 | queryResponse, err := resultsIterator.Next() 155 | if err != nil { 156 | return shim.Error(err.Error()) 157 | } 158 | if bArrayMemberAlreadyWritten == true { 159 | buffer.WriteString(",") 160 | } 161 | buffer.WriteString(string(queryResponse.Value)) 162 | bArrayMemberAlreadyWritten = true 163 | } 164 | buffer.WriteString("]") 165 | return shim.Success(buffer.Bytes()) 166 | } 167 | 168 | func (s *EstateBookContract) queryAll(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 169 | rebs, err := APIstub.GetState(key_recordinfo) 170 | if err != nil { 171 | return shim.Error("error on get recorderinfo:" + err.Error()) 172 | } 173 | recordInfo := &RecordsInfo{} 174 | if len(rebs) == 0 { 175 | return shim.Success([]byte{}) 176 | } 177 | err = json.Unmarshal(rebs, &recordInfo) 178 | if err != nil { 179 | return shim.Error("error on unmarsh recorderinfo:" + err.Error()) 180 | } 181 | resultsIterator, err := APIstub.GetStateByRange(recordInfo.Start, recordInfo.End+"1") 182 | if err != nil { 183 | return shim.Error(err.Error()) 184 | } 185 | defer resultsIterator.Close() 186 | 187 | var buffer bytes.Buffer 188 | buffer.WriteString("[") 189 | bArrayMemberAlreadyWritten := false 190 | for resultsIterator.HasNext() { 191 | queryResponse, err := resultsIterator.Next() 192 | if err != nil { 193 | return shim.Error(err.Error()) 194 | } 195 | if bArrayMemberAlreadyWritten == true { 196 | buffer.WriteString(",") 197 | } 198 | buffer.WriteString(string(queryResponse.Value)) 199 | bArrayMemberAlreadyWritten = true 200 | } 201 | buffer.WriteString("]") 202 | println("size:" + strconv.FormatUint(recordInfo.Size, 10) + " start:" + recordInfo.Start + " end:" + recordInfo.End) 203 | return shim.Success(buffer.Bytes()) 204 | } 205 | 206 | func main() { 207 | err := shim.Start(new(EstateBookContract)) 208 | if err != nil { 209 | fmt.Printf("Error creating new Smart Contract: %s", err) 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /chaincode/estatetax/estatetax.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/hyperledger/fabric/core/chaincode/shim" 8 | peer "github.com/hyperledger/fabric/protos/peer" 9 | "strconv" 10 | ) 11 | 12 | // Define the Smart Contract structure 13 | type EstateTaxContract struct { 14 | } 15 | 16 | type EstateTax struct { 17 | TaxID string `json:"taxid"` //核税编号 18 | BookID string `json:"bookid"` //不动产权证书编号 19 | Taxer string `json:"taxer"` //纳税人 20 | Area int `json:"area"` //房屋面积 21 | Tax int `json:"tax"` //纳税金额 22 | } 23 | 24 | type RecordsInfo struct { 25 | Size uint64 26 | Start string 27 | End string 28 | } 29 | 30 | var key_recordinfo = "recordeinfo" 31 | var evn_estatetax = "evn_estatetax" 32 | 33 | func (s *EstateTaxContract) Init(APIstub shim.ChaincodeStubInterface) peer.Response { 34 | return shim.Success(nil) 35 | } 36 | 37 | func (s *EstateTaxContract) Invoke(APIstub shim.ChaincodeStubInterface) peer.Response { 38 | function, args := APIstub.GetFunctionAndParameters() 39 | switch function { 40 | case "create": 41 | return s.create(APIstub, args) 42 | case "queryByTaxID": 43 | return s.queryByTaxID(APIstub, args) 44 | case "queryByPara": 45 | return s.queryByPara(APIstub, args) 46 | case "queryAll": 47 | return s.queryAll(APIstub, args) 48 | default: 49 | return shim.Error("Invalid Smart Contract function name.") 50 | } 51 | } 52 | 53 | func (s *EstateTaxContract) create(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 54 | if len(args) != 6 { 55 | return shim.Error("Incorrect number of arguments. Expecting 6. ") 56 | } 57 | key := args[0] 58 | area, err := strconv.Atoi(args[4]) 59 | if err != nil { 60 | return shim.Error("area value wrong.") 61 | } 62 | tax, err := strconv.Atoi(args[5]) 63 | if err != nil { 64 | return shim.Error("area value wrong.") 65 | } 66 | EstateTax := &EstateTax{ 67 | TaxID: args[1], 68 | BookID: args[2], 69 | Taxer: args[3], 70 | Area: area, 71 | Tax: tax, 72 | } 73 | jsBytes, err := json.Marshal(EstateTax) 74 | if err != nil { 75 | return shim.Error("marshal json error:" + err.Error()) 76 | } 77 | err = APIstub.PutState(key, jsBytes) 78 | if err != nil { 79 | return shim.Error("error on putstate:" + err.Error()) 80 | } 81 | //update recodeinfo 82 | recordInfo := &RecordsInfo{} 83 | rebs, err := APIstub.GetState(key_recordinfo) 84 | if len(rebs) == 0 { 85 | recordInfo.Size = 1 86 | recordInfo.Start = key 87 | recordInfo.End = key 88 | } else { 89 | err = json.Unmarshal(rebs, &recordInfo) 90 | if err != nil { 91 | return shim.Error("error on unmarsh recorderinfo:" + err.Error()) 92 | } 93 | recordInfo.Size = recordInfo.Size + 1 94 | recordInfo.End = key 95 | } 96 | rebs, err = json.Marshal(recordInfo) 97 | if err != nil { 98 | return shim.Error("error on marsh new recorderinfo:" + err.Error()) 99 | } 100 | err = APIstub.PutState(key_recordinfo, rebs) 101 | if err != nil { 102 | return shim.Error("error on put new recorderinfo:" + err.Error()) 103 | } 104 | //broadcast event 105 | err = APIstub.SetEvent(evn_estatetax, []byte("new EstateTax created with key:"+key)) 106 | if err != nil { 107 | return shim.Error(err.Error()) 108 | } 109 | return shim.Success([]byte("new EstateTax created with key:" + key)) 110 | } 111 | 112 | func (s *EstateTaxContract) queryByTaxID(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 113 | if len(args) != 1 { 114 | return shim.Error("Incorrect number of arguments. Expecting 1 ") 115 | } 116 | queryString := fmt.Sprintf("{\"selector\":{\"taxid\":\"%s\"}}", args[0]) 117 | qis, err := APIstub.GetQueryResult(queryString) 118 | if err != nil { 119 | return shim.Error("queryByTaxID error:" + err.Error()) 120 | } 121 | defer qis.Close() 122 | var buffer bytes.Buffer 123 | buffer.WriteString("[") 124 | bArrayMemberAlreadyWritten := false 125 | for qis.HasNext() { 126 | queryResponse, err := qis.Next() 127 | if err != nil { 128 | return shim.Error(err.Error()) 129 | } 130 | if bArrayMemberAlreadyWritten == true { 131 | buffer.WriteString(",") 132 | } 133 | buffer.WriteString(string(queryResponse.Value)) 134 | bArrayMemberAlreadyWritten = true 135 | } 136 | buffer.WriteString("]") 137 | return shim.Success(buffer.Bytes()) 138 | } 139 | 140 | func (s *EstateTaxContract) queryByPara(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 141 | if len(args) != 2 { 142 | return shim.Error("Incorrect number of arguments. Expecting 2 ") 143 | } 144 | queryString := fmt.Sprintf("{\"selector\":{\""+args[0]+"\":\"%s\"}}", args[1]) 145 | qis, err := APIstub.GetQueryResult(queryString) 146 | if err != nil { 147 | return shim.Error("queryByPara error:" + err.Error()) 148 | } 149 | defer qis.Close() 150 | resultsIterator, err := APIstub.GetQueryResult(queryString) 151 | if err != nil { 152 | return shim.Error(err.Error()) 153 | } 154 | defer resultsIterator.Close() 155 | 156 | var buffer bytes.Buffer 157 | buffer.WriteString("[") 158 | bArrayMemberAlreadyWritten := false 159 | for resultsIterator.HasNext() { 160 | queryResponse, err := resultsIterator.Next() 161 | if err != nil { 162 | return shim.Error(err.Error()) 163 | } 164 | if bArrayMemberAlreadyWritten == true { 165 | buffer.WriteString(",") 166 | } 167 | buffer.WriteString(string(queryResponse.Value)) 168 | bArrayMemberAlreadyWritten = true 169 | } 170 | buffer.WriteString("]") 171 | return shim.Success(buffer.Bytes()) 172 | } 173 | 174 | func (s *EstateTaxContract) queryAll(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 175 | rebs, err := APIstub.GetState(key_recordinfo) 176 | if err != nil { 177 | return shim.Error("error on get recorderinfo:" + err.Error()) 178 | } 179 | recordInfo := &RecordsInfo{} 180 | if len(rebs) == 0 { 181 | return shim.Success([]byte{}) 182 | } 183 | err = json.Unmarshal(rebs, &recordInfo) 184 | if err != nil { 185 | return shim.Error("error on unmarsh recorderinfo:" + err.Error()) 186 | } 187 | resultsIterator, err := APIstub.GetStateByRange(recordInfo.Start, recordInfo.End+"1") 188 | if err != nil { 189 | return shim.Error(err.Error()) 190 | } 191 | defer resultsIterator.Close() 192 | 193 | var buffer bytes.Buffer 194 | buffer.WriteString("[") 195 | bArrayMemberAlreadyWritten := false 196 | for resultsIterator.HasNext() { 197 | queryResponse, err := resultsIterator.Next() 198 | if err != nil { 199 | return shim.Error(err.Error()) 200 | } 201 | if bArrayMemberAlreadyWritten == true { 202 | buffer.WriteString(",") 203 | } 204 | buffer.WriteString(string(queryResponse.Value)) 205 | bArrayMemberAlreadyWritten = true 206 | } 207 | buffer.WriteString("]") 208 | println(" size:" + strconv.FormatUint(recordInfo.Size, 10) + " start:" + recordInfo.Start + " end:" + recordInfo.End) 209 | return shim.Success(buffer.Bytes()) 210 | } 211 | 212 | func main() { 213 | err := shim.Start(new(EstateTaxContract)) 214 | if err != nil { 215 | fmt.Printf("Error creating new Smart Contract: %s", err) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /chaincode/netcon/netcon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/hyperledger/fabric/core/chaincode/shim" 8 | peer "github.com/hyperledger/fabric/protos/peer" 9 | "strconv" 10 | ) 11 | 12 | // Define the Smart Contract structure 13 | type NetconContract struct { 14 | } 15 | 16 | type Netcon struct { 17 | NetconID string `json:"netconid"` //合同编号 18 | ApplyA string `json:"applya"` //受让方(买方) 19 | ApplyB string `json:"applyb"` //转让方(卖方) 20 | Addr string `json:"addr"` //房屋地址 21 | Area int `json:"area"` //房屋面积 22 | Balance int `json:"balance"` //转让金额 23 | } 24 | 25 | type RecordsInfo struct { 26 | Size uint64 27 | Start string 28 | End string 29 | } 30 | 31 | var key_recordinfo = "recordeinfo" 32 | var evn_netcon = "evn_netcon" 33 | 34 | func (s *NetconContract) Init(APIstub shim.ChaincodeStubInterface) peer.Response { 35 | return shim.Success(nil) 36 | } 37 | 38 | func (s *NetconContract) Invoke(APIstub shim.ChaincodeStubInterface) peer.Response { 39 | function, args := APIstub.GetFunctionAndParameters() 40 | switch function { 41 | case "create": 42 | return s.create(APIstub, args) 43 | case "queryByNetconID": 44 | return s.queryByNetconID(APIstub, args) 45 | case "queryByPara": 46 | return s.queryByPara(APIstub, args) 47 | case "queryAll": 48 | return s.queryAll(APIstub, args) 49 | default: 50 | return shim.Error("Invalid Smart Contract function name.") 51 | } 52 | } 53 | 54 | func (s *NetconContract) create(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 55 | if len(args) != 7 { 56 | return shim.Error("Incorrect number of arguments. Expecting 7. ") 57 | } 58 | area, err := strconv.Atoi(args[5]) 59 | if err != nil { 60 | return shim.Error("area value wrong.") 61 | } 62 | balance, err := strconv.Atoi(args[6]) 63 | if err != nil { 64 | return shim.Error("balance value wrong.") 65 | } 66 | netCon := &Netcon{ 67 | NetconID: args[1], 68 | ApplyA: args[2], 69 | ApplyB: args[3], 70 | Addr: args[4], 71 | Area: area, 72 | Balance: balance, 73 | } 74 | jsBytes, err := json.Marshal(netCon) 75 | if err != nil { 76 | return shim.Error("marshal json error:" + err.Error()) 77 | } 78 | err = APIstub.PutState(args[0], jsBytes) 79 | if err != nil { 80 | return shim.Error("error on putstate:" + err.Error()) 81 | } 82 | //update recodeinfo 83 | recordInfo := &RecordsInfo{} 84 | rebs, err := APIstub.GetState(key_recordinfo) 85 | if len(rebs) == 0 { 86 | recordInfo.Size = 1 87 | recordInfo.Start = args[0] 88 | recordInfo.End = args[0] 89 | } else { 90 | err = json.Unmarshal(rebs, &recordInfo) 91 | if err != nil { 92 | return shim.Error("error on unmarsh recorderinfo:" + err.Error()) 93 | } 94 | recordInfo.Size = recordInfo.Size + 1 95 | recordInfo.End = args[0] 96 | } 97 | rebs, err = json.Marshal(recordInfo) 98 | if err != nil { 99 | return shim.Error("error on marsh new recorderinfo:" + err.Error()) 100 | } 101 | err = APIstub.PutState(key_recordinfo, rebs) 102 | if err != nil { 103 | return shim.Error("error on put new recorderinfo:" + err.Error()) 104 | } 105 | //broadcast event 106 | err = APIstub.SetEvent(evn_netcon, []byte("new netcon created with key:"+args[0])) 107 | if err != nil { 108 | return shim.Error(err.Error()) 109 | } 110 | return shim.Success([]byte("new netcon created with key:" + args[0])) 111 | } 112 | 113 | func (s *NetconContract) queryByNetconID(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 114 | if len(args) != 1 { 115 | return shim.Error("Incorrect number of arguments. Expecting 1 ") 116 | } 117 | queryString := fmt.Sprintf("{\"selector\":{\"netconid\":\"%s\"}}", args[0]) 118 | qis, err := APIstub.GetQueryResult(queryString) 119 | if err != nil { 120 | return shim.Error("queryByNetconID error:" + err.Error()) 121 | } 122 | defer qis.Close() 123 | var buffer bytes.Buffer 124 | buffer.WriteString("[") 125 | bArrayMemberAlreadyWritten := false 126 | for qis.HasNext() { 127 | queryResponse, err := qis.Next() 128 | if err != nil { 129 | return shim.Error(err.Error()) 130 | } 131 | if bArrayMemberAlreadyWritten == true { 132 | buffer.WriteString(",") 133 | } 134 | buffer.WriteString(string(queryResponse.Value)) 135 | bArrayMemberAlreadyWritten = true 136 | } 137 | buffer.WriteString("]") 138 | return shim.Success(buffer.Bytes()) 139 | } 140 | 141 | func (s *NetconContract) queryByPara(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 142 | if len(args) != 2 { 143 | return shim.Error("Incorrect number of arguments. Expecting 2 ") 144 | } 145 | queryString := fmt.Sprintf("{\"selector\":{\""+args[0]+"\":\"%s\"}}", args[1]) 146 | qis, err := APIstub.GetQueryResult(queryString) 147 | if err != nil { 148 | return shim.Error("queryByNetconID error:" + err.Error()) 149 | } 150 | defer qis.Close() 151 | resultsIterator, err := APIstub.GetQueryResult(queryString) 152 | if err != nil { 153 | return shim.Error(err.Error()) 154 | } 155 | defer resultsIterator.Close() 156 | 157 | var buffer bytes.Buffer 158 | buffer.WriteString("[") 159 | bArrayMemberAlreadyWritten := false 160 | for resultsIterator.HasNext() { 161 | queryResponse, err := resultsIterator.Next() 162 | if err != nil { 163 | return shim.Error(err.Error()) 164 | } 165 | if bArrayMemberAlreadyWritten == true { 166 | buffer.WriteString(",") 167 | } 168 | buffer.WriteString(string(queryResponse.Value)) 169 | bArrayMemberAlreadyWritten = true 170 | } 171 | buffer.WriteString("]") 172 | return shim.Success(buffer.Bytes()) 173 | } 174 | 175 | func (s *NetconContract) queryAll(APIstub shim.ChaincodeStubInterface, args []string) peer.Response { 176 | rebs, err := APIstub.GetState(key_recordinfo) 177 | if err != nil { 178 | return shim.Error("error on get recorderinfo:" + err.Error()) 179 | } 180 | recordInfo := &RecordsInfo{} 181 | if len(rebs) == 0 { 182 | return shim.Success([]byte{}) 183 | } 184 | err = json.Unmarshal(rebs, &recordInfo) 185 | if err != nil { 186 | return shim.Error("error on unmarsh recorderinfo:" + err.Error()) 187 | } 188 | resultsIterator, err := APIstub.GetStateByRange(recordInfo.Start, recordInfo.End+"1") 189 | if err != nil { 190 | return shim.Error(err.Error()) 191 | } 192 | defer resultsIterator.Close() 193 | 194 | var buffer bytes.Buffer 195 | buffer.WriteString("[") 196 | bArrayMemberAlreadyWritten := false 197 | for resultsIterator.HasNext() { 198 | queryResponse, err := resultsIterator.Next() 199 | if err != nil { 200 | return shim.Error(err.Error()) 201 | } 202 | if bArrayMemberAlreadyWritten == true { 203 | buffer.WriteString(",") 204 | } 205 | buffer.WriteString(string(queryResponse.Value)) 206 | bArrayMemberAlreadyWritten = true 207 | } 208 | buffer.WriteString("]") 209 | println("size:" + strconv.FormatUint(recordInfo.Size, 10) + " start:" + recordInfo.Start + " end:" + recordInfo.End) 210 | return shim.Success(buffer.Bytes()) 211 | } 212 | 213 | func main() { 214 | err := shim.Start(new(NetconContract)) 215 | if err != nil { 216 | fmt.Printf("Error creating new Smart Contract: %s", err) 217 | } 218 | } 219 | --------------------------------------------------------------------------------