主頁 > 區塊鏈 > (四)Fabric1.4 Fabric-SDK-go及web應用

(四)Fabric1.4 Fabric-SDK-go及web應用

2021-08-17 08:21:42 區塊鏈

說在前面
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

標籤:區塊鏈

上一篇:(五)Fabric1.4 在自己專案中安裝區塊鏈瀏覽器blockchain-explorer

下一篇:股價回到起點的Coinbase,三季度有什么展望?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • JAVA使用 web3j 進行token轉賬

    最近新學習了下區塊鏈這方面的知識,所學不多,給大家分享下。 # 1. 關于web3j web3j是一個高度模塊化,反應性,型別安全的Java和Android庫,用于與智能合約配合并與以太坊網路上的客戶端(節點)集成。 # 2. 準備作業 jdk版本1.8 引入maven <dependency> < ......

    uj5u.com 2020-09-10 03:03:06 more
  • 以太坊智能合約開發框架Truffle

    前言 部署智能合約有多種方式,命令列的瀏覽器的渠道都有,但往往跟我們程式員的風格不太相符,因為我們習慣了在IDE里寫了代碼然后打包運行看效果。 雖然現在IDE中已經存在了Solidity插件,可以撰寫智能合約,但是部署智能合約卻要另走他路,沒辦法進行一個快捷的部署與測驗。 如果團隊管理的區塊節點多、 ......

    uj5u.com 2020-09-10 03:03:12 more
  • 谷歌二次驗證碼成為區塊鏈專用安全碼,你怎么看?

    前言 谷歌身份驗證器,前些年大家都比較陌生,但隨著國內互聯網安全的加強,它越來越多地出現在大家的視野中。 比較廣泛接觸的人群是國際3A游戲愛好者,游戲盜號現象嚴重+國外賬號安全應用廣泛,這類游戲一般都會要求用戶系結名為“兩步驗證”、“雙重驗證”等,平臺一般都推薦用谷歌身份驗證器。 后來區塊鏈業務風靡 ......

    uj5u.com 2020-09-10 03:03:17 more
  • 密碼學DAY1

    目錄 ##1.1 密碼學基本概念 密碼在我們的生活中有著重要的作用,那么密碼究竟來自何方,為何會產生呢? 密碼學是網路安全、資訊安全、區塊鏈等產品的基礎,常見的非對稱加密、對稱加密、散列函式等,都屬于密碼學范疇。 密碼學有數千年的歷史,從最開始的替換法到如今的非對稱加密演算法,經歷了古典密碼學,近代密 ......

    uj5u.com 2020-09-10 03:03:50 more
  • 密碼學DAY1_02

    目錄 ##1.1 ASCII編碼 ASCII(American Standard Code for Information Interchange,美國資訊交換標準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際標準ISO/IE ......

    uj5u.com 2020-09-10 03:04:50 more
  • 密碼學DAY2

    ##1.1 加密模式 加密模式:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html ECB ECB : Electronic codebook, 電子密碼本. 需要加密的訊息按照塊密碼的塊大小被分為數個塊,并對每個塊進 ......

    uj5u.com 2020-09-10 03:05:42 more
  • NTP時鐘服務器的特點(京準電子)

    NTP時鐘服務器的特點(京準電子) NTP時鐘服務器的特點(京準電子) 京準電子官V——ahjzsz 首先對時間同步進行了背景介紹,然后討論了不同的時間同步網路技術,最后指出了建立全球或區域時間同步網存在的問題。 一、概 述 在通信領域,“同步”概念是指頻率的同步,即網路各個節點的時鐘頻率和相位同步 ......

    uj5u.com 2020-09-10 03:05:47 more
  • 標準化考場時鐘同步系統推進智能化校園建設

    標準化考場時鐘同步系統推進智能化校園建設 標準化考場時鐘同步系統推進智能化校園建設 安徽京準電子科技官微——ahjzsz 一、背景概述隨著教育事業的快速發展,學校建設如雨后春筍,隨之而來的學校教育、管理、安全方面的問題成了學校管理人員面臨的最大的挑戰,這些問題同時也是學生家長所擔心的。為了讓學生有更 ......

    uj5u.com 2020-09-10 03:05:51 more
  • 位元幣入門

    引言 位元幣基本結構 位元幣基礎知識 1)哈希演算法 2)非對稱加密技術 3)數字簽名 4)MerkleTree 5)哪有位元幣,有的是UTXO 6)位元幣挖礦與共識 7)區塊驗證(共識) 總結 引言 上一篇我們已經知道了什么是區塊鏈,此篇說一下區塊鏈的第一個應用——位元幣。其實先有位元幣,后有的區塊 ......

    uj5u.com 2020-09-10 03:06:15 more
  • 北斗對時服務器(北斗對時設備)電力系統應用

    北斗對時服務器(北斗對時設備)電力系統應用 北斗對時服務器(北斗對時設備)電力系統應用 京準電子科技官微(ahjzsz) 中國北斗衛星導航系統(英文名稱:BeiDou Navigation Satellite System,簡稱BDS),因為是目前世界范圍內唯一可以大面積提供免費定位服務的系統,所以 ......

    uj5u.com 2020-09-10 03:06:20 more
