說在前面
fabric-sdk-go就像是一個中間件,它接入區塊鏈網路,代替cli模式對peer節點上的鏈碼進行呼叫,但是每個組織都有其專屬的sdk,并且對自己組織下的peer節點操作時,要使用自己的sdk,如果使用其他組織的sdk,那么就會報權限錯誤,
只有peer節點上安裝了這個節點,你才能呼叫,換言之,每個組織下的peer節點安裝鏈碼是根據你的應用決定的,同時,每個鏈碼雖然在多個peer上進行了安裝,但是只需要一次初始化就可以,如果一個peer對資料上鏈,那么安裝了這個鏈碼的所有peer都可以看到該資料
上一篇:(三)Fabric1.4 撰寫鏈碼【下】
注釋待會寫
目錄
- 一、編輯sdk組態檔
- 二、撰寫創建客戶端函式
- 三、撰寫創建通道并加入通道函式
- 四、 撰寫安裝鏈碼函式
- 五、整合到beego
- 六、撰寫中間處理函式
- 七、撰寫Controller函式
- 八、PostMan測驗結果
一、編輯sdk組態檔
1、org1_config.yaml
name: "org1-config"
#
# Copyright SecureKey Technologies Inc. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
#
# The network connection profile provides client applications the information about the target
# blockchain network that are necessary for the applications to interact with it. These are all
# knowledge that must be acquired from out-of-band sources. This file provides such a source.
#
# copied from fabric-sdk-go/test/fixtures/config/config_e2e_pkcs11.yaml
#
# Schema version of the content. Used by the SDK to apply the corresponding parsing rules.
#
version: 1.0.0
#
# The client section used by GO SDK.
#
client:
# Which organization does this application instance belong to? The value must be the name of an org
# defined under "organizations"
organization: Org1
logging:
# Develope can using debug to get more information
# level: info
level: debug
cryptoconfig:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config
# Some SDKs support pluggable KV stores, the properties under "credentialStore"
# are implementation specific
credentialStore:
# [Optional]. Used by user store. Not needed if all credentials are embedded in configuration
# and enrollments are performed elswhere.
path: "/tmp/examplestore"
# [Optional] BCCSP config for the client. Used by GO SDK.
BCCSP:
security:
enabled: true
default:
provider: "SW"
hashAlgorithm: "SHA2"
softVerify: true
level: 256
tlsCerts:
# [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false
systemCertPool: true
# [Optional]. Client key and cert for TLS handshake with peers and orderers
client:
# 使用User1@org1的證書
keyfile: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org1.perinfo.com/users/User1@org1.perinfo.com/tls/client.key
certfile: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org1.perinfo.com/users/User1@org1.perinfo.com/tls/client.cert
################################## General part ##################################
#
# [Optional]. But most apps would have this section so that channel objects can be constructed
# based on the content below. If an app is creating channels, then it likely will not need this
# section.
#
channels:
# name of the channel
perinfo-channel:
# Required. list of orderers designated by the application to use for transactions on this
# channel. This list can be a result of access control ("org1" can only access "ordererA"), or
# operational decisions to share loads from applications among the orderers. The values must
# be "names" of orgs defined under "organizations/peers"
# deprecated: not recommended, to override any orderer configuration items, entity matchers should be used.
# orderers:
# - orderer.example.com
# 不要缺少當前channel的orderer節點
orderers:
- orderer.perinfo.com
# Required. list of peers from participating orgs
peers:
peer0.org1.perinfo.com:
# [Optional]. will this peer be sent transaction proposals for endorsement? The peer must
# have the chaincode installed. The app can also use this property to decide which peers
# to send the chaincode install request. Default: true
endorsingPeer: true
# [Optional]. will this peer be sent query proposals? The peer must have the chaincode
# installed. The app can also use this property to decide which peers to send the
# chaincode install request. Default: true
chaincodeQuery: true
# [Optional]. will this peer be sent query proposals that do not require chaincodes, like
# queryBlock(), queryTransaction(), etc. Default: true
ledgerQuery: true
# [Optional]. will this peer be the target of the SDK's listener registration? All peers can
# produce events but the app typically only needs to connect to one to listen to events.
# Default: true
eventSource: true
# Add other peers in perinfo-channel for byfn
peer0.org2.perinfo.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true
peer0.org3.perinfo.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true
peer0.org4.perinfo.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true
# [Optional]. The application can use these options to perform channel operations like retrieving channel
# config etc.
policies:
#[Optional] options for retrieving channel configuration blocks
queryChannelConfig:
#[Optional] min number of success responses (from targets/peers)
minResponses: 1
#[Optional] channel config will be retrieved for these number of random targets
maxTargets: 1
#[Optional] retry options for query config block
retryOpts:
#[Optional] number of retry attempts
attempts: 5
#[Optional] the back off interval for the first retry attempt
initialBackoff: 500ms
#[Optional] the maximum back off interval for any retry attempt
maxBackoff: 5s
#[Optional] he factor by which the initial back off period is exponentially incremented
backoffFactor: 2.0
#
# list of participating organizations in this network
#
organizations:
Org1:
mspid: Org1MSP
# set msp files path
cryptoPath: peerOrganizations/org1.perinfo.com/users/{username}@org1.perinfo.com/msp
# Add peers for org1
peers:
- peer0.org1.perinfo.com
# [Optional]. Certificate Authorities issue certificates for identification purposes in a Fabric based
# network. Typically certificates provisioning is done in a separate process outside of the
# runtime network. Fabric-CA is a special certificate authority that provides a REST APIs for
# dynamic certificate management (enroll, revoke, re-enroll). The following section is only for
# Fabric-CA servers.
certificateAuthorities:
- ca.org1.perinfo.com
#users:
# Admin:
# cert:
# pem: ${FABRIC_SDK_GO_PROJECT_PATH}/fixtures/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/tlsca/tlsca.org1.example.com-cert.pem
# the profile will contain public information about organizations other than the one it belongs to.
# These are necessary information to make transaction lifecycles work, including MSP IDs and
# peers with a public URL to send transaction proposals. The file will not contain private
# information reserved for members of the organization, such as admin key and certificate,
# fabric-ca registrar enroll ID and secret, etc.
Org2:
mspid: Org2MSP
cryptoPath: peerOrganizations/org2.perinfo.com/users/{username}@org2.perinfo.com/msp
# Add peers for org2
peers:
- peer0.org2.perinfo.com
certificateAuthorities:
- ca.org2.perinfo.com
Org3:
mspid: Org3MSP
cryptoPath: peerOrganizations/org3.perinfo.com/users/{username}@org3.perinfo.com/msp
# Add peers for org3
peers:
- peer0.org3.perinfo.com
certificateAuthorities:
- ca.org3.perinfo.com
Org4:
mspid: Org4MSP
cryptoPath: peerOrganizations/org4.perinfo.com/users/{username}@org4.perinfo.com/msp
# Add peers for org4
peers:
- peer0.org4.perinfo.com
certificateAuthorities:
- ca.org4.perinfo.com
# Orderer Org name
ordererorg:
# Membership Service Provider ID for this organization
mspID: OrdererMSP
cryptoPath: ordererOrganizations/perinfo.com/users/Admin@perinfo.com/msp
orderers:
- orderer.perinfo.com
#
# List of orderers to send transaction and channel create/update requests to. For the time
# being only one orderer is needed. If more than one is defined, which one get used by the
# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers.
#
orderers:
orderer.perinfo.com:
# [Optional] Default: Infer from hostname
url: grpcs://localhost:7050
# these are standard properties defined by the gRPC library
# they will be passed in as-is to gRPC client constructor
grpcOptions:
ssl-target-name-override: orderer.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
# Certificate location absolute path
# Replace to orderer cert path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/ordererOrganizations/perinfo.com/orderers/orderer.perinfo.com/msp/tlscacerts/tlsca.perinfo.com-cert.pem
#
# List of peers to send various requests to, including endorsement, query
# and event listener registration.
#
peers:
peer0.org1.perinfo.com:
# this URL is used to send endorsement and query requests
# [Optional] Default: Infer from hostname
# 表明使用grpcs協議,設定IP和埠號,使用域名會無法連接
# url: grpcs://peer0.org1.example.com:7051
url: grpcs://localhost:7051
grpcOptions:
ssl-target-name-override: peer0.org1.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org1.perinfo.com/tlsca/tlsca.org1.perinfo.com-cert.pem
peer0.org2.perinfo.com:
# Replace the port
url: grpcs://localhost:8051
grpcOptions:
ssl-target-name-override: peer0.org2.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org2.perinfo.com/tlsca/tlsca.org2.perinfo.com-cert.pem
peer0.org3.perinfo.com:
# Replace the port
url: grpcs://localhost:9051
grpcOptions:
ssl-target-name-override: peer0.org3.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org3.perinfo.com/tlsca/tlsca.org3.perinfo.com-cert.pem
peer0.org4.perinfo.com:
# Replace the port
url: grpcs://localhost:10051
grpcOptions:
ssl-target-name-override: peer0.org4.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org4.perinfo.com/tlsca/tlsca.org4.perinfo.com-cert.pem
# Fabric-CA is a special kind of Certificate Authority provided by Hyperledger Fabric which allows
# certificate management to be done via REST APIs. Application may choose to use a standard
# Certificate Authority instead of Fabric-CA, in which case this section would not be specified.
#
certificateAuthorities:
ca.org1.perinfo.com:
url: http://localhost:7054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org1.perinfo.com/ca/ca.org1.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org1.perinfo.com
ca.org2.perinfo.com:
url: http://localhost:8054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org2.perinfo.com/ca/ca.org2.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org2.perinfo.com
ca.org3.perinfo.com:
url: http://localhost:9054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org3.perinfo.com/ca/ca.org3.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org3.perinfo.com
ca.org4.perinfo.com:
url: http://localhost:10054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org4.perinfo.com/ca/ca.org4.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org4.perinfo.com
entitymatchers:
peer:
- pattern: (\w*)peer0.org1.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:7051
ssltargetoverrideurlsubstitutionexp: peer0.org1.perinfo.com
mappedhost: peer0.org1.perinfo.com
- pattern: (\w*)peer0.org2.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:8051
ssltargetoverrideurlsubstitutionexp: peer0.org2.perinfo.com
mappedhost: peer0.org2.perinfo.com
- pattern: (\w*)peer0.org3.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:9051
ssltargetoverrideurlsubstitutionexp: peer0.org3.perinfo.com
mappedhost: peer0.org3.perinfo.com
- pattern: (\w*)peer0.org4.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:10051
ssltargetoverrideurlsubstitutionexp: peer0.org4.perinfo.com
mappedhost: peer0.org4.perinfo.com
orderer:
- pattern: (\w*)orderer.perinfo.com(\w*)
urlsubstitutionexp: localhost:7050
ssltargetoverrideurlsubstitutionexp: orderer.perinfo.com
mappedhost: orderer.perinfo.com
certificateAuthorities:
- pattern: (\w*)ca.org1.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:7054
mappedHost: ca.org1.perinfo.com
- pattern: (\w*)ca.org2.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:8054
mappedHost: ca.org2.perinfo.com
- pattern: (\w*)ca.org3.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:9054
mappedHost: ca.org3.perinfo.com
- pattern: (\w*)ca.org4.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:10054
mappedHost: ca.org4.perinfo.com
2、org2_config.yaml
和org1_config.yaml差不多,只需要修改前面非公共部分即可,同理撰寫org3_config.yaml、org4_config.yaml
name: "org2-config"
#
# Copyright SecureKey Technologies Inc. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
#
# The network connection profile provides client applications the information about the target
# blockchain network that are necessary for the applications to interact with it. These are all
# knowledge that must be acquired from out-of-band sources. This file provides such a source.
#
# copied from fabric-sdk-go/test/fixtures/config/config_e2e_pkcs11.yaml
#
# Schema version of the content. Used by the SDK to apply the corresponding parsing rules.
#
version: 1.0.0
#
# The client section used by GO SDK.
#
client:
# Which organization does this application instance belong to? The value must be the name of an org
# defined under "organizations"
organization: Org2
logging:
# Develope can using debug to get more information
# level: info
level: debug
cryptoconfig:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config
# Some SDKs support pluggable KV stores, the properties under "credentialStore"
# are implementation specific
credentialStore:
# [Optional]. Used by user store. Not needed if all credentials are embedded in configuration
# and enrollments are performed elswhere.
path: "/tmp/examplestore"
# [Optional] BCCSP config for the client. Used by GO SDK.
BCCSP:
security:
enabled: true
default:
provider: "SW"
hashAlgorithm: "SHA2"
softVerify: true
level: 256
tlsCerts:
# [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false
systemCertPool: true
# [Optional]. Client key and cert for TLS handshake with peers and orderers
client:
# 使用User1@org2的證書
keyfile: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org2.perinfo.com/users/User1@org2.perinfo.com/tls/client.key
certfile: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org2.perinfo.com/users/User1@org2.perinfo.com/tls/client.cert
################################## General part ##################################
#
# [Optional]. But most apps would have this section so that channel objects can be constructed
# based on the content below. If an app is creating channels, then it likely will not need this
# section.
#
channels:
# name of the channel
perinfo-channel:
# Required. list of orderers designated by the application to use for transactions on this
# channel. This list can be a result of access control ("org1" can only access "ordererA"), or
# operational decisions to share loads from applications among the orderers. The values must
# be "names" of orgs defined under "organizations/peers"
# deprecated: not recommended, to override any orderer configuration items, entity matchers should be used.
# orderers:
# - orderer.example.com
# 不要缺少當前channel的orderer節點
orderers:
- orderer.perinfo.com
# Required. list of peers from participating orgs
peers:
peer0.org1.perinfo.com:
# [Optional]. will this peer be sent transaction proposals for endorsement? The peer must
# have the chaincode installed. The app can also use this property to decide which peers
# to send the chaincode install request. Default: true
endorsingPeer: true
# [Optional]. will this peer be sent query proposals? The peer must have the chaincode
# installed. The app can also use this property to decide which peers to send the
# chaincode install request. Default: true
chaincodeQuery: true
# [Optional]. will this peer be sent query proposals that do not require chaincodes, like
# queryBlock(), queryTransaction(), etc. Default: true
ledgerQuery: true
# [Optional]. will this peer be the target of the SDK's listener registration? All peers can
# produce events but the app typically only needs to connect to one to listen to events.
# Default: true
eventSource: true
# Add other peers in perinfo-channel for byfn
peer0.org2.perinfo.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true
peer0.org3.perinfo.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true
peer0.org4.perinfo.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true
# [Optional]. The application can use these options to perform channel operations like retrieving channel
# config etc.
policies:
#[Optional] options for retrieving channel configuration blocks
queryChannelConfig:
#[Optional] min number of success responses (from targets/peers)
minResponses: 1
#[Optional] channel config will be retrieved for these number of random targets
maxTargets: 1
#[Optional] retry options for query config block
retryOpts:
#[Optional] number of retry attempts
attempts: 5
#[Optional] the back off interval for the first retry attempt
initialBackoff: 500ms
#[Optional] the maximum back off interval for any retry attempt
maxBackoff: 5s
#[Optional] he factor by which the initial back off period is exponentially incremented
backoffFactor: 2.0
#
# list of participating organizations in this network
#
organizations:
Org1:
mspid: Org1MSP
# set msp files path
cryptoPath: peerOrganizations/org1.perinfo.com/users/{username}@org1.perinfo.com/msp
# Add peers for org1
peers:
- peer0.org1.perinfo.com
# [Optional]. Certificate Authorities issue certificates for identification purposes in a Fabric based
# network. Typically certificates provisioning is done in a separate process outside of the
# runtime network. Fabric-CA is a special certificate authority that provides a REST APIs for
# dynamic certificate management (enroll, revoke, re-enroll). The following section is only for
# Fabric-CA servers.
certificateAuthorities:
- ca.org1.perinfo.com
#users:
# Admin:
# cert:
# pem: ${FABRIC_SDK_GO_PROJECT_PATH}/fixtures/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/tlsca/tlsca.org1.example.com-cert.pem
# the profile will contain public information about organizations other than the one it belongs to.
# These are necessary information to make transaction lifecycles work, including MSP IDs and
# peers with a public URL to send transaction proposals. The file will not contain private
# information reserved for members of the organization, such as admin key and certificate,
# fabric-ca registrar enroll ID and secret, etc.
Org2:
mspid: Org2MSP
cryptoPath: peerOrganizations/org2.perinfo.com/users/{username}@org2.perinfo.com/msp
# Add peers for org2
peers:
- peer0.org2.perinfo.com
certificateAuthorities:
- ca.org2.perinfo.com
Org3:
mspid: Org3MSP
cryptoPath: peerOrganizations/org3.perinfo.com/users/{username}@org3.perinfo.com/msp
# Add peers for org3
peers:
- peer0.org3.perinfo.com
certificateAuthorities:
- ca.org3.perinfo.com
Org4:
mspid: Org4MSP
cryptoPath: peerOrganizations/org4.perinfo.com/users/{username}@org4.perinfo.com/msp
# Add peers for org4
peers:
- peer0.org4.perinfo.com
certificateAuthorities:
- ca.org4.perinfo.com
# Orderer Org name
ordererorg:
# Membership Service Provider ID for this organization
mspID: OrdererMSP
cryptoPath: ordererOrganizations/perinfo.com/users/Admin@perinfo.com/msp
orderers:
- orderer.perinfo.com
#
# List of orderers to send transaction and channel create/update requests to. For the time
# being only one orderer is needed. If more than one is defined, which one get used by the
# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers.
#
orderers:
orderer.perinfo.com:
# [Optional] Default: Infer from hostname
url: grpcs://localhost:7050
# these are standard properties defined by the gRPC library
# they will be passed in as-is to gRPC client constructor
grpcOptions:
ssl-target-name-override: orderer.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
# Certificate location absolute path
# Replace to orderer cert path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/ordererOrganizations/perinfo.com/orderers/orderer.perinfo.com/msp/tlscacerts/tlsca.perinfo.com-cert.pem
#
# List of peers to send various requests to, including endorsement, query
# and event listener registration.
#
peers:
peer0.org1.perinfo.com:
# this URL is used to send endorsement and query requests
# [Optional] Default: Infer from hostname
# 表明使用grpcs協議,設定IP和埠號,使用域名會無法連接
# url: grpcs://peer0.org1.example.com:7051
url: grpcs://localhost:7051
grpcOptions:
ssl-target-name-override: peer0.org1.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org1.perinfo.com/tlsca/tlsca.org1.perinfo.com-cert.pem
peer0.org2.perinfo.com:
# Replace the port
url: grpcs://localhost:8051
grpcOptions:
ssl-target-name-override: peer0.org2.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org2.perinfo.com/tlsca/tlsca.org2.perinfo.com-cert.pem
peer0.org3.perinfo.com:
# Replace the port
url: grpcs://localhost:9051
grpcOptions:
ssl-target-name-override: peer0.org3.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org3.perinfo.com/tlsca/tlsca.org3.perinfo.com-cert.pem
peer0.org4.perinfo.com:
# Replace the port
url: grpcs://localhost:10051
grpcOptions:
ssl-target-name-override: peer0.org4.perinfo.com
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org4.perinfo.com/tlsca/tlsca.org4.perinfo.com-cert.pem
# Fabric-CA is a special kind of Certificate Authority provided by Hyperledger Fabric which allows
# certificate management to be done via REST APIs. Application may choose to use a standard
# Certificate Authority instead of Fabric-CA, in which case this section would not be specified.
#
certificateAuthorities:
ca.org1.perinfo.com:
url: http://localhost:7054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org1.perinfo.com/ca/ca.org1.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org1.perinfo.com
ca.org2.perinfo.com:
url: http://localhost:8054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org2.perinfo.com/ca/ca.org2.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org2.perinfo.com
ca.org3.perinfo.com:
url: http://localhost:9054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org3.perinfo.com/ca/ca.org3.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org3.perinfo.com
ca.org4.perinfo.com:
url: http://localhost:10054
tlsCACerts:
# Certificate location absolute path
path: ${FABRIC_SDK_GO_PROJECT_PATH}/fabric/fixtures/crypto-config/peerOrganizations/org4.perinfo.com/ca/ca.org4.perinfo.com-cert.pem
# Client key and cert for SSL handshake with Fabric CA
#client:
# key:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key
# cert:
# path: /home/alextan/blockchain/fabric/fabric-samples-1.4/raft-local-test/crypto-config/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt
# Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is
# needed to enroll and invoke new users.
registrar:
enrollId: admin
enrollSecret: perinfo68
# [Optional] The optional name of the CA.
caName: ca.org4.perinfo.com
entitymatchers:
peer:
- pattern: (\w*)peer0.org1.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:7051
ssltargetoverrideurlsubstitutionexp: peer0.org1.perinfo.com
mappedhost: peer0.org1.perinfo.com
- pattern: (\w*)peer0.org2.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:8051
ssltargetoverrideurlsubstitutionexp: peer0.org2.perinfo.com
mappedhost: peer0.org2.perinfo.com
- pattern: (\w*)peer0.org3.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:9051
ssltargetoverrideurlsubstitutionexp: peer0.org3.perinfo.com
mappedhost: peer0.org3.perinfo.com
- pattern: (\w*)peer0.org4.perinfo.com(\w*)
urlsubstitutionexp: grpcs://localhost:10051
ssltargetoverrideurlsubstitutionexp: peer0.org4.perinfo.com
mappedhost: peer0.org4.perinfo.com
orderer:
- pattern: (\w*)orderer.perinfo.com(\w*)
urlsubstitutionexp: localhost:7050
ssltargetoverrideurlsubstitutionexp: orderer.perinfo.com
mappedhost: orderer.perinfo.com
certificateAuthorities:
- pattern: (\w*)ca.org1.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:7054
mappedHost: ca.org1.perinfo.com
- pattern: (\w*)ca.org2.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:8054
mappedHost: ca.org2.perinfo.com
- pattern: (\w*)ca.org3.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:9054
mappedHost: ca.org3.perinfo.com
- pattern: (\w*)ca.org4.perinfo.com(\w*)
urlSubstitutionExp: http://localhost:10054
mappedHost: ca.org4.perinfo.com
二、撰寫創建客戶端函式
/*
@Author : Jessy
@Description :
@File : client.go
@Software: GoLand
@Version: 1.0.0
@Date : 2021/8/10 21:19
*/
package cli
import (
"log"
"os"
"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
"github.com/hyperledger/fabric-sdk-go/pkg/client/event"
)
type Client struct {
// Fabric network information
ConfigPath string
OrgName string
OrgAdmin string
OrgUser string
// sdk clients
SDK *fabsdk.FabricSDK
rc *resmgmt.Client
cc *channel.Client
e *event.Client
// Same for each peer
ChannelID string
CCIDs []string // chaincode ID, eq name
CCPaths []string // chaincode source path, 是GOPATH下的某個目錄
CCGoPath string // GOPATH used for chaincode
}
func New(cfg, org, admin, user string, ccids []string, ccpaths []string) *Client {
c := &Client{
ConfigPath: cfg,
OrgName: org,
OrgAdmin: admin,
OrgUser: user,
CCIDs: ccids,
CCPaths: ccpaths, // 相對路徑是從GOPAHT/src開始的
CCGoPath: os.Getenv("GOPATH"),
ChannelID: "perinfo-channel",
}
// create sdk
sdk, err := fabsdk.New(config.FromFile(c.ConfigPath))
if err != nil {
log.Panicf("failed to create fabric sdk: %s", err)
}
c.SDK = sdk
log.Println("Initialized fabric sdk")
c.rc, c.cc, c.e = NewSdkClient(sdk, c.ChannelID, c.OrgName, c.OrgAdmin, c.OrgUser)
return c
}
// NewSdkClient create resource client and channel client
func NewSdkClient(sdk *fabsdk.FabricSDK, channelID, orgName, orgAdmin, OrgUser string) (rc *resmgmt.Client, cc *channel.Client, e *event.Client) {
var err error
// create rc
rcp := sdk.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(orgName))
rc, err = resmgmt.New(rcp)
if err != nil {
log.Panicf("failed to create resource client: %s", err)
}
log.Println("Initialized resource client")
// create cc
ccp := sdk.ChannelContext(channelID, fabsdk.WithUser(OrgUser))
cc, err = channel.New(ccp)
if err != nil {
log.Panicf("failed to create channel client: %s", err)
}
log.Println("Initialized channel client")
//create event
e, err = event.New(ccp)
if err != nil {
log.Panicf( "failed to create new event client",err)
}
log.Println("Event client created")
return rc, cc, e
}
func (c *Client) CloseSDK() {
c.SDK.Close()
}
三、撰寫創建通道并加入通道函式
/*
@Author : Jessy
@Description :
@File : init.go
@Software: GoLand
@Version: 1.0.0
@Date : 2021/8/10 21:11
*/
package cli
import (
"log"
"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp"
mspclient "github.com/hyperledger/fabric-sdk-go/pkg/client/msp"
)
//fabric/sdkConfig/org1_config.yaml
const (
org1CfgPath = "fabric/sdkConfig/org1_config.yaml"
org2CfgPath = "fabric/sdkConfig/org2_config.yaml"
org3CfgPath = "fabric/sdkConfig/org3_config.yaml"
org4CfgPath = "fabric/sdkConfig/org4_config.yaml"
org1Name = "Org1"
org2Name = "Org2"
org3Name = "Org3"
org4Name = "Org4"
orgAdmin = "Admin"
ordererID = "orderer.perinfo.com"
ordererOrgName = "ordererorg"
channelID = "perinfo-channel"
channelConfig = "fabric/fixtures/channel-artifacts/channel.tx"
)
func CreateChannel(){
sdk1, err := fabsdk.New(config.FromFile(org1CfgPath))
if err != nil {
log.Panicf("failed to create fabric sdk1: %s", err)
}
sdk2, err := fabsdk.New(config.FromFile(org2CfgPath))
if err != nil {
log.Panicf("failed to create fabric sdk2: %s", err)
}
sdk3, err := fabsdk.New(config.FromFile(org3CfgPath))
if err != nil {
log.Panicf("failed to create fabric sdk3: %s", err)
}
sdk4, err := fabsdk.New(config.FromFile(org4CfgPath))
if err != nil {
log.Panicf("failed to create fabric sdk4: %s", err)
}
clientContext := sdk1.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(ordererOrgName))
resMgmtClient, err := resmgmt.New(clientContext)
if err != nil {
log.Panicf("failed to create resMgmtClient in createChannel: %s", err)
}
mspClient, err := mspclient.New(sdk1.Context(), mspclient.WithOrg(org1Name))
if err != nil {
log.Panicf("failed to create msp client: %s", err)
}
adminIdentity, err := mspClient.GetSigningIdentity(orgAdmin)
if err != nil {
log.Panicf("failed to GetSigningIdentity: %s", err)
}
req := resmgmt.SaveChannelRequest{ChannelID: channelID,
ChannelConfigPath: channelConfig,
SigningIdentities: []msp.SigningIdentity{adminIdentity}}
_, err = resMgmtClient.SaveChannel(req, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(ordererID))
if err != nil {
log.Panicf("failed to GetSigningIdentity: %s", err)
}
log.Println("created fabric channel")
// join Channel
org1Context := sdk1.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(org1Name))
org2Context := sdk2.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(org2Name))
org3Context := sdk3.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(org3Name))
org4Context := sdk4.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(org4Name))
org1ResMgmt, err := resmgmt.New(org1Context)
if err != nil {
log.Panicf("failed to create org1ResMgmt: %s", err)
}
org2ResMgmt, err := resmgmt.New(org2Context)
if err != nil {
log.Panicf("failed to create org2ResMgmt: %s", err)
}
org3ResMgmt, err := resmgmt.New(org3Context)
if err != nil {
log.Panicf("failed to create org3ResMgmt: %s", err)
}
org4ResMgmt, err := resmgmt.New(org4Context)
if err != nil {
log.Panicf("failed to create org4ResMgmt: %s", err)
}
if err = org1ResMgmt.JoinChannel(channelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(ordererID)); err != nil {
log.Panicf("Org1 peers failed to JoinChannel: %s", err)
}
log.Println("org1 joined channel")
if err = org2ResMgmt.JoinChannel(channelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(ordererID)); err != nil {
log.Panicf("Org2 peers failed to JoinChannel: %s", err)
}
log.Println("org2 joined channel")
if err = org3ResMgmt.JoinChannel(channelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(ordererID)); err != nil {
log.Panicf("Org3 peers failed to JoinChannel: %s", err)
}
log.Println("org3 joined channel")
if err = org4ResMgmt.JoinChannel(channelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(ordererID)); err != nil {
log.Panicf("Org4 peers failed to JoinChannel: %s", err)
}
log.Println("org4 joined channel")
}
四、 撰寫安裝鏈碼函式
/*
@Author : Jessy
@Description :
@File : IIchaincode.go
@Software: GoLand
@Version: 1.0.0
@Date : 2021/8/10 21:24
*/
package cli
import (
"log"
"net/http"
"strings"
"fmt"
"github.com/pkg/errors"
"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
"github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/gopackager"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric-protos-go/common"
)
// InstallCC install chaincode for target peer
func (c *Client) InstallCC(v string, peer string) error {
targetPeer := resmgmt.WithTargetEndpoints(peer)
//由于傳遞的是鏈碼陣列,所以這里回圈
ccids := c.CCIDs
var errs []error
var ccpath string
for i,ccid := range ccids{
// 打包鏈碼 pack the chaincode
ccpath = c.CCPaths[i]
ccPkg, err := gopackager.NewCCPackage(ccpath, c.CCGoPath)
if err != nil {
s_err:=fmt.Sprintf("pack chaincode %s error",ccid)
errs = append(errs, errors.New(s_err))
break
}
// 構建鏈碼安裝請求 new request of installing chaincode
req := resmgmt.InstallCCRequest{
Name: ccid,
Path: ccpath,
Version: v,
Package: ccPkg,
}
// 安裝鏈碼
resps, err := c.rc.InstallCC(req, targetPeer)
if err != nil {
s_err:=fmt.Sprintf("installCC %s error",ccid)
errs = append(errs, errors.New(s_err))
break
}
// 檢查其他錯誤
for _, resp := range resps {
log.Printf("Install response status: %v", resp.Status)
if resp.Status != http.StatusOK {
errs = append(errs, errors.New(resp.Info))
}
if resp.Info == "already installed" {
log.Printf("Chaincode %s already installed on peer: %s.\n", ccid +"-"+v, resp.Target)
continue
}
}
}
if len(errs) > 0 {
log.Printf("InstallCC errors: %v", errs)
return errors.WithMessage(errs[0], "installCC first error")
}
return nil
}
func (c *Client) InstantiateCC(v string, peer string) error {
// endorser policy
//ccPolicy := cauthdsl.SignedByAnyMember([]string{"org1.info.com"})
org1OrOrg2 := "OR('Org1MSP.member','Org2MSP.member',Org3MSP.member,Org4MSP.member)"
ccPolicy, err := c.genPolicy(org1OrOrg2)
if err != nil {
return errors.WithMessage(err, "gen policy from string error")
}
// new request
// Attention: args should include `init` for Request not
// have a method term to call init
args := packArgs([]string{"init"}) //撰寫的所有鏈碼中初始化都沒有其他引數,所以可以統一初始化
ccids := c.CCIDs
var ccpath string
var errs []error
for i,ccid := range ccids{
ccpath=c.CCPaths[i]
req := resmgmt.InstantiateCCRequest{
Name: ccid,
Path: ccpath,
Version: v,
Args: args,
Policy: ccPolicy,
}
// send request and handle response
reqPeers := resmgmt.WithTargetEndpoints(peer)
resp, err := c.rc.InstantiateCC(c.ChannelID, req, reqPeers)
if err != nil {
if strings.Contains(err.Error(), "already exists") {
continue
}
s_err:=fmt.Sprintf("instantiate chaincode %s error:%v",ccid,err)
errs=append(errs, errors.New(s_err))
}
log.Printf("Instantitate chaincode tx: %s", resp.TransactionID)
}
if len(errs) > 0 {
log.Printf("InstallCC errors: %v", errs)
return errors.WithMessage(errs[0], "Instantitate first error:")
}
return nil
}
func (c *Client) UpgradeCC(v string, peer string) error {
// endorser policy
//ccPolicy := cauthdsl.SignedByAnyMember([]string{"org1.info.com"})
// endorser policy
org1AndOrg2 :="AND('Org1MSP.member','Org2MSP.member',Org3MSP.member,Org4MSP.member)"
ccPolicy, err := c.genPolicy(org1AndOrg2)
if err != nil {
return errors.WithMessage(err, "gen policy from string error")
}
// new request
// Attention: args should include `init` for Request not
// have a method term to call init
// Reset a b's value to test the upgrade
args := packArgs([]string{"init"})
ccids := c.CCIDs
var ccpath string
var errs []error
for i,ccid := range ccids{
ccpath=c.CCPaths[i]
req := resmgmt.UpgradeCCRequest{
Name: ccid,
Path: ccpath,
Version: v,
Args: args,
Policy: ccPolicy,
}
// send request and handle response
reqPeers := resmgmt.WithTargetEndpoints(peer)
resp, err := c.rc.UpgradeCC(c.ChannelID, req, reqPeers)
if err != nil {
s_err:=fmt.Sprintf("upgrade chaincode %s error",ccid)
errs = append(errs,errors.New(s_err))
}
log.Printf("upgrade chaincode tx: %s", resp.TransactionID)
}
if len(errs) > 0 {
log.Printf("upgrade errors: %v", errs)
return errors.WithMessage(errs[0], "upgrade first error:")
}
return nil
}
func packArgs(paras []string) [][]byte {
var args [][]byte
for _, k := range paras {
args = append(args, []byte(k))
}
return args
}
func (c *Client) genPolicy(p string) (*common.SignaturePolicyEnvelope, error) {
// TODO bug, this any leads to endorser invalid
if p == "ANY" {
return cauthdsl.SignedByAnyMember([]string{c.OrgName}), nil
}
return cauthdsl.FromString(p)
}
五、整合到beego
在beego的main.go檔案如下撰寫,即可在啟動beegoWeb應用時啟動客戶端
先啟動網路,二者可以獨立啟動,但是停止beego之后需要注釋掉通道函式和安裝鏈碼函式,不然會報已經生成通道和鏈碼版本錯誤,你也可以動態升級鏈碼版本,beego熱啟動也行
package main
import (
_ "PerInfoChain/routers"
"PerInfoChain/common/app"
"PerInfoChain/fabric/cli"
"PerInfoChain/fabric/pkgPerInfo"
"PerInfoChain/common"
"PerInfoChain/controllers"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/plugins/cors"
"log"
)
const (
org1CfgPath = "fabric/sdkConfig/org1_config.yaml"
org2CfgPath = "fabric/sdkConfig/org2_config.yaml"
org3CfgPath = "fabric/sdkConfig/org3_config.yaml"
org4CfgPath = "fabric/sdkConfig/org4_config.yaml"
)
// 全域變數
var ( //可以放到一起添加,不用像我這樣分開,沒有影響
//教育
peer0Org1 = "peer0.org1.perinfo.com"
peer0Org1CCIDs = []string{
"BasicInfoCC",
"EducationCC",
"EducationScoreCC",
}
peer0Org1CCPATHs = []string{
"PerInfoChain/fabric/chaincode/basic-info",
"PerInfoChain/fabric/chaincode/education-info",
"PerInfoChain/fabric/chaincode/education-score-info",
}
//銀行
peer0Org2 = "peer0.org2.perinfo.com"
peer0Org2CCIDs = []string{
"BasicInfoCC",
"BankCC",
"BankDetailCC",
}
peer0Org2CCPATHs = []string{
"PerInfoChain/fabric/chaincode/basic-info",
"PerInfoChain/fabric/chaincode/bank-info",
"PerInfoChain/fabric/chaincode/bank-detail-info",
}
//公安
peer0Org3 = "peer0.org3.perinfo.com"
peer0Org3CCIDs = []string{
"BasicInfoCC",
"PoliceCC",
}
peer0Org3CCPATHs = []string{
"PerInfoChain/fabric/chaincode/basic-info",
"PerInfoChain/fabric/chaincode/police-info",
}
//住房
peer0Org4 = "peer0.org4.perinfo.com"
peer0Org4CCIDs = []string{
"BasicInfoCC",
"HouseCC",
}
peer0Org4CCPATHs = []string{
"PerInfoChain/fabric/chaincode/basic-info",
"PerInfoChain/fabric/chaincode/house-info",
}
)
func initialize() (*app.Application, error){
//跨域
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
AllowAllOrigins: true,
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
AllowCredentials: true,
}))
err := setupLogger()
if err != nil {
log.Fatalf("init.setupLogger err: %v", err)
}
//fabric
//TODO 區塊鏈網路部分,與web無關 nit 創建通道 第一次運行后注釋掉
cli.CreateChannel()
//注冊sdk 與web有關
org1Client := cli.New(org1CfgPath,"Org1","Admin","User1",peer0Org1CCIDs,peer0Org1CCPATHs)
org2Client := cli.New(org2CfgPath,"Org2","Admin","User1",peer0Org2CCIDs,peer0Org2CCPATHs)
org3Client := cli.New(org3CfgPath,"Org3","Admin","User1",peer0Org3CCIDs,peer0Org3CCPATHs)
org4Client := cli.New(org4CfgPath,"Org4","Admin","User1",peer0Org4CCIDs,peer0Org4CCPATHs)
// Launch the web application listening
application := &app.Application{
Client1: org1Client,
Client2: org2Client,
Client3: org3Client,
Client4: org4Client,
}
// TODO 區塊鏈網路部分,與web無關 Install, instantiate, invoke, query 鏈碼
ClientInstallAndInstantiateCC(application)
//Phase1(application.Client1, application.Client2, application.Client3,application.Client4)
// Install, upgrade, invoke, query
//Phase2(org1Client, org2Client, org3Client,org4Client)
return application, nil
}
func ClientInstallAndInstantiateCC(app *app.Application) {
if err := app.Client1.InstallCC("v1", peer0Org1); err != nil {
log.Panicf("Intall chaincode error: %v", err)
}
log.Println("Chaincode has been installed on org1's peers")
if err := app.Client2.InstallCC("v1", peer0Org2); err != nil {
log.Panicf("Intall chaincode error: %v", err)
}
log.Println("Chaincode has been installed on org2's peers")
if err := app.Client3.InstallCC("v1", peer0Org3); err != nil {
log.Panicf("Intall chaincode error: %v", err)
}
log.Println("Chaincode has been installed on org3's peers")
if err := app.Client4.InstallCC("v1", peer0Org4); err != nil {
log.Panicf("Intall chaincode error: %v", err)
}
log.Println("Chaincode has been installed on org4's peers")
// InstantiateCC chaincode only need once for each channel
if err := app.Client1.InstantiateCC("v1", peer0Org1); err != nil {
log.Panicf("Instantiated chaincode error: %v", err)
}
log.Println("Chaincode has been instantiated")
if err := app.Client2.InstantiateCC("v1", peer0Org2); err != nil {
log.Panicf("Instantiated chaincode error: %v", err)
}
log.Println("Chaincode has been instantiated")
if err := app.Client3.InstantiateCC("v1", peer0Org3); err != nil {
log.Panicf("Instantiated chaincode error: %v", err)
}
log.Println("Chaincode has been instantiated")
if err := app.Client4.InstantiateCC("v1", peer0Org4); err != nil {
log.Panicf("Instantiated chaincode error: %v", err)
}
log.Println("Chaincode has been instantiated")
}
func main() {
app, err := initialize()
if err != nil {
return
}
defer app.Client1.CloseSDK()
defer app.Client2.CloseSDK()
defer app.Client3.CloseSDK()
defer app.Client4.CloseSDK()
ns := beego.NewNamespace("/api/v1",
beego.NSNamespace("/fabric",
beego.NSBefore(common.ChenkToken),
//basicInfo
beego.NSRouter("/basic_info/query_by_userid/:user_id", &controllers.FabricController{App:app}, "get:QueryBasicByUserID"),
beego.NSRouter("/basic_info/query_by_idcard/:idcard", &controllers.FabricController{App:app}, "get:QueryBasicByIDCard"),
beego.NSRouter("/basic_info/query_history/:user_id", &controllers.FabricController{App:app}, "get:QueryHistoryBasic"),
),
)
beego.AddNamespace(ns)
beego.Run()
}
}
有空了再做fabric私有資料
六、撰寫中間處理函式
cli_basicInfo.go
/*
@Author : Jessy
@Description :
@File : cli_basic
@Software: GoLand
@Version: 1.0.0
@Date : 2021/8/10 21:46
*/
package cli
import (
"PerInfoChain/fabric/pkgPerInfo"
"log"
"fmt"
"time"
"github.com/pkg/errors"
"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
)
func (c *Client) AddBasicInfo(peers []string, basicInfo pkgPerInfo.BasicInfo) (string, error) {
// prepare arguments
chaincodeID:="BasicInfoCC"
var args []string
args = append(args,basicInfo.UserID)
args = append(args,basicInfo.IDCard)
args = append(args,basicInfo.Name)
args = append(args,basicInfo.Sex)
args = append(args,basicInfo.Nation)
args = append(args,basicInfo.Native)
args = append(args,basicInfo.Birthday)
args = append(args,basicInfo.Phone)
args = append(args,basicInfo.Email)
args = append(args,basicInfo.PoliticalLook)
args = append(args,basicInfo.HomeAddress)
args = append(args,basicInfo.LoginUserID)
args = append(args,basicInfo.UserInfoFileHash)
eventID := "event_addBasicInfo"
// Add data that will be visible in the proposal, like a description of the invoke request
transientDataMap := make(map[string][]byte)
transientDataMap["result"] = []byte("Transient data in addBasicInfo")
reg, notifier, err := c.e.RegisterChaincodeEvent(chaincodeID, eventID)
if err != nil {
return "", err
}
defer c.e.Unregister(reg)
// new channel request for invoke
req := channel.Request{
ChaincodeID: chaincodeID,
Fcn: "addBasicInfo",
Args: packArgs(args),
TransientMap: transientDataMap,
}
// send request and handle response
// peers is needed
reqPeers := channel.WithTargetEndpoints(peers...)
resp, err := c.cc.Execute(req, reqPeers)
log.Printf("Invoke basicInfo add response:\n"+ "id: %v\nvalidate: %v\nchaincode status: %v\n\n", resp.TransactionID, resp.TxValidationCode, resp.ChaincodeStatus)
if err != nil {
s_err:=fmt.Sprintf("add basicInfo error:%s",err)
return "", errors.WithMessage(err, s_err)
}
// Wait for the result of the submission
select {
case ccEvent := <-notifier:
fmt.Printf("Received CC event: %s\n", ccEvent)
case <-time.After(time.Second * 20):
//TODO 一直沒有受到回傳的cc event,但是可以上鏈成功,所以這里還是return nil 美觀
//return "", fmt.Sprintf("did NOT receive CC event for eventId(%s)", eventID)
return string(resp.TransactionID), nil
}
return string(resp.TransactionID), nil
}
func (c *Client) UpdateBasicInfo(peers []string, basicInfo pkgPerInfo.BasicInfo) (string, error) {
// new channel request for query
chaincodeID:="BasicInfoCC"
var args []string
args = append(args,basicInfo.UserID)
args = append(args,basicInfo.IDCard)
args = append(args,basicInfo.Name)
args = append(args,basicInfo.Sex)
args = append(args,basicInfo.Nation)
args = append(args,basicInfo.Native)
args = append(args,basicInfo.Birthday)
args = append(args,basicInfo.Phone)
args = append(args,basicInfo.Email)
args = append(args,basicInfo.PoliticalLook)
args = append(args,basicInfo.HomeAddress)
args = append(args,basicInfo.LoginUserID)
args = append(args,basicInfo.UserInfoFileHash)
eventID := "event_updateBasicInfo"
// Add data that will be visible in the proposal, like a description of the invoke request
transientDataMap := make(map[string][]byte)
transientDataMap["result"] = []byte("Transient data in UpdateBasicInfo")
reg, notifier, err := c.e.RegisterChaincodeEvent(chaincodeID, eventID)
if err != nil {
return "", err
}
defer c.e.Unregister(reg)
// new channel request for invoke
req := channel.Request{
ChaincodeID: chaincodeID,
Fcn: "updateBasicInfoByUserID",
Args: packArgs(args),
TransientMap: transientDataMap,
}
// send request and handle response
reqPeers := channel.WithTargetEndpoints(peers...)
resp, err := c.cc.Execute(req, reqPeers)
log.Printf("Invoke basicInfo update response:\n"+"id: %v\nvalidate: %v\nchaincode status: %v\n\n", resp.TransactionID, resp.TxValidationCode, resp.ChaincodeStatus)
if err != nil {
s_err:=fmt.Sprintf("update basicInfo error:%s",err)
return "", errors.WithMessage(err, s_err)
}
// Wait for the result of the submission
select {
case ccEvent := <-notifier:
fmt.Printf("Received CC event: %s\n", ccEvent)
case <-time.After(time.Second * 20):
//return "", fmt.Sprintf("did NOT receive CC event for eventId(%s)", eventID)
return string(resp.TransactionID), nil
}
return string(resp.TransactionID), nil
}
func (c *Client) DelBasicInfo(peers []string, userID string) (string, error) {
// new channel request for invoke
chaincodeID:="BasicInfoCC"
var args []string
args = append(args,userID)
eventID := "event_deleteBasicInfo"
// Add data that will be visible in the proposal, like a description of the invoke request
transientDataMap := make(map[string][]byte)
transientDataMap["result"] = []byte("Transient data in deleteBasicInfo")
reg, notifier, err := c.e.RegisterChaincodeEvent(chaincodeID, eventID)
if err != nil {
return "", err
}
defer c.e.Unregister(reg)
req := channel.Request{
ChaincodeID: chaincodeID,
Fcn: "delBasicInfoByUserID",
Args: packArgs(args),
}
// send request and handle response
// peers is needed
reqPeers := channel.WithTargetEndpoints(peers...)
resp, err := c.cc.Execute(req, reqPeers)
log.Printf("Invoke basicInfo delete response:\n"+"id: %v\nvalidate: %v\nchaincode status: %v\n\n", resp.TransactionID, resp.TxValidationCode, resp.ChaincodeStatus)
if err != nil {
return "", errors.WithMessage(err, "delete basicInfo error")
}
// Wait for the result of the submission
select {
case ccEvent := <-notifier:
fmt.Printf("Received CC event: %s\n", ccEvent)
case <-time.After(time.Second * 20):
return string(resp.TransactionID), nil
}
return string(resp.TransactionID), nil
}
func (c *Client) QueryBasicInfoByUserID(peer, UserID string) (string, error) {
channelID := "BasicInfoCC"
// new channel request for query
var args []string
args = append(args,UserID)
req := channel.Request{
ChaincodeID: channelID,
Fcn: "queryBasicByUserID",
Args: packArgs(args),
}
// send request and handle response
reqPeers := channel.WithTargetEndpoints(peer)
resp, err := c.cc.Query(req, reqPeers)
if err != nil {
return "",errors.WithMessage(err, "query basicInfo error")
}
//log.Printf("Query basicInfo by UserID tx response:\ntx: %s\nresult: %v\n\n", resp.TransactionID, string(resp.Payload))
return string(resp.Payload), nil
}
func (c *Client) QueryHistoryBasicInfo(peer string, UserID string) (string, error) {
channelID := "BasicInfoCC"
// new channel request for query
var args []string
args = append(args,UserID)
req := channel.Request{
ChaincodeID: channelID,
Fcn: "getHistoryBasicInfo",
Args: packArgs(args),
}
// send request and handle response
reqPeers := channel.WithTargetEndpoints(peer)
resp, err := c.cc.Query(req, reqPeers)
if err != nil {
s_err:=fmt.Sprintf("query history basicInfo error:%s",err)
return "", errors.WithMessage(err, s_err)
}
//log.Printf("Query basicInfo history tx response:\ntx: %s\nresult: %v\n\n", resp.TransactionID, string(resp.Payload))
return string(resp.Payload), nil
}
func (c *Client) QueryBasicInfoByIDCard(peer string, IDCard string) (string, error) {
channelID := "BasicInfoCC"
// new channel request for query
var args []string
args = append(args,IDCard)
req := channel.Request{
ChaincodeID: channelID,
Fcn: "queryBasicInfoByIDCard",
Args: packArgs(args),
}
// send request and handle response
reqPeers := channel.WithTargetEndpoints(peer)
resp, err := c.cc.Query(req, reqPeers)
if err != nil {
return "",errors.WithMessage(err, "query basicInfo by IDCard error")
}
//log.Printf("Query basicInfo by IDCard tx response:\ntx: %s\nresult: %v\n\n", resp.TransactionID, string(resp.Payload))
if resp.Payload == nil{
return "",errors.WithMessage(err, "未能根據身份證IDCard找到個人基本資訊")
}
return string(resp.Payload), nil
}
七、撰寫Controller函式
這里主要涉及查詢,由于添加涉及到保密部分,故不放出來,大同小異
/*
@Author : Jessy
@Description :
@File : FabricController.go
@Software: GoLand
@Version: 1.0.0
@Date : 2021/8/12 17:10
*/
package controllers
import (
fabapp "PerInfoChain/common/app"
"PerInfoChain/fabric/pkgPerInfo"
"PerInfoChain/pkg/errcode"
"encoding/json"
"errors"
"fmt"
"strings"
)
type FabricController struct {
BaseController
App *fabapp.Application
}
var (
peer0Org1 = "peer0.org1.perinfo.com"
)
// BasicInfo
func (c *FabricController)QueryBasicByUserID() {
UserID := c.Ctx.Input.Param(":user_id")
basicInfoDes,_ := c.App.Client1.QueryBasicInfoByUserID(peer0Org1,UserID)
basicInfoS:=fmt.Sprintf(strings.Replace(basicInfoDes,"\\","",-1))
var basicInfo pkgPerInfo.BasicInfo
err := json.Unmarshal([]byte(basicInfoS),&basicInfo)
if err!= nil{
c.ToErrorResponse(errcode.ErrorFabricBasicInfoQueryFail.WithDetails(errors.New("區塊鏈網路未根據UserID找到個人基本資訊").Error()))
return
}
c.ToResponse(&basicInfo)
}
func (c *FabricController)QueryBasicByIDCard() {
IDCard := c.Ctx.Input.Param(":idcard")
basicInfoListDes,_ := c.App.Client1.QueryBasicInfoByIDCard(peer0Org1,IDCard)
if basicInfoListDes == ""{
c.ToErrorResponse(errcode.ErrorFabricBasicInfoQueryFail.WithDetails(errors.New("個人基本資訊序列化出錯").Error()))
return
}
var basicInfoList []map[string]string
err:= json.Unmarshal([]byte(basicInfoListDes),&basicInfoList)
if err !=nil {
c.ToErrorResponse(errcode.ErrorFabricBasicInfoQueryFail.WithDetails(errors.New("個人基本資訊序列化出錯").Error()))
return
}
if len(basicInfoList)==0 {
c.ToErrorResponse(errcode.ErrorFabricBasicInfoQueryFail.WithDetails(errors.New("未根據身份證找到個人基本資訊").Error()))
}
c.ToResponse(basicInfoList)
}
func (c *FabricController)QueryHistoryBasic() {
UserID := c.Ctx.Input.Param(":user_id")
str,_ := c.App.Client1.QueryHistoryBasicInfo(peer0Org1,UserID)
s := strings.Replace(str,"\\","",-1)
var historylistS []pkgPerInfo.HistoryS
var historyList []pkgPerInfo.HistoryBasic
var basicInfo pkgPerInfo.BasicInfo
err:=json.Unmarshal([]byte(s),&historylistS)
if err !=nil {
c.ToErrorResponse(errcode.ErrorFabricBasicInfoQueryFail.WithDetails(errors.New("歷史個人基本資訊序列化出錯").Error()))
return
}
for i,history := range historylistS{
basicInfo.UserID=history.Value["UserID"]
basicInfo.IDCard=history.Value["IDCard"]
basicInfo.Name=history.Value["Name"]
basicInfo.Sex=history.Value["Sex"]
basicInfo.Nation=history.Value["Nation"]
basicInfo.Native=history.Value["Native"]
basicInfo.Birthday=history.Value["Birthday"]
basicInfo.Phone=history.Value["Phone"]
basicInfo.Email=history.Value["Email"]
basicInfo.PoliticalLook=history.Value["PoliticalLook"]
basicInfo.HomeAddress=history.Value["HomeAddress"]
basicInfo.LoginUserID=history.Value["LoginUserID"]
basicInfo.UserInfoFileHash=history.Value["UserInfoFileHash"]
basicInfo.Time=history.Value["Time"]
history:=pkgPerInfo.HistoryBasic{
TxId: historylistS[i].TxId,
Value: basicInfo,
Timestamp: historylistS[i].Timestamp,
IsDelete: historylistS[i].IsDelete,
}
historyList=append(historyList,history)
}
c.ToResponse(historyList)
}
八、PostMan測驗結果
根據UserID查詢資訊

查詢歷史資訊

下一篇:(五)在自己專案中安裝區塊鏈瀏覽器blockchain-explorer
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/294286.html
標籤:區塊鏈