最新发布
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:46:47 more
  • Hyperledger Fabric 使用 CouchDB 和復雜智能合約開發

    在上個實驗中,我們已經實作了簡單智能合約實作及客戶端開發,但該實驗中智能合約只有基礎的增刪改查功能,且其中的資料管理功能與傳統 MySQL 比相差甚遠。本文將在前面實驗的基礎上,將 Hyperledger Fabric 的默認資料庫支持 LevelDB 改為 CouchDB 模式,以實作更復雜的資料... ......

    uj5u.com 2023-04-16 07:28:31 more
  • .NET Core 波場鏈離線簽名、廣播交易(發送 TRX和USDT)筆記

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. PM> Install-Package Tron.Wallet.Net 配置 public reco ......

    uj5u.com 2023-04-14 08:08:00 more
  • DKP 黑客分析——不正確的代幣對比率計算

    概述: 2023 年 2 月 8 日,針對 DKP 協議的閃電貸攻擊導致該協議的用戶損失了 8 萬美元,因為 execute() 函式取決于 USDT-DKP 對中兩種代幣的余額比率。 智能合約黑客概述: 攻擊者的交易:0x0c850f,0x2d31 攻擊者地址:0xF38 利用合同:0xf34ad ......

    uj5u.com 2023-04-07 07:46:09 more
  • Defi開發簡介

    Defi開發簡介 介紹 Defi是去中心化金融的縮寫, 是一項旨在利用區塊鏈技術和智能合約創建更加開放,可訪問和透明的金融體系的運動. 這與傳統金融形成鮮明對比,傳統金融通常由少數大型銀行和金融機構控制 在Defi的世界里,用戶可以直接從他們的電腦或移動設備上訪問廣泛的金融服務,而不需要像銀行或者信 ......

    uj5u.com 2023-04-05 08:01:34 more
  • solidity簡單的ERC20代幣實作

    // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "hardhat/console.sol"; //ERC20 同質化代幣,每個代幣的本質或性質都是相同 //ETH 是原生代幣,它不是ERC20代幣, ......

    uj5u.com 2023-03-21 07:56:29 more
  • solidity 參考型別修飾符memory、calldata與storage 常量修飾符C

    在solidity語言中 參考型別修飾符(參考型別為存盤空間不固定的數值型別) memory、calldata與storage,它們只能修飾參考型別變數,比如字串、陣列、位元組等... memory 適用于方法傳參、返參或在方法體內使用,使用完就會清除掉,釋放記憶體 calldata 僅適用于方法傳參 ......

    uj5u.com 2023-03-08 07:57:54 more
  • solidity注解標簽

    在solidity語言中 注釋符為// 注解符為/* 內容*/ 或者 是 ///內容 注解中含有這幾個標簽給予我們使用 @title 一個應該描述合約/介面的標題 contract, library, interface @author 作者的名字 contract, library, interf ......

    uj5u.com 2023-03-08 07:57:49 more
  • 評價指標:相似度、GAS消耗

    【代碼注釋自動生成方法綜述】 這些評測指標主要來自機器翻譯和文本總結等研究領域,可以評估候選文本(即基于代碼注釋自動方法而生成)和參考文本(即基于手工方式而生成)的相似度. BLEU指標^[^?88^^?^]^:其全稱是bilingual evaluation understudy.該指標是最早用于 ......

    uj5u.com 2023-02-23 07:27:39 more
  • 基于NOSTR協議的“公有制”版本的Twitter,去中心化社交軟體Damus

    最近,一個幽靈,Web3的幽靈,在網路游蕩,它叫Damus,這玩意詮釋了什么叫做病毒式營銷,滑稽的是,一個Web3產品卻在Web2的產品鏈上瘋狂傳銷,各方大佬紛紛為其背書,到底發生了什么?Damus的葫蘆里,賣的是什么藥? 注冊和簡單實用 很少有什么產品在用戶注冊環節會有什么噱頭,但Damus確實出 ......

    uj5u.com 2023-02-05 06:48:39 more