mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
Compare commits
5 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad8fc2fba7 | ||
|
|
e496083c0b | ||
|
|
46b92e22da | ||
|
|
42c7d4a142 | ||
|
|
b2a89cffbc |
1347 changed files with 31237 additions and 142325 deletions
53
.github/actions/fsat-setup/action.yaml
vendored
53
.github/actions/fsat-setup/action.yaml
vendored
|
|
@ -1,53 +0,0 @@
|
|||
name: Set up the Full Stack Asset Transfer Guide Dependencies
|
||||
description: Set up the Full Stack Asset Transfer Guide Dependencies
|
||||
inputs:
|
||||
node-version:
|
||||
description: Version of node
|
||||
default: "lts/*"
|
||||
just-version:
|
||||
description: Just Version
|
||||
default: "1.43.0"
|
||||
k9s-version:
|
||||
description: k9s Version
|
||||
default: v0.50.15
|
||||
fabric-version:
|
||||
description: Version of Hyperledger Fabric
|
||||
default: "2.5.15"
|
||||
ca-version:
|
||||
description: Version of Hyperledger Fabric CA
|
||||
default: "1.5.15"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
|
||||
- name: Install k9s
|
||||
shell: bash
|
||||
run: |
|
||||
curl --fail --silent --show-error -L https://github.com/derailed/k9s/releases/download/${{ inputs.k9s-version }}/k9s_Linux_amd64.tar.gz -o /tmp/k9s_Linux_amd64.tar.gz
|
||||
tar -zxf /tmp/k9s_Linux_amd64.tar.gz -C /usr/local/bin k9s
|
||||
sudo chown root /usr/local/bin/k9s
|
||||
sudo chmod 755 /usr/local/bin/k9s
|
||||
|
||||
- name: Install just
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: just@${{ inputs.just-version }}
|
||||
|
||||
- name: Install weft
|
||||
shell: bash
|
||||
run: |
|
||||
npm install -g @hyperledger-labs/weft
|
||||
|
||||
- name: Install fabric CLI
|
||||
shell: bash
|
||||
working-directory: full-stack-asset-transfer-guide
|
||||
run: |
|
||||
curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh \
|
||||
| bash -s -- binary --fabric-version ${{ inputs.fabric-version }} --ca-version ${{ inputs.ca-version }}
|
||||
echo ${PWD}/bin >> $GITHUB_PATH
|
||||
63
.github/actions/test-network-setup/action.yaml
vendored
63
.github/actions/test-network-setup/action.yaml
vendored
|
|
@ -1,63 +0,0 @@
|
|||
name: Set up Test Network Runner
|
||||
description: Set up the Test Network Runtime
|
||||
inputs:
|
||||
go-version:
|
||||
description: Version of go
|
||||
default: stable
|
||||
node-version:
|
||||
description: Version of node
|
||||
default: "lts/*"
|
||||
java-version:
|
||||
description: Version of JDK
|
||||
default: 25.x
|
||||
fabric-version:
|
||||
description: Version of Hyperledger Fabric
|
||||
default: 2.5.15
|
||||
ca-version:
|
||||
description: Version of Hyperledger Fabric CA
|
||||
default: 1.5.15
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
cache-dependency-path: "**/go.sum"
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: ${{ inputs.java-version }}
|
||||
cache: gradle
|
||||
|
||||
- name: Install fabric CLI
|
||||
shell: bash
|
||||
run: |
|
||||
curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh \
|
||||
| bash -s -- binary --fabric-version ${{ inputs.fabric-version }} --ca-version ${{ inputs.ca-version }}
|
||||
echo ${PWD}/bin >> $GITHUB_PATH
|
||||
|
||||
- name: Pull Fabric Docker Images
|
||||
shell: bash
|
||||
run: |
|
||||
curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh \
|
||||
| bash -s -- docker --fabric-version ${{ inputs.fabric-version }} --ca-version ${{ inputs.ca-version }}
|
||||
|
||||
- name: Pull chaincode container images
|
||||
shell: bash
|
||||
run: |
|
||||
docker pull ghcr.io/hyperledger/fabric-nodeenv:2.5
|
||||
docker tag ghcr.io/hyperledger/fabric-nodeenv:2.5 hyperledger/fabric-nodeenv:2.5
|
||||
docker pull ghcr.io/hyperledger/fabric-javaenv:2.5
|
||||
docker tag ghcr.io/hyperledger/fabric-javaenv:2.5 hyperledger/fabric-javaenv:2.5
|
||||
|
||||
- name: Install retry CLI
|
||||
shell: bash
|
||||
run: curl -sSL https://raw.githubusercontent.com/kadwanev/retry/master/retry -o ./bin/retry && chmod +x ./bin/retry
|
||||
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
|
|
@ -1,6 +0,0 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
8
.github/settings.yml
vendored
8
.github/settings.yml
vendored
|
|
@ -1,10 +1,10 @@
|
|||
repository:
|
||||
name: fabric-samples
|
||||
description: Samples for Hyperledger Fabric
|
||||
homepage: https://lf-hyperledger.atlassian.net/wiki/spaces/fabric
|
||||
default_branch: main
|
||||
description: null
|
||||
homepage: https://wiki.hyperledger.org/display/fabric
|
||||
default_branch: master
|
||||
has_downloads: true
|
||||
has_issues: true
|
||||
has_issues: false
|
||||
has_projects: false
|
||||
has_wiki: false
|
||||
archived: false
|
||||
|
|
|
|||
65
.github/workflows/lint.yaml
vendored
65
.github/workflows/lint.yaml
vendored
|
|
@ -1,65 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Lint 🎉
|
||||
run-name: ${{ github.actor }} is linting fabric-samples 🎉
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["main", "release-2.5"]
|
||||
pull_request:
|
||||
branches: ["main", "release-2.5"]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
NODE_VER: "lts/*"
|
||||
JAVA_VER: 25.x
|
||||
|
||||
jobs:
|
||||
go:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: actions/checkout@v6
|
||||
- run: go install golang.org/x/tools/cmd/goimports@latest
|
||||
- run: ci/scripts/lint-go.sh
|
||||
|
||||
typescript:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VER }}
|
||||
- run: ci/scripts/lint-typescript.sh
|
||||
|
||||
javascript:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VER }}
|
||||
- run: ci/scripts/lint-javascript.sh
|
||||
|
||||
java:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: ${{ env.JAVA_VER }}
|
||||
- run: ci/scripts/lint-java.sh
|
||||
|
||||
shell:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- run: ci/scripts/lint-shell.sh
|
||||
58
.github/workflows/rest-sample.yaml
vendored
58
.github/workflows/rest-sample.yaml
vendored
|
|
@ -1,58 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: REST Sample 🐧
|
||||
run-name: ${{ github.actor }} is testing the REST Sample 🐧
|
||||
|
||||
env:
|
||||
NODE_VER: "lts/*"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["main", "release-2.5"]
|
||||
paths: ["asset-transfer-basic/rest-api-typescript/**"]
|
||||
pull_request:
|
||||
branches: ["main", "release-2.5"]
|
||||
paths: ["asset-transfer-basic/rest-api-typescript/**"]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test-sample:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VER }}
|
||||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
|
||||
- name: Install REST Sample Dependencies
|
||||
working-directory: asset-transfer-basic/rest-api-typescript
|
||||
run: npm install
|
||||
|
||||
- name: Build REST Sample Application
|
||||
run: npm run build
|
||||
working-directory: asset-transfer-basic/rest-api-typescript
|
||||
|
||||
- name: Test REST Sample Application
|
||||
run: npm test
|
||||
working-directory: asset-transfer-basic/rest-api-typescript
|
||||
|
||||
- name: Build REST Sample Docker Image
|
||||
run: docker build -t ghcr.io/hyperledger/fabric-rest-sample .
|
||||
working-directory: asset-transfer-basic/rest-api-typescript
|
||||
|
||||
- name: Publish REST Sample Docker Image
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main')
|
||||
run: |
|
||||
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
docker push ghcr.io/hyperledger/fabric-rest-sample:latest
|
||||
working-directory: asset-transfer-basic/rest-api-typescript
|
||||
59
.github/workflows/test-fsat.yaml
vendored
59
.github/workflows/test-fsat.yaml
vendored
|
|
@ -1,59 +0,0 @@
|
|||
name: Full Stack Asset Transfer Guide 🚀
|
||||
run-name: ${{ github.actor }} is testing the Full Stack Asset Transfer Guide 🚀
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
- "release-2.5"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
ansible:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Full Stack Runtime
|
||||
uses: ./.github/actions/fsat-setup
|
||||
- run: just test-ansible
|
||||
working-directory: full-stack-asset-transfer-guide
|
||||
|
||||
appdev:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Full Stack Runtime
|
||||
uses: ./.github/actions/fsat-setup
|
||||
- run: just test-appdev
|
||||
working-directory: full-stack-asset-transfer-guide
|
||||
|
||||
chaincode:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Full Stack Runtime
|
||||
uses: ./.github/actions/fsat-setup
|
||||
- run: just test-chaincode
|
||||
working-directory: full-stack-asset-transfer-guide
|
||||
|
||||
cloud:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Full Stack Runtime
|
||||
uses: ./.github/actions/fsat-setup
|
||||
- run: just test-cloud
|
||||
working-directory: full-stack-asset-transfer-guide
|
||||
|
||||
console:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Full Stack Runtime
|
||||
uses: ./.github/actions/fsat-setup
|
||||
- run: just test-console
|
||||
working-directory: full-stack-asset-transfer-guide
|
||||
49
.github/workflows/test-high-throughput.yaml
vendored
49
.github/workflows/test-high-throughput.yaml
vendored
|
|
@ -1,49 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test High Throughput
|
||||
run-name: ${{ github.actor }} is running the High Throughput tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["main", "release-2.5"]
|
||||
pull_request:
|
||||
branches: ["main", "release-2.5"]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
basic:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Start Fabric
|
||||
working-directory: high-throughput
|
||||
run: ./startFabric.sh
|
||||
|
||||
- name: Test High Throughput
|
||||
working-directory: high-throughput/application-go
|
||||
run: |
|
||||
go run . manyUpdates testvar1 100 +
|
||||
go run . prune testvar1
|
||||
go run . get testvar1
|
||||
go run . update testvar1 100 +
|
||||
go run . get testvar1
|
||||
go run . delete testvar1
|
||||
go run . manyUpdatesTraditional testvar2 100 +
|
||||
go run . getstandard testvar2
|
||||
go run . updatestandard testvar2 100 +
|
||||
go run . getstandard testvar2
|
||||
go run . delstandard testvar2
|
||||
|
||||
- name: Stop Fabric
|
||||
working-directory: high-throughput
|
||||
run: ./networkDown.sh
|
||||
39
.github/workflows/test-network-basic.yaml
vendored
39
.github/workflows/test-network-basic.yaml
vendored
|
|
@ -1,39 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network Basic 🔎
|
||||
run-name: ${{ github.actor }} is running the Test Network Basic tests 🔎
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
basic:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
- javascript
|
||||
- typescript
|
||||
- java
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Run Test Network Basic
|
||||
working-directory: test-network
|
||||
run: ../ci/scripts/run-test-network-basic.sh
|
||||
env:
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
49
.github/workflows/test-network-bft-orderer.yaml
vendored
49
.github/workflows/test-network-bft-orderer.yaml
vendored
|
|
@ -1,49 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network BFT Orderer 🍟
|
||||
run-name: ${{ github.actor }} is running the Test Network with BFT Orderer tests 🍟
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
basic:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
- javascript
|
||||
- typescript
|
||||
- java
|
||||
crypto:
|
||||
- cryptogen
|
||||
- ca
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
# Note: The default Fabric version for CI is currently the latest LTS (v2.5.x).
|
||||
# To test BFT Orderers, Fabric v3.x is explicitly specified here.
|
||||
with:
|
||||
fabric-version: 3.1.4
|
||||
|
||||
- name: Run Test Network with BFT Orderers
|
||||
working-directory: test-network
|
||||
run: ../ci/scripts/run-test-network-basic.sh
|
||||
env:
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
ORDERER_TYPE: bft
|
||||
CRYPTO: ${{ matrix.crypto }}
|
||||
41
.github/workflows/test-network-events.yaml
vendored
41
.github/workflows/test-network-events.yaml
vendored
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network Events 💡
|
||||
run-name: ${{ github.actor }} is running the Test Network Events tests 💡
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
events:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
- javascript
|
||||
- java
|
||||
chaincode-name:
|
||||
- events
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Run Test
|
||||
working-directory: test-network
|
||||
run: ../ci/scripts/run-test-network-events.sh
|
||||
env:
|
||||
CHAINCODE_NAME: ${{ matrix.chaincode-name }}
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
51
.github/workflows/test-network-hsm.yaml
vendored
51
.github/workflows/test-network-hsm.yaml
vendored
|
|
@ -1,51 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network HSM 🍏
|
||||
run-name: ${{ github.actor }} is running the Test Network HSM tests 🍏
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
hsm:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
- javascript
|
||||
- typescript
|
||||
- java
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Install SoftHSM
|
||||
run: sudo apt install -y softhsm2
|
||||
|
||||
- name: Set up SoftHSM
|
||||
env:
|
||||
TMPDIR: ${{ runner.temp }}
|
||||
SOFTHSM2_CONF: ${{ github.workspace }}/softhsm2.conf
|
||||
run: |
|
||||
echo "directories.tokendir = ${TMPDIR}" > "${SOFTHSM2_CONF}"
|
||||
softhsm2-util --init-token --slot 0 --label "ForFabric" --pin 98765432 --so-pin 1234
|
||||
|
||||
- name: Run Test Network HSM
|
||||
working-directory: test-network
|
||||
env:
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
SOFTHSM2_CONF: ${{ github.workspace }}/softhsm2.conf
|
||||
run: ../ci/scripts/run-test-network-hsm.sh
|
||||
124
.github/workflows/test-network-k8s.yaml
vendored
124
.github/workflows/test-network-k8s.yaml
vendored
|
|
@ -1,124 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Kubernetes Test Network 🍒
|
||||
run-name: ${{ github.actor }} is testing the Kubernetes Test Network 🍒
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
ccaas-java:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Test the network
|
||||
id: run-test
|
||||
working-directory: test-network-k8s
|
||||
run: ../ci/scripts/run-k8s-test-network-basic.sh
|
||||
env:
|
||||
CLIENT_LANGUAGE: typescript
|
||||
CHAINCODE_LANGUAGE: java
|
||||
- name: Upload failure logs
|
||||
if: ${{ failure() && steps.run-test.conclusion == 'failure' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ github.job }}-logs
|
||||
path: test-network-k8s/network-debug.log
|
||||
|
||||
ccaas-external:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Test the network
|
||||
id: run-test
|
||||
working-directory: test-network-k8s
|
||||
run: ../ci/scripts/run-k8s-test-network-basic.sh
|
||||
env:
|
||||
CLIENT_LANGUAGE: typescript
|
||||
CHAINCODE_LANGUAGE: external
|
||||
- name: Upload failure logs
|
||||
if: ${{ failure() && steps.run-test.conclusion == 'failure' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ github.job }}-logs
|
||||
path: test-network-k8s/network-debug.log
|
||||
|
||||
k8s-builder:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Test the network
|
||||
id: run-test
|
||||
working-directory: test-network-k8s
|
||||
run: ../ci/scripts/run-k8s-test-network-basic.sh
|
||||
env:
|
||||
CHAINCODE_NAME: basic
|
||||
CHAINCODE_LANGUAGE: java
|
||||
CHAINCODE_BUILDER: k8s
|
||||
- name: Upload failure logs
|
||||
if: ${{ failure() && steps.run-test.conclusion == 'failure' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ github.job }}-logs
|
||||
path: test-network-k8s/network-debug.log
|
||||
|
||||
multi-namespace:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Test the network
|
||||
id: run-test
|
||||
working-directory: test-network-k8s
|
||||
run: ../ci/scripts/run-k8s-test-network-basic.sh
|
||||
env:
|
||||
ORG0_NS: org0-namespace
|
||||
ORG1_NS: org1-namespace
|
||||
ORG2_NS: org2-namespace
|
||||
CHAINCODE_NAME: basic
|
||||
CHAINCODE_LANGUAGE: java
|
||||
CHAINCODE_BUILDER: k8s
|
||||
- name: Upload failure logs
|
||||
if: ${{ failure() && steps.run-test.conclusion == 'failure' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ github.job }}-logs
|
||||
path: test-network-k8s/network-debug.log
|
||||
|
||||
bft-orderer:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
# This job requires Fabric v3.0 or later, which is only supported on 'main'.
|
||||
# Ensure it does not run on 'release-2.5' or earlier versions.
|
||||
if: ${{ github.ref == 'refs/heads/main' || github.event.pull_request.base.ref == 'main' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Test the network
|
||||
id: run-test
|
||||
working-directory: test-network-k8s
|
||||
run: ../ci/scripts/run-k8s-test-network-basic.sh
|
||||
env:
|
||||
CLIENT_LANGUAGE: typescript
|
||||
CHAINCODE_LANGUAGE: java
|
||||
# Note: The default Fabric version for CI is currently the latest LTS (v2.5.x).
|
||||
# To test BFT Orderers, Fabric v3.x is explicitly specified here.
|
||||
FABRIC_VERSION: '3.1'
|
||||
ORDERER_TYPE: bft
|
||||
- name: Upload failure logs
|
||||
if: ${{ failure() && steps.run-test.conclusion == 'failure' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ github.job }}-logs
|
||||
path: test-network-k8s/network-debug.log
|
||||
41
.github/workflows/test-network-ledger.yaml
vendored
41
.github/workflows/test-network-ledger.yaml
vendored
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network Ledger 🥑
|
||||
run-name: ${{ github.actor }} is running the Test Network Ledger tests 🥑
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
basic:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
- javascript
|
||||
- typescript
|
||||
chaincode-name:
|
||||
- ledger
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Run Test
|
||||
working-directory: test-network
|
||||
run: ../ci/scripts/run-test-network-ledger.sh
|
||||
env:
|
||||
CHAINCODE_NAME: ${{ matrix.chaincode-name }}
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
39
.github/workflows/test-network-off-chain.yaml
vendored
39
.github/workflows/test-network-off-chain.yaml
vendored
|
|
@ -1,39 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network Off Chain 🍔
|
||||
run-name: ${{ github.actor }} is running the Test Network Off Chain tests 🍔
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
off-chain:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
- javascript
|
||||
- typescript
|
||||
- java
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Run Test Network Off Chain
|
||||
working-directory: test-network
|
||||
env:
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
run: ../ci/scripts/run-test-network-off-chain.sh
|
||||
41
.github/workflows/test-network-private.yaml
vendored
41
.github/workflows/test-network-private.yaml
vendored
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network Private 🔒
|
||||
run-name: ${{ github.actor }} is running the Test Network Private tests 🔒
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["main", "release-2.5"]
|
||||
pull_request:
|
||||
branches: ["main", "release-2.5"]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
private:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
- java
|
||||
- typescript
|
||||
chaincode-name:
|
||||
- private
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Run Test
|
||||
working-directory: test-network
|
||||
run: ../ci/scripts/run-test-network-private.sh
|
||||
env:
|
||||
CHAINCODE_NAME: ${{ matrix.chaincode-name }}
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
40
.github/workflows/test-network-sbe.yaml
vendored
40
.github/workflows/test-network-sbe.yaml
vendored
|
|
@ -1,40 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network SBE 🎵
|
||||
run-name: ${{ github.actor }} is running the Test Network SBE tests 🎵
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
SBE:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- typescript
|
||||
- java
|
||||
chaincode-name:
|
||||
- sbe
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Run Test
|
||||
working-directory: test-network
|
||||
run: ../ci/scripts/run-test-network-sbe.sh
|
||||
env:
|
||||
CHAINCODE_NAME: ${{ matrix.chaincode-name }}
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
39
.github/workflows/test-network-secured.yaml
vendored
39
.github/workflows/test-network-secured.yaml
vendored
|
|
@ -1,39 +0,0 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
name: Test Network Secured 🔔
|
||||
run-name: ${{ github.actor }} is running the Test Network Secured tests 🔔
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
pull_request:
|
||||
branches: [ "main", "release-2.5" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
secured:
|
||||
runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
chaincode-language:
|
||||
- go
|
||||
chaincode-name:
|
||||
- secured
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up the test network runtime
|
||||
uses: ./.github/actions/test-network-setup
|
||||
|
||||
- name: Run Test
|
||||
working-directory: test-network
|
||||
run: ../ci/scripts/run-test-network-secured.sh
|
||||
env:
|
||||
CHAINCODE_NAME: ${{ matrix.chaincode-name }}
|
||||
CHAINCODE_LANGUAGE: ${{ matrix.chaincode-language }}
|
||||
20
.gitignore
vendored
20
.gitignore
vendored
|
|
@ -4,6 +4,9 @@
|
|||
.#*
|
||||
# Vim file artifacts
|
||||
.*.sw*
|
||||
# installed platform-specific binaries
|
||||
/bin
|
||||
/config
|
||||
.DS_Store
|
||||
.project
|
||||
# omit Go vendor directories
|
||||
|
|
@ -15,19 +18,4 @@ vendor/
|
|||
node_modules/
|
||||
# Ignore Gradle build output directory
|
||||
build
|
||||
# Ignore Maven build output directory
|
||||
target
|
||||
|
||||
# Eclipse
|
||||
.classpath
|
||||
.settings
|
||||
|
||||
# installed Fabric binaries etc.
|
||||
/bin/
|
||||
builders/
|
||||
config/
|
||||
external-chaincode/
|
||||
install-fabric.sh
|
||||
|
||||
# override the ignore of all config/ folders
|
||||
!full-stack-asset-transfer-guide/infrastructure/sample-network/config
|
||||
package-lock.json
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Fabric Samples Maintainers
|
||||
# Fabric Samples Maintaners
|
||||
* @hyperledger/fabric-samples-maintainers
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ Code of Conduct Guidelines
|
|||
==========================
|
||||
|
||||
Please review the Hyperledger [Code of
|
||||
Conduct](https://lf-hyperledger.atlassian.net/wiki/spaces/HYP/pages/19595281/Hyperledger+Code+of+Conduct)
|
||||
Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct)
|
||||
before participating. It is important that we keep things civil.
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
|
||||
|
|
|
|||
|
|
@ -3,12 +3,18 @@ Maintainers
|
|||
|
||||
fabric-samples uses a non-author code review policy, requiring a single approval from a non-author maintainer.
|
||||
|
||||
| Name | GitHub | Discord ID | email |
|
||||
|---------------------------|------------------|------------------|-------------------------------------|
|
||||
| Dave Enyeart | denyeart | Dave Enyeart | enyeart@us.ibm.com |
|
||||
| Mark Lewis | bestbeforetoday | bestbeforetoday | Mark.S.Lewis@outlook.com |
|
||||
| Tatsuya Sato | satota2 | satota2 | tatsuya.sato.so@hitachi.com |
|
||||
| Name | GitHub | Chat | email |
|
||||
|---------------------------|------------------|----------------|-------------------------------------|
|
||||
| Arnaud Le Hors | lehors | lehors | lehors@us.ibm.com |
|
||||
| Bret Harrison | harrisob | bretharrison | harrisob@us.ibm.com |
|
||||
| Chris Ferris | christo4ferris | cbf | chris.ferris@gmail.com |
|
||||
| Dave Enyeart | denyeart | dave.enyeart | enyeart@us.ibm.com |
|
||||
| Gari Singh | mastersingh24 | mastersingh24 | gari.r.singh@gmail.com |
|
||||
| Jason Yellick | jyellick | jyellick | jyellick@us.ibm.com |
|
||||
| Matthew B White | mbwhite | mbwhite | whitemat@uk.ibm.com |
|
||||
| Nikhil Gupta | nikhil550 | negupta | nikhilg550@gmail.com |
|
||||
| Simon Stone | sstone1 | sstone1 | sstone1@uk.ibm.com |
|
||||
|
||||
Also: Please see the [Release Manager section](https://github.com/hyperledger/fabric/blob/main/MAINTAINERS.md)
|
||||
Also: Please see the [Release Manager section](https://github.com/hyperledger/fabric/blob/master/MAINTAINERS.md)
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
|
||||
|
|
|
|||
38
README.md
38
README.md
|
|
@ -4,11 +4,6 @@
|
|||
|
||||
You can use Fabric samples to get started working with Hyperledger Fabric, explore important Fabric features, and learn how to build applications that can interact with blockchain networks using the Fabric SDKs. To learn more about Hyperledger Fabric, visit the [Fabric documentation](https://hyperledger-fabric.readthedocs.io/en/latest).
|
||||
|
||||
Note that this branch contains samples for the latest Fabric release. For older Fabric versions, refer to the corresponding branches:
|
||||
|
||||
- [release-2.2](https://github.com/hyperledger/fabric-samples/tree/release-2.2)
|
||||
- [release-1.4](https://github.com/hyperledger/fabric-samples/tree/release-1.4)
|
||||
|
||||
## Getting started with the Fabric samples
|
||||
|
||||
To use the Fabric samples, you need to download the Fabric Docker images and the Fabric CLI tools. First, make sure that you have installed all of the [Fabric prerequisites](https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html). You can then follow the instructions to [Install the Fabric Samples, Binaries, and Docker Images](https://hyperledger-fabric.readthedocs.io/en/latest/install.html) in the Fabric documentation. In addition to downloading the Fabric images and tool binaries, the Fabric samples will also be cloned to your local machine.
|
||||
|
|
@ -20,12 +15,6 @@ Organization peers and an ordering service node. You can use it on your local ma
|
|||
You can also use it to deploy and test your own Fabric chaincodes and applications. To get started, see
|
||||
the [test network tutorial](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html).
|
||||
|
||||
The [Kubernetes Test Network](test-network-k8s) sample builds upon the Compose network, constructing a Fabric
|
||||
network with peer, orderer, and CA infrastructure nodes running on Kubernetes. In addition to providing a sample
|
||||
Kubernetes guide, the Kube test network can be used as a platform to author and debug _cloud ready_ Fabric Client
|
||||
applications on a development or CI workstation.
|
||||
|
||||
|
||||
## Asset transfer samples and tutorials
|
||||
|
||||
The asset transfer series provides a series of sample smart contracts and applications to demonstrate how to store and transfer assets using Hyperledger Fabric.
|
||||
|
|
@ -36,17 +25,15 @@ transfer an asset in a more realistic transfer scenario.
|
|||
|
||||
| **Smart Contract** | **Description** | **Tutorial** | **Smart contract languages** | **Application languages** |
|
||||
| -----------|------------------------------|----------|---------|---------|
|
||||
| [Basic](asset-transfer-basic) | The Basic sample smart contract that allows you to create and transfer an asset by putting data on the ledger and retrieving it. This sample is recommended for new Fabric users. | [Writing your first application](https://hyperledger-fabric.readthedocs.io/en/latest/write_first_app.html) | Go, JavaScript, TypeScript, Java | Go, TypeScript, Java |
|
||||
| [Basic](asset-transfer-basic) | The Basic sample smart contract that allows you to create and transfer an asset by putting data on the ledger and retrieving it. This sample is recommended for new Fabric users. | [Writing your first application](https://hyperledger-fabric.readthedocs.io/en/latest/write_first_app.html) | Go, JavaScript, TypeScript, Java | Go, JavaScript, TypeScript, Java |
|
||||
| [Ledger queries](asset-transfer-ledger-queries) | The ledger queries sample demonstrates range queries and transaction updates using range queries (applicable for both LevelDB and CouchDB state databases), and how to deploy an index with your chaincode to support JSON queries (applicable for CouchDB state database only). | [Using CouchDB](https://hyperledger-fabric.readthedocs.io/en/latest/couchdb_tutorial.html) | Go, JavaScript | Java, JavaScript |
|
||||
| [Private data](asset-transfer-private-data) | This sample demonstrates the use of private data collections, how to manage private data collections with the chaincode lifecycle, and how the private data hash can be used to verify private data on the ledger. It also demonstrates how to control asset updates and transfers using client-based ownership and access control. | [Using Private Data](https://hyperledger-fabric.readthedocs.io/en/latest/private_data_tutorial.html) | Go, TypeScript, Java | TypeScript |
|
||||
| [State-Based Endorsement](asset-transfer-sbe) | This sample demonstrates how to override the chaincode-level endorsement policy to set endorsement policies at the key-level (data/asset level). | [Using State-based endorsement](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-sbe) | Java, TypeScript | JavaScript |
|
||||
| [Secured agreement](asset-transfer-secured-agreement) | Smart contract that uses implicit private data collections, state-based endorsement, and organization-based ownership and access control to keep data private and securely transfer an asset with the consent of both the current owner and buyer. | [Secured asset transfer](https://hyperledger-fabric.readthedocs.io/en/latest/secured_asset_transfer/secured_private_asset_transfer_tutorial.html) | Go | TypeScript |
|
||||
| [Events](asset-transfer-events) | The events sample demonstrates how smart contracts can emit events that are read by the applications interacting with the network. | [README](asset-transfer-events/README.md) | Go, JavaScript, Java | Go, TypeScript, Java |
|
||||
| [Attribute-based access control](asset-transfer-abac) | Demonstrates the use of attribute and identity based access control using a simple asset transfer scenario | [README](asset-transfer-abac/README.md) | Go | _None_ |
|
||||
| [Private data](asset-transfer-private-data) | This sample demonstrates the use of private data collections, how to manage private data collections with the chaincode lifecycle, and how the private data hash can be used to verify private data on the ledger. It also demonstrates how to control asset updates and transfers using client-based ownership and access control. | [Using Private Data](https://hyperledger-fabric.readthedocs.io/en/latest/private_data_tutorial.html) | Go, Java | JavaScript |
|
||||
| [State-Based Endorsement](asset-transfer-sbe) | This sample demonstrates how to override the chaincode-level endorsement policy to set endorsement policies at the key-level (data/asset level). | [Using State-based endorsement](https://github.com/hyperledger/fabric-samples/tree/master/asset-transfer-sbe) | Java, TypeScript | JavaScript |
|
||||
| [Secured agreement](asset-transfer-secured-agreement) | Smart contract that uses implicit private data collections, state-based endorsement, and organization-based ownership and access control to keep data private and securely transfer an asset with the consent of both the current owner and buyer. | [Secured asset transfer](https://hyperledger-fabric.readthedocs.io/en/latest/secured_asset_transfer/secured_private_asset_transfer_tutorial.html) | Go | JavaScript |
|
||||
| [Events](asset-transfer-events) | The events sample demonstrates how smart contracts can emit events that are read by the applications interacting with the network. | [README](asset-transfer-events/README.md) | JavaScript, Java | JavaScript |
|
||||
| [Attribute-based access control](asset-transfer-abac) | Demonstrates the use of attribute and identity based access control using a simple asset transfer scenario | [README](asset-transfer-abac/README.md) | Go | None |
|
||||
|
||||
## Full stack asset transfer guide
|
||||
|
||||
The [full stack asset transfer guide](full-stack-asset-transfer-guide#readme) workshop demonstrates how a generic asset transfer solution for Hyperledger Fabric can be developed and deployed. This covers chaincode development, client application development, and deployment to a production-like environment.
|
||||
|
||||
## Additional samples
|
||||
|
||||
|
|
@ -54,16 +41,15 @@ Additional samples demonstrate various Fabric use cases and application patterns
|
|||
|
||||
| **Sample** | **Description** | **Documentation** |
|
||||
| -------------|------------------------------|------------------|
|
||||
| [Off chain data](off_chain_data) | Learn how to use block events to build an off-chain database for reporting and analytics. | [Peer channel-based event services](https://hyperledger-fabric.readthedocs.io/en/latest/peer_event_services.html) |
|
||||
| [Token SDK](token-sdk) | Sample REST API around the Hyperledger Labs [Token SDK](https://github.com/hyperledger-labs/fabric-token-sdk) for privacy friendly (zero knowledge proof) UTXO transactions. | [README](token-sdk/README.md) |
|
||||
| [Commercial paper](commercial-paper) | Explore a use case and detailed application development tutorial in which two organizations use a blockchain network to trade commercial paper. | [Commercial paper tutorial](https://hyperledger-fabric.readthedocs.io/en/latest/tutorial/commercial_paper.html) |
|
||||
| [Off chain data](off_chain_data) | Learn how to use the Peer channel-based event services to build an off-chain database for reporting and analytics. | [Peer channel-based event services](https://hyperledger-fabric.readthedocs.io/en/latest/peer_event_services.html) |
|
||||
| [Token ERC-20](token-erc-20) | Smart contract demonstrating how to create and transfer fungible tokens using an account-based model. | [README](token-erc-20/README.md) |
|
||||
| [Token UTXO](token-utxo) | Smart contract demonstrating how to create and transfer fungible tokens using a UTXO (unspent transaction output) model. | [README](token-utxo/README.md) |
|
||||
| [Token ERC-1155](token-erc-1155) | Smart contract demonstrating how to create and transfer multiple tokens (both fungible and non-fungible) using an account based model. | [README](token-erc-1155/README.md) |
|
||||
| [Token ERC-721](token-erc-721) | Smart contract demonstrating how to create and transfer non-fungible tokens using an account-based model. | [README](token-erc-721/README.md) |
|
||||
| [High throughput](high-throughput) | Learn how you can design your smart contract to avoid transaction collisions in high volume environments. | [README](high-throughput/README.md) |
|
||||
| [Simple Auction](auction-simple) | Run an auction where bids are kept private until the auction is closed, after which users can reveal their bid. | [README](auction-simple/README.md) |
|
||||
| [Dutch Auction](auction-dutch) | Run an auction in which multiple items of the same type can be sold to more than one buyer. This example also includes the ability to add an auditor organization. | [README](auction-dutch/README.md) |
|
||||
|
||||
| [Auction](auction) | Run an auction where bids are kept private until the auction is closed, after which users can reveal their bid | [README](auction/README.md) |
|
||||
| [Chaincode](chaincode) | A set of other sample smart contracts, many of which were used in tutorials prior to the asset transfer sample series. | |
|
||||
| [Interest rate swaps](interest_rate_swaps) | **Deprecated in favor of state based endorsement asset transfer sample** | |
|
||||
| [Fabcar](fabcar) | **Deprecated in favor of basic asset transfer sample** | |
|
||||
|
||||
## License <a name="license"></a>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ If you think you have discovered a security issue in any of the Hyperledger proj
|
|||
|
||||
There are two ways to report a security bug. The easiest is to email a description of the flaw and any related information (e.g. reproduction steps, version) to [security at hyperledger dot org](mailto:security@hyperledger.org).
|
||||
|
||||
The other way is to file a confidential security bug in the repository's [security advisories page](https://github.com/hyperledger/fabric/security/advisories). Guidance can be found in the GitHub documentation on [privately reporting a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability).
|
||||
The other way is to file a confidential security bug in our [JIRA bug tracking system](https://jira.hyperledger.org). Be sure to set the “Security Level” to “Security issue”.
|
||||
|
||||
The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://wiki.hyperledger.org/display/HYP/Defect+Response) on our [wiki](https://wiki.hyperledger.org).
|
||||
|
||||
The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://lf-hyperledger.atlassian.net/wiki/spaces/SEC/pages/20283618/Defect+Response) on our [wiki](https://lf-hyperledger.atlassian.net/wiki).
|
||||
|
|
@ -40,34 +40,34 @@ export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example
|
|||
There are two ways to generate certificates with attributes added. We will use both methods and create two identities in the process. The first method is to specify that the attribute be added to the certificate by default when the identity is registered. The following command will register an identity named creator1 with the attribute of `abac.creator=true`.
|
||||
|
||||
```
|
||||
fabric-ca-client register --id.name creator1 --id.secret creator1pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:ecert' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem"
|
||||
fabric-ca-client register --id.name creator1 --id.secret creator1pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:ecert' --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
|
||||
```
|
||||
|
||||
The `ecert` suffix adds the attribute to the certificate automatically when the identity is enrolled. As a result, the following enroll command will contain the attribute that was provided in the registration command.
|
||||
|
||||
```
|
||||
fabric-ca-client enroll -u https://creator1:creator1pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem"
|
||||
fabric-ca-client enroll -u https://creator1:creator1pw@localhost:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
|
||||
```
|
||||
|
||||
Now that we have enrolled the identity, run the command below to copy the Node OU configuration file into the creator1 MSP folder.
|
||||
```
|
||||
cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp/config.yaml"
|
||||
cp ${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp/config.yaml
|
||||
```
|
||||
|
||||
The second method is to request that the attribute be added upon enrollment. The following command will register an identity named creator2 with the same `abac.creator` attribute.
|
||||
```
|
||||
fabric-ca-client register --id.name creator2 --id.secret creator2pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem"
|
||||
fabric-ca-client register --id.name creator2 --id.secret creator2pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:' --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
|
||||
```
|
||||
|
||||
The following enroll command will add the attribute to the certificate:
|
||||
|
||||
```
|
||||
fabric-ca-client enroll -u https://creator2:creator2pw@localhost:7054 --caname ca-org1 --enrollment.attrs "abac.creator" -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem"
|
||||
fabric-ca-client enroll -u https://creator2:creator2pw@localhost:7054 --caname ca-org1 --enrollment.attrs "abac.creator" -M ${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
|
||||
```
|
||||
|
||||
Run the command below to copy the Node OU configuration file into the creator2 MSP folder.
|
||||
```
|
||||
cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp/config.yaml"
|
||||
cp ${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp/config.yaml
|
||||
```
|
||||
|
||||
## Create an asset
|
||||
|
|
@ -76,16 +76,16 @@ You can use either identity with the `abac.creator=true` attribute to create an
|
|||
|
||||
```
|
||||
export CORE_PEER_TLS_ENABLED=true
|
||||
export CORE_PEER_LOCALMSPID=Org1MSP
|
||||
export CORE_PEER_LOCALMSPID="Org1MSP"
|
||||
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp
|
||||
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
|
||||
export CORE_PEER_ADDRESS=localhost:7051
|
||||
export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt")
|
||||
export TARGET_TLS_OPTIONS="-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
|
||||
```
|
||||
|
||||
Run the following command to create Asset1:
|
||||
```
|
||||
peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset1","blue","20","100"]}'
|
||||
peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset1","blue","20","100"]}'
|
||||
```
|
||||
|
||||
You can use the command below to query the asset on the ledger:
|
||||
|
|
@ -102,7 +102,7 @@ The result will list the creator1 identity as the asset owner. The `GetID()` API
|
|||
As the owner of Asset1, the creator1 identity has the ability to transfer the asset to another owner. In order to transfer the asset, the owner needs to provide the name and issuer of the new owner to the `TransferAsset` function. The `asset-transfer-abac` smart contract has a `GetSubmittingClientIdentity` function that allows users to retrieve their certificate information and provide it to the asset owner out of band (we omit this step). Issue the command below to transfer Asset1 to the user1 identity from Org1 that was created when the test network was deployed:
|
||||
```
|
||||
export RECIPIENT="x509::CN=user1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US"
|
||||
peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"TransferAsset","Args":["Asset1","'"$RECIPIENT"'"]}'
|
||||
peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n abac -c '{"function":"TransferAsset","Args":["Asset1","'"$RECIPIENT"'"]}'
|
||||
```
|
||||
Query the ledger to verify that the asset has a new owner:
|
||||
```
|
||||
|
|
@ -117,7 +117,7 @@ We can see that Asset1 with is now owned by User1:
|
|||
|
||||
Now that the asset has been transferred, the new owner can update the asset properties. The smart contract uses the `GetID()` API to ensure that the update is being submitted by the asset owner. To demonstrate the difference between identity and attribute based access control, lets try to update the asset using the creator1 identity first:
|
||||
```
|
||||
peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}'
|
||||
peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}'
|
||||
```
|
||||
|
||||
Even though creator1 can create new assets, the smart contract detects that the transaction was not submitted by the identity that owns the asset, user1. The command returns the following error:
|
||||
|
|
@ -132,7 +132,7 @@ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.examp
|
|||
|
||||
We can now update the asset. Run the following command to change the asset color from blue to green. All other aspects of the asset will remain unchanged.
|
||||
```
|
||||
peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}'
|
||||
peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}'
|
||||
```
|
||||
Run the query command again to verify that the asset has changed color:
|
||||
```
|
||||
|
|
@ -147,7 +147,7 @@ The result will display that Asset1 is now green:
|
|||
|
||||
The owner also has the ability to delete the asset. Run the following command to remove Asset1 from the ledger:
|
||||
```
|
||||
peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"DeleteAsset","Args":["Asset1"]}'
|
||||
peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n abac -c '{"function":"DeleteAsset","Args":["Asset1"]}'
|
||||
```
|
||||
|
||||
If you query the ledger once more, you will see that Asset1 no longer exists:
|
||||
|
|
@ -157,7 +157,7 @@ peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["A
|
|||
|
||||
While we are operating as User1, we can demonstrate attribute based access control by trying to create an asset using an identity without the `abac.creator=true` attribute. Run the following command to try to create Asset1 as User1:
|
||||
```
|
||||
peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset2","red","20","100"]}'
|
||||
peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset2","red","20","100"]}'
|
||||
```
|
||||
|
||||
The smart contract will return the following error:
|
||||
|
|
|
|||
|
|
@ -1,26 +1,5 @@
|
|||
module github.com/hyperledger/fabric-samples/asset-transfer-abac/chaincode-go
|
||||
|
||||
go 1.23.0
|
||||
go 1.15
|
||||
|
||||
require github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0
|
||||
|
||||
require (
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 // indirect
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
google.golang.org/protobuf v1.36.4 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
require github.com/hyperledger/fabric-contract-api-go v1.1.1
|
||||
|
|
|
|||
|
|
@ -1,81 +1,138 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DATA-DOG/go-txdb v0.1.3/go.mod h1:DhAhxMXZpUJVGnT+p9IbzJoRKvlArO2pkHjnGX7o0n0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c=
|
||||
github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk=
|
||||
github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4=
|
||||
github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs=
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc=
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
|
||||
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
|
||||
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
|
||||
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
|
||||
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
|
||||
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212 h1:1i4lnpV8BDgKOLi1hgElfBqdHXjXieSuj8629mwBZ8o=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc=
|
||||
github.com/hyperledger/fabric-contract-api-go v1.1.1 h1:gDhOC18gjgElNZ85kFWsbCQq95hyUP/21n++m0Sv6B0=
|
||||
github.com/hyperledger/fabric-contract-api-go v1.1.1/go.mod h1:+39cWxbh5py3NtXpRA63rAH7NzXyED+QJx1EZr0tJPo=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e h1:9PS5iezHk/j7XriSlNuSQILyCOfcZ9wZ3/PiucmSE8E=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ=
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/hyperledger/fabric-contract-api-go/v2/contractapi"
|
||||
"github.com/hyperledger/fabric-contract-api-go/contractapi"
|
||||
)
|
||||
|
||||
// SmartContract provides functions for managing an Asset
|
||||
|
|
@ -28,7 +28,7 @@ func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface,
|
|||
// Demonstrate the use of Attribute-Based Access Control (ABAC) by checking
|
||||
// to see if the caller has the "abac.creator" attribute with a value of true;
|
||||
// if not, return an error.
|
||||
|
||||
//
|
||||
err := ctx.GetClientIdentity().AssertAttributeValue("abac.creator", "true")
|
||||
if err != nil {
|
||||
return fmt.Errorf("submitting client not authorized to create asset, does not have abac.creator role")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package main
|
|||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hyperledger/fabric-contract-api-go/v2/contractapi"
|
||||
"github.com/hyperledger/fabric-contract-api-go/contractapi"
|
||||
abac "github.com/hyperledger/fabric-samples/asset-transfer-abac/chaincode-go/smart-contract"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
# Asset transfer basic sample
|
||||
|
||||
The asset transfer basic sample demonstrates:
|
||||
|
||||
- Connecting a client application to a Fabric blockchain network.
|
||||
- Submitting smart contract transactions to update ledger state.
|
||||
- Evaluating smart contract transactions to query ledger state.
|
||||
- Handling errors in transaction invocation.
|
||||
|
||||
## About the sample
|
||||
|
||||
This sample includes smart contract and application code in multiple languages. This sample shows create, read, update, transfer and delete of an asset.
|
||||
|
||||
For a more detailed walk-through of the application code and client API usage, refer to the [Running a Fabric Application tutorial](https://hyperledger-fabric.readthedocs.io/en/latest/write_first_app.html) in the main Hyperledger Fabric documentation.
|
||||
|
||||
### Application
|
||||
|
||||
Follow the execution flow in the client application code, and corresponding output on running the application. Pay attention to the sequence of:
|
||||
|
||||
- Transaction invocations (console output like "**--> Submit Transaction**" and "**--> Evaluate Transaction**").
|
||||
- Results returned by transactions (console output like "**\*\*\* Result**").
|
||||
|
||||
### Smart Contract
|
||||
|
||||
The smart contract (in folder `chaincode-xyz`) implements the following functions to support the application:
|
||||
|
||||
- CreateAsset
|
||||
- ReadAsset
|
||||
- UpdateAsset
|
||||
- DeleteAsset
|
||||
- TransferAsset
|
||||
|
||||
Note that the asset transfer implemented by the smart contract is a simplified scenario, without ownership validation, meant only to demonstrate how to invoke transactions.
|
||||
|
||||
## Running the sample
|
||||
|
||||
The Fabric test network is used to deploy and run this sample. Follow these steps in order:
|
||||
|
||||
1. Create the test network and a channel (from the `test-network` folder).
|
||||
|
||||
```
|
||||
./network.sh up createChannel -c mychannel -ca
|
||||
```
|
||||
|
||||
1. Deploy one of the smart contract implementations (from the `test-network` folder).
|
||||
|
||||
- To deploy the **TypeScript** chaincode implementation:
|
||||
|
||||
```shell
|
||||
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript
|
||||
```
|
||||
|
||||
- To deploy the **JavaScript** chaincode implementation:
|
||||
|
||||
```shell
|
||||
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
|
||||
```
|
||||
|
||||
- To deploy the **Go** chaincode implementation:
|
||||
|
||||
```shell
|
||||
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go/ -ccl go
|
||||
```
|
||||
|
||||
- To deploy the **Java** chaincode implementation:
|
||||
```shell
|
||||
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java/ -ccl java
|
||||
```
|
||||
|
||||
1. Run the application (from the `asset-transfer-basic` folder).
|
||||
|
||||
- To run the **TypeScript** sample application:
|
||||
|
||||
```shell
|
||||
cd application-gateway-typescript
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
- To run the **JavaScript** sample application:
|
||||
|
||||
```shell
|
||||
cd application-gateway-javascript
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
- To run the **Go** sample application:
|
||||
|
||||
```shell
|
||||
cd application-gateway-go
|
||||
go run .
|
||||
```
|
||||
|
||||
- To run the **Java** sample application:
|
||||
```shell
|
||||
cd application-gateway-java
|
||||
./gradlew run
|
||||
```
|
||||
|
||||
## Clean up
|
||||
|
||||
When you are finished, you can bring down the test network (from the `test-network` folder). The command will remove all the nodes of the test network, and delete any ledger data that you created.
|
||||
|
||||
```shell
|
||||
./network.sh down
|
||||
```
|
||||
|
|
@ -1,275 +0,0 @@
|
|||
/*
|
||||
Copyright 2021 IBM All Rights Reserved.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/hyperledger/fabric-gateway/pkg/client"
|
||||
"github.com/hyperledger/fabric-gateway/pkg/hash"
|
||||
"github.com/hyperledger/fabric-gateway/pkg/identity"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
mspID = "Org1MSP"
|
||||
cryptoPath = "../../test-network/organizations/peerOrganizations/org1.example.com"
|
||||
certPath = cryptoPath + "/users/User1@org1.example.com/msp/signcerts"
|
||||
keyPath = cryptoPath + "/users/User1@org1.example.com/msp/keystore"
|
||||
tlsCertPath = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt"
|
||||
peerEndpoint = "dns:///localhost:7051"
|
||||
gatewayPeer = "peer0.org1.example.com"
|
||||
)
|
||||
|
||||
var now = time.Now()
|
||||
var assetId = fmt.Sprintf("asset%d", now.Unix()*1e3+int64(now.Nanosecond())/1e6)
|
||||
|
||||
func main() {
|
||||
// The gRPC client connection should be shared by all Gateway connections to this endpoint
|
||||
clientConnection := newGrpcConnection()
|
||||
defer clientConnection.Close()
|
||||
|
||||
id := newIdentity()
|
||||
sign := newSign()
|
||||
|
||||
// Create a Gateway connection for a specific client identity
|
||||
gw, err := client.Connect(
|
||||
id,
|
||||
client.WithSign(sign),
|
||||
client.WithHash(hash.SHA256),
|
||||
client.WithClientConnection(clientConnection),
|
||||
// Default timeouts for different gRPC calls
|
||||
client.WithEvaluateTimeout(5*time.Second),
|
||||
client.WithEndorseTimeout(15*time.Second),
|
||||
client.WithSubmitTimeout(5*time.Second),
|
||||
client.WithCommitStatusTimeout(1*time.Minute),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer gw.Close()
|
||||
|
||||
// Override default values for chaincode and channel name as they may differ in testing contexts.
|
||||
chaincodeName := "basic"
|
||||
if ccname := os.Getenv("CHAINCODE_NAME"); ccname != "" {
|
||||
chaincodeName = ccname
|
||||
}
|
||||
|
||||
channelName := "mychannel"
|
||||
if cname := os.Getenv("CHANNEL_NAME"); cname != "" {
|
||||
channelName = cname
|
||||
}
|
||||
|
||||
network := gw.GetNetwork(channelName)
|
||||
contract := network.GetContract(chaincodeName)
|
||||
|
||||
initLedger(contract)
|
||||
getAllAssets(contract)
|
||||
createAsset(contract)
|
||||
readAssetByID(contract)
|
||||
transferAssetAsync(contract)
|
||||
exampleErrorHandling(contract)
|
||||
}
|
||||
|
||||
// newGrpcConnection creates a gRPC connection to the Gateway server.
|
||||
func newGrpcConnection() *grpc.ClientConn {
|
||||
certificatePEM, err := os.ReadFile(tlsCertPath)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to read TLS certifcate file: %w", err))
|
||||
}
|
||||
|
||||
certificate, err := identity.CertificateFromPEM(certificatePEM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AddCert(certificate)
|
||||
transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer)
|
||||
|
||||
connection, err := grpc.NewClient(peerEndpoint, grpc.WithTransportCredentials(transportCredentials))
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to create gRPC connection: %w", err))
|
||||
}
|
||||
|
||||
return connection
|
||||
}
|
||||
|
||||
// newIdentity creates a client identity for this Gateway connection using an X.509 certificate.
|
||||
func newIdentity() *identity.X509Identity {
|
||||
certificatePEM, err := readFirstFile(certPath)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to read certificate file: %w", err))
|
||||
}
|
||||
|
||||
certificate, err := identity.CertificateFromPEM(certificatePEM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
id, err := identity.NewX509Identity(mspID, certificate)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
// newSign creates a function that generates a digital signature from a message digest using a private key.
|
||||
func newSign() identity.Sign {
|
||||
privateKeyPEM, err := readFirstFile(keyPath)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to read private key file: %w", err))
|
||||
}
|
||||
|
||||
privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sign, err := identity.NewPrivateKeySign(privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return sign
|
||||
}
|
||||
|
||||
func readFirstFile(dirPath string) ([]byte, error) {
|
||||
dir, err := os.Open(dirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileNames, err := dir.Readdirnames(1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return os.ReadFile(path.Join(dirPath, fileNames[0]))
|
||||
}
|
||||
|
||||
// This type of transaction would typically only be run once by an application the first time it was started after its
|
||||
// initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function.
|
||||
func initLedger(contract *client.Contract) {
|
||||
fmt.Printf("\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger \n")
|
||||
|
||||
_, err := contract.SubmitTransaction("InitLedger")
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to submit transaction: %w", err))
|
||||
}
|
||||
|
||||
fmt.Printf("*** Transaction committed successfully\n")
|
||||
}
|
||||
|
||||
// Evaluate a transaction to query ledger state.
|
||||
func getAllAssets(contract *client.Contract) {
|
||||
fmt.Println("\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger")
|
||||
|
||||
evaluateResult, err := contract.EvaluateTransaction("GetAllAssets")
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to evaluate transaction: %w", err))
|
||||
}
|
||||
result := formatJSON(evaluateResult)
|
||||
|
||||
fmt.Printf("*** Result:%s\n", result)
|
||||
}
|
||||
|
||||
// Submit a transaction synchronously, blocking until it has been committed to the ledger.
|
||||
func createAsset(contract *client.Contract) {
|
||||
fmt.Printf("\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments \n")
|
||||
|
||||
_, err := contract.SubmitTransaction("CreateAsset", assetId, "yellow", "5", "Tom", "1300")
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to submit transaction: %w", err))
|
||||
}
|
||||
|
||||
fmt.Printf("*** Transaction committed successfully\n")
|
||||
}
|
||||
|
||||
// Evaluate a transaction by assetID to query ledger state.
|
||||
func readAssetByID(contract *client.Contract) {
|
||||
fmt.Printf("\n--> Evaluate Transaction: ReadAsset, function returns asset attributes\n")
|
||||
|
||||
evaluateResult, err := contract.EvaluateTransaction("ReadAsset", assetId)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to evaluate transaction: %w", err))
|
||||
}
|
||||
result := formatJSON(evaluateResult)
|
||||
|
||||
fmt.Printf("*** Result:%s\n", result)
|
||||
}
|
||||
|
||||
// Submit transaction asynchronously, blocking until the transaction has been sent to the orderer, and allowing
|
||||
// this thread to process the chaincode response (e.g. update a UI) without waiting for the commit notification
|
||||
func transferAssetAsync(contract *client.Contract) {
|
||||
fmt.Printf("\n--> Async Submit Transaction: TransferAsset, updates existing asset owner")
|
||||
|
||||
submitResult, commit, err := contract.SubmitAsync("TransferAsset", client.WithArguments(assetId, "Mark"))
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to submit transaction asynchronously: %w", err))
|
||||
}
|
||||
|
||||
fmt.Printf("\n*** Successfully submitted transaction to transfer ownership from %s to Mark. \n", string(submitResult))
|
||||
fmt.Println("*** Waiting for transaction commit.")
|
||||
|
||||
if commitStatus, err := commit.Status(); err != nil {
|
||||
panic(fmt.Errorf("failed to get commit status: %w", err))
|
||||
} else if !commitStatus.Successful {
|
||||
panic(fmt.Errorf("transaction %s failed to commit with status: %d", commitStatus.TransactionID, int32(commitStatus.Code)))
|
||||
}
|
||||
|
||||
fmt.Printf("*** Transaction committed successfully\n")
|
||||
}
|
||||
|
||||
// Submit transaction, passing in the wrong number of arguments ,expected to throw an error containing details of any error responses from the smart contract.
|
||||
func exampleErrorHandling(contract *client.Contract) {
|
||||
fmt.Println("\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error")
|
||||
|
||||
_, err := contract.SubmitTransaction("UpdateAsset", "asset70", "blue", "5", "Tomoko", "300")
|
||||
if err == nil {
|
||||
panic("******** FAILED to return an error")
|
||||
}
|
||||
|
||||
fmt.Println("*** Successfully caught the error:")
|
||||
|
||||
var commitStatusErr *client.CommitStatusError
|
||||
var transactionErr *client.TransactionError
|
||||
|
||||
if errors.As(err, &commitStatusErr) {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
fmt.Printf("Timeout waiting for transaction %s commit status: %s\n", commitStatusErr.TransactionID, commitStatusErr)
|
||||
} else {
|
||||
fmt.Printf("Error obtaining commit status for transaction %s with gRPC status %v: %s\n", commitStatusErr.TransactionID, status.Code(commitStatusErr), commitStatusErr)
|
||||
}
|
||||
} else if errors.As(err, &transactionErr) {
|
||||
// The error could be an EndorseError, SubmitError or CommitError.
|
||||
fmt.Println(err)
|
||||
fmt.Printf("TransactionID: %s\n", transactionErr.TransactionID)
|
||||
} else {
|
||||
panic(fmt.Errorf("unexpected error type %T: %w", err, err))
|
||||
}
|
||||
}
|
||||
|
||||
// Format JSON data
|
||||
func formatJSON(data []byte) string {
|
||||
var prettyJSON bytes.Buffer
|
||||
if err := json.Indent(&prettyJSON, data, "", " "); err != nil {
|
||||
panic(fmt.Errorf("failed to parse JSON: %w", err))
|
||||
}
|
||||
return prettyJSON.String()
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
module assetTransfer
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/hyperledger/fabric-gateway v1.10.0
|
||||
google.golang.org/grpc v1.76.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.7 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
)
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hyperledger/fabric-gateway v1.10.0 h1:x5z/pofdVYIqgMo9QWejubfAZYCSt94WdUPj4Wipdeg=
|
||||
github.com/hyperledger/fabric-gateway v1.10.0/go.mod h1:fSFS1vQkPZq6inNvzsnI/7PCaKSU+UZOZ6uAuau0Yq0=
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.7 h1:sQ5qv8vQQfwewa1JlCiSCC8dLElmaU2/frLolpgibEY=
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.7/go.mod h1:bJnwzfv03oZQeCc863pdGTDgf5nmCy6Za3RAE7d2XsQ=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* This generated file contains a sample Java project to get you started.
|
||||
* For more details take a look at the Java Quickstart chapter in the Gradle
|
||||
* User Manual available at https://docs.gradle.org/6.5/userguide/tutorial_java_projects.html
|
||||
*/
|
||||
plugins {
|
||||
// Apply the application plugin to add support for building a CLI application.
|
||||
id 'application'
|
||||
}
|
||||
|
||||
ext {
|
||||
javaMainClass = "application.java.App"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.hyperledger.fabric:fabric-gateway:1.10.0'
|
||||
implementation platform('com.google.protobuf:protobuf-bom:4.33.0')
|
||||
implementation platform('io.grpc:grpc-bom:1.76.0')
|
||||
compileOnly 'io.grpc:grpc-api'
|
||||
runtimeOnly 'io.grpc:grpc-netty-shaded'
|
||||
implementation 'com.google.code.gson:gson:2.13.2'
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.release = 11
|
||||
}
|
||||
|
||||
application {
|
||||
// Define the main class for the application.
|
||||
mainClass = 'App'
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,252 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.hyperledger.fabric.example</groupId>
|
||||
<artifactId>asset-transfer-basic</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-bom</artifactId>
|
||||
<version>4.33.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-bom</artifactId>
|
||||
<version>1.76.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.hyperledger.fabric</groupId>
|
||||
<artifactId>fabric-gateway</artifactId>
|
||||
<version>1.10.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-netty-shaded</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be
|
||||
moved to parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see
|
||||
https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see
|
||||
https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.4.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see
|
||||
https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.grpc.Grpc;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.TlsChannelCredentials;
|
||||
import org.hyperledger.fabric.client.CommitException;
|
||||
import org.hyperledger.fabric.client.CommitStatusException;
|
||||
import org.hyperledger.fabric.client.Contract;
|
||||
import org.hyperledger.fabric.client.EndorseException;
|
||||
import org.hyperledger.fabric.client.Gateway;
|
||||
import org.hyperledger.fabric.client.GatewayException;
|
||||
import org.hyperledger.fabric.client.Hash;
|
||||
import org.hyperledger.fabric.client.SubmitException;
|
||||
import org.hyperledger.fabric.client.identity.Identities;
|
||||
import org.hyperledger.fabric.client.identity.Identity;
|
||||
import org.hyperledger.fabric.client.identity.Signer;
|
||||
import org.hyperledger.fabric.client.identity.Signers;
|
||||
import org.hyperledger.fabric.client.identity.X509Identity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class App {
|
||||
private static final String MSP_ID = System.getenv().getOrDefault("MSP_ID", "Org1MSP");
|
||||
private static final String CHANNEL_NAME = System.getenv().getOrDefault("CHANNEL_NAME", "mychannel");
|
||||
private static final String CHAINCODE_NAME = System.getenv().getOrDefault("CHAINCODE_NAME", "basic");
|
||||
|
||||
// Path to crypto materials.
|
||||
private static final Path CRYPTO_PATH = Paths.get("../../test-network/organizations/peerOrganizations/org1.example.com");
|
||||
// Path to user certificate.
|
||||
private static final Path CERT_DIR_PATH = CRYPTO_PATH.resolve(Paths.get("users/User1@org1.example.com/msp/signcerts"));
|
||||
// Path to user private key directory.
|
||||
private static final Path KEY_DIR_PATH = CRYPTO_PATH.resolve(Paths.get("users/User1@org1.example.com/msp/keystore"));
|
||||
// Path to peer tls certificate.
|
||||
private static final Path TLS_CERT_PATH = CRYPTO_PATH.resolve(Paths.get("peers/peer0.org1.example.com/tls/ca.crt"));
|
||||
|
||||
// Gateway peer end point.
|
||||
private static final String PEER_ENDPOINT = "localhost:7051";
|
||||
private static final String OVERRIDE_AUTH = "peer0.org1.example.com";
|
||||
|
||||
private final Contract contract;
|
||||
private final String assetId = "asset" + Instant.now().toEpochMilli();
|
||||
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
// The gRPC client connection should be shared by all Gateway connections to
|
||||
// this endpoint.
|
||||
var channel = newGrpcConnection();
|
||||
|
||||
var builder = Gateway.newInstance()
|
||||
.identity(newIdentity())
|
||||
.signer(newSigner())
|
||||
.hash(Hash.SHA256)
|
||||
.connection(channel)
|
||||
// Default timeouts for different gRPC calls
|
||||
.evaluateOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS))
|
||||
.endorseOptions(options -> options.withDeadlineAfter(15, TimeUnit.SECONDS))
|
||||
.submitOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS))
|
||||
.commitStatusOptions(options -> options.withDeadlineAfter(1, TimeUnit.MINUTES));
|
||||
|
||||
try (var gateway = builder.connect()) {
|
||||
new App(gateway).run();
|
||||
} finally {
|
||||
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private static ManagedChannel newGrpcConnection() throws IOException {
|
||||
var credentials = TlsChannelCredentials.newBuilder()
|
||||
.trustManager(TLS_CERT_PATH.toFile())
|
||||
.build();
|
||||
return Grpc.newChannelBuilder(PEER_ENDPOINT, credentials)
|
||||
.overrideAuthority(OVERRIDE_AUTH)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Identity newIdentity() throws IOException, CertificateException {
|
||||
try (var certReader = Files.newBufferedReader(getFirstFilePath(CERT_DIR_PATH))) {
|
||||
var certificate = Identities.readX509Certificate(certReader);
|
||||
return new X509Identity(MSP_ID, certificate);
|
||||
}
|
||||
}
|
||||
|
||||
private static Signer newSigner() throws IOException, InvalidKeyException {
|
||||
try (var keyReader = Files.newBufferedReader(getFirstFilePath(KEY_DIR_PATH))) {
|
||||
var privateKey = Identities.readPrivateKey(keyReader);
|
||||
return Signers.newPrivateKeySigner(privateKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getFirstFilePath(Path dirPath) throws IOException {
|
||||
try (var keyFiles = Files.list(dirPath)) {
|
||||
return keyFiles.findFirst().orElseThrow();
|
||||
}
|
||||
}
|
||||
|
||||
public App(final Gateway gateway) {
|
||||
// Get a network instance representing the channel where the smart contract is
|
||||
// deployed.
|
||||
var network = gateway.getNetwork(CHANNEL_NAME);
|
||||
|
||||
// Get the smart contract from the network.
|
||||
contract = network.getContract(CHAINCODE_NAME);
|
||||
}
|
||||
|
||||
public void run() throws GatewayException, CommitException {
|
||||
// Initialize a set of asset data on the ledger using the chaincode 'InitLedger' function.
|
||||
initLedger();
|
||||
|
||||
// Return all the current assets on the ledger.
|
||||
getAllAssets();
|
||||
|
||||
// Create a new asset on the ledger.
|
||||
createAsset();
|
||||
|
||||
// Update an existing asset asynchronously.
|
||||
transferAssetAsync();
|
||||
|
||||
// Get the asset details by assetID.
|
||||
readAssetById();
|
||||
|
||||
// Update an asset which does not exist.
|
||||
updateNonExistentAsset();
|
||||
}
|
||||
|
||||
/**
|
||||
* This type of transaction would typically only be run once by an application
|
||||
* the first time it was started after its initial deployment. A new version of
|
||||
* the chaincode deployed later would likely not need to run an "init" function.
|
||||
*/
|
||||
private void initLedger() throws EndorseException, SubmitException, CommitStatusException, CommitException {
|
||||
System.out.println("\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger");
|
||||
|
||||
contract.submitTransaction("InitLedger");
|
||||
|
||||
System.out.println("*** Transaction committed successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a transaction to query ledger state.
|
||||
*/
|
||||
private void getAllAssets() throws GatewayException {
|
||||
System.out.println("\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger");
|
||||
|
||||
var result = contract.evaluateTransaction("GetAllAssets");
|
||||
|
||||
System.out.println("*** Result: " + prettyJson(result));
|
||||
}
|
||||
|
||||
private String prettyJson(final byte[] json) {
|
||||
return prettyJson(new String(json, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private String prettyJson(final String json) {
|
||||
var parsedJson = JsonParser.parseString(json);
|
||||
return gson.toJson(parsedJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a transaction synchronously, blocking until it has been committed to
|
||||
* the ledger.
|
||||
*/
|
||||
private void createAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException {
|
||||
System.out.println("\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments");
|
||||
|
||||
contract.submitTransaction("CreateAsset", assetId, "yellow", "5", "Tom", "1300");
|
||||
|
||||
System.out.println("*** Transaction committed successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit transaction asynchronously, allowing the application to process the
|
||||
* smart contract response (e.g. update a UI) while waiting for the commit
|
||||
* notification.
|
||||
*/
|
||||
private void transferAssetAsync() throws EndorseException, SubmitException, CommitStatusException {
|
||||
System.out.println("\n--> Async Submit Transaction: TransferAsset, updates existing asset owner");
|
||||
|
||||
var commit = contract.newProposal("TransferAsset")
|
||||
.addArguments(assetId, "Saptha")
|
||||
.build()
|
||||
.endorse()
|
||||
.submitAsync();
|
||||
|
||||
var result = commit.getResult();
|
||||
var oldOwner = new String(result, StandardCharsets.UTF_8);
|
||||
|
||||
System.out.println("*** Successfully submitted transaction to transfer ownership from " + oldOwner + " to Saptha");
|
||||
System.out.println("*** Waiting for transaction commit");
|
||||
|
||||
var status = commit.getStatus();
|
||||
if (!status.isSuccessful()) {
|
||||
throw new RuntimeException("Transaction " + status.getTransactionId() +
|
||||
" failed to commit with status code " + status.getCode());
|
||||
}
|
||||
|
||||
System.out.println("*** Transaction committed successfully");
|
||||
}
|
||||
|
||||
private void readAssetById() throws GatewayException {
|
||||
System.out.println("\n--> Evaluate Transaction: ReadAsset, function returns asset attributes");
|
||||
|
||||
var evaluateResult = contract.evaluateTransaction("ReadAsset", assetId);
|
||||
|
||||
System.out.println("*** Result:" + prettyJson(evaluateResult));
|
||||
}
|
||||
|
||||
/**
|
||||
* submitTransaction() will throw an error containing details of any error
|
||||
* responses from the smart contract.
|
||||
*/
|
||||
private void updateNonExistentAsset() {
|
||||
try {
|
||||
System.out.println("\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error");
|
||||
|
||||
contract.submitTransaction("UpdateAsset", "asset70", "blue", "5", "Tomoko", "300");
|
||||
|
||||
System.out.println("******** FAILED to return an error");
|
||||
} catch (EndorseException | SubmitException | CommitStatusException e) {
|
||||
System.out.println("*** Successfully caught the error:");
|
||||
e.printStackTrace(System.out);
|
||||
System.out.println("Transaction ID: " + e.getTransactionId());
|
||||
} catch (CommitException e) {
|
||||
System.out.println("*** Successfully caught the error:");
|
||||
e.printStackTrace(System.out);
|
||||
System.out.println("Transaction ID: " + e.getTransactionId());
|
||||
System.out.println("Status code: " + e.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
engine-strict=true
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
{
|
||||
languageOptions: {
|
||||
ecmaVersion: 2023,
|
||||
sourceType: 'commonjs',
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"name": "asset-transfer-basic",
|
||||
"version": "1.0.0",
|
||||
"description": "Asset Transfer Basic Application implemented in JavaScript using fabric-gateway",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint src",
|
||||
"pretest": "npm run lint",
|
||||
"start": "node src/app.js"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"author": "Hyperledger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.14.0",
|
||||
"@hyperledger/fabric-gateway": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.5.0",
|
||||
"eslint": "^9.5.0",
|
||||
"globals": "^15.6.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,301 +0,0 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
const grpc = require('@grpc/grpc-js');
|
||||
const { connect, hash, signers } = require('@hyperledger/fabric-gateway');
|
||||
const crypto = require('node:crypto');
|
||||
const fs = require('node:fs/promises');
|
||||
const path = require('node:path');
|
||||
const { TextDecoder } = require('node:util');
|
||||
|
||||
const channelName = envOrDefault('CHANNEL_NAME', 'mychannel');
|
||||
const chaincodeName = envOrDefault('CHAINCODE_NAME', 'basic');
|
||||
const mspId = envOrDefault('MSP_ID', 'Org1MSP');
|
||||
|
||||
// Path to crypto materials.
|
||||
const cryptoPath = envOrDefault(
|
||||
'CRYPTO_PATH',
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'test-network',
|
||||
'organizations',
|
||||
'peerOrganizations',
|
||||
'org1.example.com'
|
||||
)
|
||||
);
|
||||
|
||||
// Path to user private key directory.
|
||||
const keyDirectoryPath = envOrDefault(
|
||||
'KEY_DIRECTORY_PATH',
|
||||
path.resolve(
|
||||
cryptoPath,
|
||||
'users',
|
||||
'User1@org1.example.com',
|
||||
'msp',
|
||||
'keystore'
|
||||
)
|
||||
);
|
||||
|
||||
// Path to user certificate directory.
|
||||
const certDirectoryPath = envOrDefault(
|
||||
'CERT_DIRECTORY_PATH',
|
||||
path.resolve(
|
||||
cryptoPath,
|
||||
'users',
|
||||
'User1@org1.example.com',
|
||||
'msp',
|
||||
'signcerts'
|
||||
)
|
||||
);
|
||||
|
||||
// Path to peer tls certificate.
|
||||
const tlsCertPath = envOrDefault(
|
||||
'TLS_CERT_PATH',
|
||||
path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt')
|
||||
);
|
||||
|
||||
// Gateway peer endpoint.
|
||||
const peerEndpoint = envOrDefault('PEER_ENDPOINT', 'localhost:7051');
|
||||
|
||||
// Gateway peer SSL host name override.
|
||||
const peerHostAlias = envOrDefault('PEER_HOST_ALIAS', 'peer0.org1.example.com');
|
||||
|
||||
const utf8Decoder = new TextDecoder();
|
||||
const assetId = `asset${String(Date.now())}`;
|
||||
|
||||
async function main() {
|
||||
displayInputParameters();
|
||||
|
||||
// The gRPC client connection should be shared by all Gateway connections to this endpoint.
|
||||
const client = await newGrpcConnection();
|
||||
|
||||
const gateway = connect({
|
||||
client,
|
||||
identity: await newIdentity(),
|
||||
signer: await newSigner(),
|
||||
hash: hash.sha256,
|
||||
// Default timeouts for different gRPC calls
|
||||
evaluateOptions: () => {
|
||||
return { deadline: Date.now() + 5000 }; // 5 seconds
|
||||
},
|
||||
endorseOptions: () => {
|
||||
return { deadline: Date.now() + 15000 }; // 15 seconds
|
||||
},
|
||||
submitOptions: () => {
|
||||
return { deadline: Date.now() + 5000 }; // 5 seconds
|
||||
},
|
||||
commitStatusOptions: () => {
|
||||
return { deadline: Date.now() + 60000 }; // 1 minute
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
// Get a network instance representing the channel where the smart contract is deployed.
|
||||
const network = gateway.getNetwork(channelName);
|
||||
|
||||
// Get the smart contract from the network.
|
||||
const contract = network.getContract(chaincodeName);
|
||||
|
||||
// Initialize a set of asset data on the ledger using the chaincode 'InitLedger' function.
|
||||
await initLedger(contract);
|
||||
|
||||
// Return all the current assets on the ledger.
|
||||
await getAllAssets(contract);
|
||||
|
||||
// Create a new asset on the ledger.
|
||||
await createAsset(contract);
|
||||
|
||||
// Update an existing asset asynchronously.
|
||||
await transferAssetAsync(contract);
|
||||
|
||||
// Get the asset details by assetID.
|
||||
await readAssetByID(contract);
|
||||
|
||||
// Update an asset which does not exist.
|
||||
await updateNonExistentAsset(contract);
|
||||
} finally {
|
||||
gateway.close();
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('******** FAILED to run the application:', error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
|
||||
async function newGrpcConnection() {
|
||||
const tlsRootCert = await fs.readFile(tlsCertPath);
|
||||
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
|
||||
return new grpc.Client(peerEndpoint, tlsCredentials, {
|
||||
'grpc.ssl_target_name_override': peerHostAlias,
|
||||
});
|
||||
}
|
||||
|
||||
async function newIdentity() {
|
||||
const certPath = await getFirstDirFileName(certDirectoryPath);
|
||||
const credentials = await fs.readFile(certPath);
|
||||
return { mspId, credentials };
|
||||
}
|
||||
|
||||
async function getFirstDirFileName(dirPath) {
|
||||
const files = await fs.readdir(dirPath);
|
||||
const file = files[0];
|
||||
if (!file) {
|
||||
throw new Error(`No files in directory: ${dirPath}`);
|
||||
}
|
||||
return path.join(dirPath, file);
|
||||
}
|
||||
|
||||
async function newSigner() {
|
||||
const keyPath = await getFirstDirFileName(keyDirectoryPath);
|
||||
const privateKeyPem = await fs.readFile(keyPath);
|
||||
const privateKey = crypto.createPrivateKey(privateKeyPem);
|
||||
return signers.newPrivateKeySigner(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* This type of transaction would typically only be run once by an application the first time it was started after its
|
||||
* initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function.
|
||||
*/
|
||||
async function initLedger(contract) {
|
||||
console.log(
|
||||
'\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger'
|
||||
);
|
||||
|
||||
await contract.submitTransaction('InitLedger');
|
||||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a transaction to query ledger state.
|
||||
*/
|
||||
async function getAllAssets(contract) {
|
||||
console.log(
|
||||
'\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger'
|
||||
);
|
||||
|
||||
const resultBytes = await contract.evaluateTransaction('GetAllAssets');
|
||||
|
||||
const resultJson = utf8Decoder.decode(resultBytes);
|
||||
const result = JSON.parse(resultJson);
|
||||
console.log('*** Result:', result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a transaction synchronously, blocking until it has been committed to the ledger.
|
||||
*/
|
||||
async function createAsset(contract) {
|
||||
console.log(
|
||||
'\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments'
|
||||
);
|
||||
|
||||
await contract.submitTransaction(
|
||||
'CreateAsset',
|
||||
assetId,
|
||||
'yellow',
|
||||
'5',
|
||||
'Tom',
|
||||
'1300'
|
||||
);
|
||||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit transaction asynchronously, allowing the application to process the smart contract response (e.g. update a UI)
|
||||
* while waiting for the commit notification.
|
||||
*/
|
||||
async function transferAssetAsync(contract) {
|
||||
console.log(
|
||||
'\n--> Async Submit Transaction: TransferAsset, updates existing asset owner'
|
||||
);
|
||||
|
||||
const commit = await contract.submitAsync('TransferAsset', {
|
||||
arguments: [assetId, 'Saptha'],
|
||||
});
|
||||
const oldOwner = utf8Decoder.decode(commit.getResult());
|
||||
|
||||
console.log(
|
||||
`*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha`
|
||||
);
|
||||
console.log('*** Waiting for transaction commit');
|
||||
|
||||
const status = await commit.getStatus();
|
||||
if (!status.successful) {
|
||||
throw new Error(
|
||||
`Transaction ${
|
||||
status.transactionId
|
||||
} failed to commit with status code ${String(status.code)}`
|
||||
);
|
||||
}
|
||||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
async function readAssetByID(contract) {
|
||||
console.log(
|
||||
'\n--> Evaluate Transaction: ReadAsset, function returns asset attributes'
|
||||
);
|
||||
|
||||
const resultBytes = await contract.evaluateTransaction(
|
||||
'ReadAsset',
|
||||
assetId
|
||||
);
|
||||
|
||||
const resultJson = utf8Decoder.decode(resultBytes);
|
||||
const result = JSON.parse(resultJson);
|
||||
console.log('*** Result:', result);
|
||||
}
|
||||
|
||||
/**
|
||||
* submitTransaction() will throw an error containing details of any error responses from the smart contract.
|
||||
*/
|
||||
async function updateNonExistentAsset(contract) {
|
||||
console.log(
|
||||
'\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error'
|
||||
);
|
||||
|
||||
try {
|
||||
await contract.submitTransaction(
|
||||
'UpdateAsset',
|
||||
'asset70',
|
||||
'blue',
|
||||
'5',
|
||||
'Tomoko',
|
||||
'300'
|
||||
);
|
||||
console.log('******** FAILED to return an error');
|
||||
} catch (error) {
|
||||
console.log('*** Successfully caught the error: \n', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* envOrDefault() will return the value of an environment variable, or a default value if the variable is undefined.
|
||||
*/
|
||||
function envOrDefault(key, defaultValue) {
|
||||
return process.env[key] || defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* displayInputParameters() will print the global scope parameters used by the main driver routine.
|
||||
*/
|
||||
function displayInputParameters() {
|
||||
console.log(`channelName: ${channelName}`);
|
||||
console.log(`chaincodeName: ${chaincodeName}`);
|
||||
console.log(`mspId: ${mspId}`);
|
||||
console.log(`cryptoPath: ${cryptoPath}`);
|
||||
console.log(`keyDirectoryPath: ${keyDirectoryPath}`);
|
||||
console.log(`certDirectoryPath: ${certDirectoryPath}`);
|
||||
console.log(`tlsCertPath: ${tlsCertPath}`);
|
||||
console.log(`peerEndpoint: ${peerEndpoint}`);
|
||||
console.log(`peerHostAlias: ${peerHostAlias}`);
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
engine-strict=true
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import js from '@eslint/js';
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
|
||||
languageOptions: {
|
||||
ecmaVersion: 2023,
|
||||
sourceType: 'module',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"name": "asset-transfer-basic",
|
||||
"version": "1.0.0",
|
||||
"description": "Asset Transfer Basic Application implemented in typeScript using fabric-gateway",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"build:watch": "tsc -w",
|
||||
"lint": "eslint src",
|
||||
"prepare": "npm run build",
|
||||
"pretest": "npm run lint",
|
||||
"start": "node dist/app.js"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"author": "Hyperledger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.14.0",
|
||||
"@hyperledger/fabric-gateway": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tsconfig/node20": "^20.1.9",
|
||||
"@types/node": "^20.19.33",
|
||||
"eslint": "^10.0.2",
|
||||
"typescript": "~5.8",
|
||||
"typescript-eslint": "^8.56.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as grpc from '@grpc/grpc-js';
|
||||
import { connect, Contract, hash, Identity, Signer, signers } from '@hyperledger/fabric-gateway';
|
||||
import * as crypto from 'crypto';
|
||||
import { promises as fs } from 'fs';
|
||||
import * as path from 'path';
|
||||
import { TextDecoder } from 'util';
|
||||
|
||||
const channelName = envOrDefault('CHANNEL_NAME', 'mychannel');
|
||||
const chaincodeName = envOrDefault('CHAINCODE_NAME', 'basic');
|
||||
const mspId = envOrDefault('MSP_ID', 'Org1MSP');
|
||||
|
||||
// Path to crypto materials.
|
||||
const cryptoPath = envOrDefault('CRYPTO_PATH', path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com'));
|
||||
|
||||
// Path to user private key directory.
|
||||
const keyDirectoryPath = envOrDefault('KEY_DIRECTORY_PATH', path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'keystore'));
|
||||
|
||||
// Path to user certificate directory.
|
||||
const certDirectoryPath = envOrDefault('CERT_DIRECTORY_PATH', path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'signcerts'));
|
||||
|
||||
// Path to peer tls certificate.
|
||||
const tlsCertPath = envOrDefault('TLS_CERT_PATH', path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt'));
|
||||
|
||||
// Gateway peer endpoint.
|
||||
const peerEndpoint = envOrDefault('PEER_ENDPOINT', 'localhost:7051');
|
||||
|
||||
// Gateway peer SSL host name override.
|
||||
const peerHostAlias = envOrDefault('PEER_HOST_ALIAS', 'peer0.org1.example.com');
|
||||
|
||||
const utf8Decoder = new TextDecoder();
|
||||
const assetId = `asset${String(Date.now())}`;
|
||||
|
||||
async function main(): Promise<void> {
|
||||
displayInputParameters();
|
||||
|
||||
// The gRPC client connection should be shared by all Gateway connections to this endpoint.
|
||||
const client = await newGrpcConnection();
|
||||
|
||||
const gateway = connect({
|
||||
client,
|
||||
identity: await newIdentity(),
|
||||
signer: await newSigner(),
|
||||
hash: hash.sha256,
|
||||
// Default timeouts for different gRPC calls
|
||||
evaluateOptions: () => {
|
||||
return { deadline: Date.now() + 5000 }; // 5 seconds
|
||||
},
|
||||
endorseOptions: () => {
|
||||
return { deadline: Date.now() + 15000 }; // 15 seconds
|
||||
},
|
||||
submitOptions: () => {
|
||||
return { deadline: Date.now() + 5000 }; // 5 seconds
|
||||
},
|
||||
commitStatusOptions: () => {
|
||||
return { deadline: Date.now() + 60000 }; // 1 minute
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
// Get a network instance representing the channel where the smart contract is deployed.
|
||||
const network = gateway.getNetwork(channelName);
|
||||
|
||||
// Get the smart contract from the network.
|
||||
const contract = network.getContract(chaincodeName);
|
||||
|
||||
// Initialize a set of asset data on the ledger using the chaincode 'InitLedger' function.
|
||||
await initLedger(contract);
|
||||
|
||||
// Return all the current assets on the ledger.
|
||||
await getAllAssets(contract);
|
||||
|
||||
// Create a new asset on the ledger.
|
||||
await createAsset(contract);
|
||||
|
||||
// Update an existing asset asynchronously.
|
||||
await transferAssetAsync(contract);
|
||||
|
||||
// Get the asset details by assetID.
|
||||
await readAssetByID(contract);
|
||||
|
||||
// Update an asset which does not exist.
|
||||
await updateNonExistentAsset(contract)
|
||||
} finally {
|
||||
gateway.close();
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error: unknown) => {
|
||||
console.error('******** FAILED to run the application:', error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
|
||||
async function newGrpcConnection(): Promise<grpc.Client> {
|
||||
const tlsRootCert = await fs.readFile(tlsCertPath);
|
||||
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
|
||||
return new grpc.Client(peerEndpoint, tlsCredentials, {
|
||||
'grpc.ssl_target_name_override': peerHostAlias,
|
||||
});
|
||||
}
|
||||
|
||||
async function newIdentity(): Promise<Identity> {
|
||||
const certPath = await getFirstDirFileName(certDirectoryPath);
|
||||
const credentials = await fs.readFile(certPath);
|
||||
return { mspId, credentials };
|
||||
}
|
||||
|
||||
async function getFirstDirFileName(dirPath: string): Promise<string> {
|
||||
const files = await fs.readdir(dirPath);
|
||||
const file = files[0];
|
||||
if (!file) {
|
||||
throw new Error(`No files in directory: ${dirPath}`);
|
||||
}
|
||||
return path.join(dirPath, file);
|
||||
}
|
||||
|
||||
async function newSigner(): Promise<Signer> {
|
||||
const keyPath = await getFirstDirFileName(keyDirectoryPath);
|
||||
const privateKeyPem = await fs.readFile(keyPath);
|
||||
const privateKey = crypto.createPrivateKey(privateKeyPem);
|
||||
return signers.newPrivateKeySigner(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* This type of transaction would typically only be run once by an application the first time it was started after its
|
||||
* initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function.
|
||||
*/
|
||||
async function initLedger(contract: Contract): Promise<void> {
|
||||
console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger');
|
||||
|
||||
await contract.submitTransaction('InitLedger');
|
||||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a transaction to query ledger state.
|
||||
*/
|
||||
async function getAllAssets(contract: Contract): Promise<void> {
|
||||
console.log('\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger');
|
||||
|
||||
const resultBytes = await contract.evaluateTransaction('GetAllAssets');
|
||||
|
||||
const resultJson = utf8Decoder.decode(resultBytes);
|
||||
const result: unknown = JSON.parse(resultJson);
|
||||
console.log('*** Result:', result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a transaction synchronously, blocking until it has been committed to the ledger.
|
||||
*/
|
||||
async function createAsset(contract: Contract): Promise<void> {
|
||||
console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments');
|
||||
|
||||
await contract.submitTransaction(
|
||||
'CreateAsset',
|
||||
assetId,
|
||||
'yellow',
|
||||
'5',
|
||||
'Tom',
|
||||
'1300',
|
||||
);
|
||||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit transaction asynchronously, allowing the application to process the smart contract response (e.g. update a UI)
|
||||
* while waiting for the commit notification.
|
||||
*/
|
||||
async function transferAssetAsync(contract: Contract): Promise<void> {
|
||||
console.log('\n--> Async Submit Transaction: TransferAsset, updates existing asset owner');
|
||||
|
||||
const commit = await contract.submitAsync('TransferAsset', {
|
||||
arguments: [assetId, 'Saptha'],
|
||||
});
|
||||
const oldOwner = utf8Decoder.decode(commit.getResult());
|
||||
|
||||
console.log(`*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha`);
|
||||
console.log('*** Waiting for transaction commit');
|
||||
|
||||
const status = await commit.getStatus();
|
||||
if (!status.successful) {
|
||||
throw new Error(`Transaction ${status.transactionId} failed to commit with status code ${String(status.code)}`);
|
||||
}
|
||||
|
||||
console.log('*** Transaction committed successfully');
|
||||
}
|
||||
|
||||
async function readAssetByID(contract: Contract): Promise<void> {
|
||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns asset attributes');
|
||||
|
||||
const resultBytes = await contract.evaluateTransaction('ReadAsset', assetId);
|
||||
|
||||
const resultJson = utf8Decoder.decode(resultBytes);
|
||||
const result: unknown = JSON.parse(resultJson);
|
||||
console.log('*** Result:', result);
|
||||
}
|
||||
|
||||
/**
|
||||
* submitTransaction() will throw an error containing details of any error responses from the smart contract.
|
||||
*/
|
||||
async function updateNonExistentAsset(contract: Contract): Promise<void>{
|
||||
console.log('\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error');
|
||||
|
||||
try {
|
||||
await contract.submitTransaction(
|
||||
'UpdateAsset',
|
||||
'asset70',
|
||||
'blue',
|
||||
'5',
|
||||
'Tomoko',
|
||||
'300',
|
||||
);
|
||||
console.log('******** FAILED to return an error');
|
||||
} catch (error) {
|
||||
console.log('*** Successfully caught the error: \n', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* envOrDefault() will return the value of an environment variable, or a default value if the variable is undefined.
|
||||
*/
|
||||
function envOrDefault(key: string, defaultValue: string): string {
|
||||
return process.env[key] || defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* displayInputParameters() will print the global scope parameters used by the main driver routine.
|
||||
*/
|
||||
function displayInputParameters(): void {
|
||||
console.log(`channelName: ${channelName}`);
|
||||
console.log(`chaincodeName: ${chaincodeName}`);
|
||||
console.log(`mspId: ${mspId}`);
|
||||
console.log(`cryptoPath: ${cryptoPath}`);
|
||||
console.log(`keyDirectoryPath: ${keyDirectoryPath}`);
|
||||
console.log(`certDirectoryPath: ${certDirectoryPath}`);
|
||||
console.log(`tlsCertPath: ${tlsCertPath}`);
|
||||
console.log(`peerEndpoint: ${peerEndpoint}`);
|
||||
console.log(`peerHostAlias: ${peerHostAlias}`);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["src/"],
|
||||
"exclude": ["**/*.spec.*"]
|
||||
}
|
||||
4
asset-transfer-basic/application-go/.gitignore
vendored
Executable file
4
asset-transfer-basic/application-go/.gitignore
vendored
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
wallet
|
||||
!wallet/.gitkeep
|
||||
|
||||
keystore
|
||||
155
asset-transfer-basic/application-go/assetTransfer.go
Normal file
155
asset-transfer-basic/application-go/assetTransfer.go
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
Copyright 2020 IBM All Rights Reserved.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
|
||||
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("============ application-golang starts ============")
|
||||
|
||||
err := os.Setenv("DISCOVERY_AS_LOCALHOST", "true")
|
||||
if err != nil {
|
||||
log.Fatalf("Error setting DISCOVERY_AS_LOCALHOST environemnt variable: %v", err)
|
||||
}
|
||||
|
||||
wallet, err := gateway.NewFileSystemWallet("wallet")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create wallet: %v", err)
|
||||
}
|
||||
|
||||
if !wallet.Exists("appUser") {
|
||||
err = populateWallet(wallet)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to populate wallet contents: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
ccpPath := filepath.Join(
|
||||
"..",
|
||||
"..",
|
||||
"test-network",
|
||||
"organizations",
|
||||
"peerOrganizations",
|
||||
"org1.example.com",
|
||||
"connection-org1.yaml",
|
||||
)
|
||||
|
||||
gw, err := gateway.Connect(
|
||||
gateway.WithConfig(config.FromFile(filepath.Clean(ccpPath))),
|
||||
gateway.WithIdentity(wallet, "appUser"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to gateway: %v", err)
|
||||
}
|
||||
defer gw.Close()
|
||||
|
||||
network, err := gw.GetNetwork("mychannel")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to get network: %v", err)
|
||||
}
|
||||
|
||||
contract := network.GetContract("basic")
|
||||
|
||||
log.Println("--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger")
|
||||
result, err := contract.SubmitTransaction("InitLedger")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to Submit transaction: %v", err)
|
||||
}
|
||||
log.Println(string(result))
|
||||
|
||||
log.Println("--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger")
|
||||
result, err = contract.EvaluateTransaction("GetAllAssets")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to evaluate transaction: %v", err)
|
||||
}
|
||||
log.Println(string(result))
|
||||
|
||||
log.Println("--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments")
|
||||
result, err = contract.SubmitTransaction("CreateAsset", "asset13", "yellow", "5", "Tom", "1300")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to Submit transaction: %v", err)
|
||||
}
|
||||
log.Println(string(result))
|
||||
|
||||
log.Println("--> Evaluate Transaction: ReadAsset, function returns an asset with a given assetID")
|
||||
result, err = contract.EvaluateTransaction("ReadAsset", "asset13")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to evaluate transaction: %v\n", err)
|
||||
}
|
||||
log.Println(string(result))
|
||||
|
||||
log.Println("--> Evaluate Transaction: AssetExists, function returns 'true' if an asset with given assetID exist")
|
||||
result, err = contract.EvaluateTransaction("AssetExists", "asset1")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to evaluate transaction: %v\n", err)
|
||||
}
|
||||
log.Println(string(result))
|
||||
|
||||
log.Println("--> Submit Transaction: TransferAsset asset1, transfer to new owner of Tom")
|
||||
_, err = contract.SubmitTransaction("TransferAsset", "asset1", "Tom")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to Submit transaction: %v", err)
|
||||
}
|
||||
|
||||
log.Println("--> Evaluate Transaction: ReadAsset, function returns 'asset1' attributes")
|
||||
result, err = contract.EvaluateTransaction("ReadAsset", "asset1")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to evaluate transaction: %v", err)
|
||||
}
|
||||
log.Println(string(result))
|
||||
log.Println("============ application-golang ends ============")
|
||||
}
|
||||
|
||||
func populateWallet(wallet *gateway.Wallet) error {
|
||||
log.Println("============ Populating wallet ============")
|
||||
credPath := filepath.Join(
|
||||
"..",
|
||||
"..",
|
||||
"test-network",
|
||||
"organizations",
|
||||
"peerOrganizations",
|
||||
"org1.example.com",
|
||||
"users",
|
||||
"User1@org1.example.com",
|
||||
"msp",
|
||||
)
|
||||
|
||||
certPath := filepath.Join(credPath, "signcerts", "cert.pem")
|
||||
// read the certificate pem
|
||||
cert, err := ioutil.ReadFile(filepath.Clean(certPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyDir := filepath.Join(credPath, "keystore")
|
||||
// there's a single file in this dir containing the private key
|
||||
files, err := ioutil.ReadDir(keyDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(files) != 1 {
|
||||
return fmt.Errorf("keystore folder should have contain one file")
|
||||
}
|
||||
keyPath := filepath.Join(keyDir, files[0].Name())
|
||||
key, err := ioutil.ReadFile(filepath.Clean(keyPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key))
|
||||
|
||||
return wallet.Put("appUser", identity)
|
||||
}
|
||||
5
asset-transfer-basic/application-go/go.mod
Normal file
5
asset-transfer-basic/application-go/go.mod
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
module asset-transfer-basic
|
||||
|
||||
go 1.14
|
||||
|
||||
require github.com/hyperledger/fabric-sdk-go v1.0.0-rc1
|
||||
277
asset-transfer-basic/application-go/go.sum
Normal file
277
asset-transfer-basic/application-go/go.sum
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||
github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw=
|
||||
github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo=
|
||||
github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4=
|
||||
github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93 h1:qdfmdGwtm13OVx+AxguOWUTbgmXGn2TbdUHipo3chMg=
|
||||
github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
|
||||
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno=
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hyperledger/fabric-config v0.0.5 h1:khRkm8U9Ghdg8VmZfptgzCFlCzrka8bPfUkM+/j6Zlg=
|
||||
github.com/hyperledger/fabric-config v0.0.5/go.mod h1:YpITBI/+ZayA3XWY5lF302K7PAsFYjEEPM/zr3hegA8=
|
||||
github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324=
|
||||
github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85 h1:bNgEcCg5NVRWs/T+VUEfhgh5Olx/N4VB+0+ybW+oSuA=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 h1:SEbB3yH4ISTGRifDamYXAst36gO2kM855ndMJlsv+pc=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
|
||||
github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f h1:eAkJx0+8PBbfP6xZxVRD2agk9W7oDbqllxO+ERgnKJk=
|
||||
github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE=
|
||||
github.com/hyperledger/fabric-sdk-go v1.0.0-beta2 h1:FBYygns0Qga+mQ4PXycyTU5m4N9KAZM+Ttf7agiV7M8=
|
||||
github.com/hyperledger/fabric-sdk-go v1.0.0-beta2/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE=
|
||||
github.com/hyperledger/fabric-sdk-go v1.0.0-beta3.0.20201006151309-9c426dcc5096 h1:veml7LmfavSHqF8w8z/PGGlfdXvmx5SstQIH6Nyy87c=
|
||||
github.com/hyperledger/fabric-sdk-go v1.0.0-beta3.0.20201006151309-9c426dcc5096/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo=
|
||||
github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
|
||||
github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c=
|
||||
github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.7.6 h1:U+1DqNen04MdEPgFiIwdOUiqZ8qPa37xgogX/sd3+54=
|
||||
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238 h1:+MZW2uvHgN8kYvksEN3f7eFL2wpzk0GxmlFsMybWc7E=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
|
||||
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/pelletier/go-toml v1.1.0 h1:cmiOvKzEunMsAxyhXSzpL5Q1CRKpVv0KQsnAIcSEVYM=
|
||||
github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
|
||||
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 h1:osmNoEW2SCW3L7EX0km2LYM8HKpNWRiouxjE3XHkyGc=
|
||||
github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f h1:c9M4CCa6g8WURSsbrl3lb/w/G1Z5xZpYvhhjdcVDOkE=
|
||||
github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/spf13/afero v1.1.0 h1:bopulORc2JeYaxfHLvJa5NzxviA9PoWhpiiJkru7Ji4=
|
||||
github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.3.1 h1:GPTpEAuNr98px18yNQ66JllNil98wfRZ/5Ukny8FeQA=
|
||||
github.com/spf13/afero v1.3.1/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
|
||||
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso=
|
||||
github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/spf13/viper v1.1.1 h1:/8JBRFO4eoHu1TmpsLgNBq1CQgRUg4GolYlEFieqJgo=
|
||||
github.com/spf13/viper v1.1.1/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
|
||||
github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU=
|
||||
github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
|
||||
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
|
||||
github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e h1:mvOa4+/DXStR4ZXOks/UsjeFdn5O5JpLUtzqk9U8xXw=
|
||||
github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8=
|
||||
github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg=
|
||||
github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8=
|
||||
google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
6
asset-transfer-basic/application-java/.gitattributes
vendored
Normal file
6
asset-transfer-basic/application-java/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
43
asset-transfer-basic/application-java/build.gradle
Normal file
43
asset-transfer-basic/application-java/build.gradle
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* This generated file contains a sample Java project to get you started.
|
||||
* For more details take a look at the Java Quickstart chapter in the Gradle
|
||||
* User Manual available at https://docs.gradle.org/6.5/userguide/tutorial_java_projects.html
|
||||
*/
|
||||
|
||||
plugins {
|
||||
// Apply the java plugin to add support for Java
|
||||
id 'java'
|
||||
|
||||
// Apply the application plugin to add support for building a CLI application.
|
||||
id 'application'
|
||||
}
|
||||
ext {
|
||||
javaMainClass = "application.java.App"
|
||||
}
|
||||
|
||||
repositories {
|
||||
// Use jcenter for resolving dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// This dependency is used by the application.
|
||||
implementation 'com.google.guava:guava:29.0-jre'
|
||||
implementation 'org.hyperledger.fabric:fabric-gateway-java:2.1.1'
|
||||
}
|
||||
|
||||
application {
|
||||
// Define the main class for the application.
|
||||
mainClassName = 'application.java.App'
|
||||
}
|
||||
|
||||
// task for running the app after building dependencies
|
||||
task runApp(type: Exec) {
|
||||
dependsOn build
|
||||
group = "Execution"
|
||||
description = "Run the main class with ExecTask"
|
||||
commandLine "java", "-classpath", sourceSets.main.runtimeClasspath.getAsPath(), javaMainClass
|
||||
}
|
||||
BIN
asset-transfer-basic/application-java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
asset-transfer-basic/application-java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
|
|
@ -1,7 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
185
asset-transfer-basic/application-java/gradlew
vendored
Executable file
185
asset-transfer-basic/application-java/gradlew
vendored
Executable file
|
|
@ -0,0 +1,185 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
@ -1,94 +1,104 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
* in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
rootProject.name = 'asset-transfer-basic'
|
||||
rootProject.name = 'application-java'
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// Running TestApp:
|
||||
// gradle runApp
|
||||
|
||||
package application.java;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import org.hyperledger.fabric.gateway.Contract;
|
||||
import org.hyperledger.fabric.gateway.Gateway;
|
||||
import org.hyperledger.fabric.gateway.Network;
|
||||
import org.hyperledger.fabric.gateway.Wallet;
|
||||
import org.hyperledger.fabric.gateway.Wallets;
|
||||
|
||||
|
||||
public class App {
|
||||
|
||||
static {
|
||||
System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true");
|
||||
}
|
||||
|
||||
// helper function for getting connected to the gateway
|
||||
public static Gateway connect() throws Exception{
|
||||
// Load a file system based wallet for managing identities.
|
||||
Path walletPath = Paths.get("wallet");
|
||||
Wallet wallet = Wallets.newFileSystemWallet(walletPath);
|
||||
// load a CCP
|
||||
Path networkConfigPath = Paths.get("..", "..", "test-network", "organizations", "peerOrganizations", "org1.example.com", "connection-org1.yaml");
|
||||
|
||||
Gateway.Builder builder = Gateway.createBuilder();
|
||||
builder.identity(wallet, "appUser").networkConfig(networkConfigPath).discovery(true);
|
||||
return builder.connect();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// enrolls the admin and registers the user
|
||||
try {
|
||||
EnrollAdmin.main(null);
|
||||
RegisterUser.main(null);
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
|
||||
// connect to the network and invoke the smart contract
|
||||
try (Gateway gateway = connect()) {
|
||||
|
||||
// get the network and contract
|
||||
Network network = gateway.getNetwork("mychannel");
|
||||
Contract contract = network.getContract("basic");
|
||||
|
||||
byte[] result;
|
||||
|
||||
System.out.println("Submit Transaction: InitLedger creates the initial set of assets on the ledger.");
|
||||
contract.submitTransaction("InitLedger");
|
||||
|
||||
System.out.println("\n");
|
||||
result = contract.evaluateTransaction("GetAllAssets");
|
||||
System.out.println("Evaluate Transaction: GetAllAssets, result: " + new String(result));
|
||||
|
||||
System.out.println("\n");
|
||||
System.out.println("Submit Transaction: CreateAsset asset13");
|
||||
//CreateAsset creates an asset with ID asset13, color yellow, owner Tom, size 5 and appraisedValue of 1300
|
||||
contract.submitTransaction("CreateAsset", "asset13", "yellow", "5", "Tom", "1300");
|
||||
|
||||
System.out.println("\n");
|
||||
System.out.println("Evaluate Transaction: ReadAsset asset13");
|
||||
// ReadAsset returns an asset with given assetID
|
||||
result = contract.evaluateTransaction("ReadAsset", "asset13");
|
||||
System.out.println("result: " + new String(result));
|
||||
|
||||
System.out.println("\n");
|
||||
System.out.println("Evaluate Transaction: AssetExists asset1");
|
||||
// AssetExists returns "true" if an asset with given assetID exist
|
||||
result = contract.evaluateTransaction("AssetExists", "asset1");
|
||||
System.out.println("result: " + new String(result));
|
||||
|
||||
System.out.println("\n");
|
||||
System.out.println("Submit Transaction: UpdateAsset asset1, new AppraisedValue : 350");
|
||||
// UpdateAsset updates an existing asset with new properties. Same args as CreateAsset
|
||||
contract.submitTransaction("UpdateAsset", "asset1", "blue", "5", "Tomoko", "350");
|
||||
|
||||
System.out.println("\n");
|
||||
System.out.println("Evaluate Transaction: ReadAsset asset1");
|
||||
result = contract.evaluateTransaction("ReadAsset", "asset1");
|
||||
System.out.println("result: " + new String(result));
|
||||
|
||||
try {
|
||||
System.out.println("\n");
|
||||
System.out.println("Submit Transaction: UpdateAsset asset70");
|
||||
//Non existing asset asset70 should throw Error
|
||||
contract.submitTransaction("UpdateAsset", "asset70", "blue", "5", "Tomoko", "300");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Expected an error on UpdateAsset of non-existing Asset: " + e);
|
||||
}
|
||||
|
||||
System.out.println("\n");
|
||||
System.out.println("Submit Transaction: TransferAsset asset1 from owner Tomoko > owner Tom");
|
||||
// TransferAsset transfers an asset with given ID to new owner Tom
|
||||
contract.submitTransaction("TransferAsset", "asset1", "Tom");
|
||||
|
||||
System.out.println("\n");
|
||||
System.out.println("Evaluate Transaction: ReadAsset asset1");
|
||||
result = contract.evaluateTransaction("ReadAsset", "asset1");
|
||||
System.out.println("result: " + new String(result));
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package application.java;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hyperledger.fabric.gateway.Wallet;
|
||||
import org.hyperledger.fabric.gateway.Wallets;
|
||||
import org.hyperledger.fabric.gateway.Identities;
|
||||
import org.hyperledger.fabric.gateway.Identity;
|
||||
import org.hyperledger.fabric.sdk.Enrollment;
|
||||
import org.hyperledger.fabric.sdk.security.CryptoSuite;
|
||||
import org.hyperledger.fabric.sdk.security.CryptoSuiteFactory;
|
||||
import org.hyperledger.fabric_ca.sdk.EnrollmentRequest;
|
||||
import org.hyperledger.fabric_ca.sdk.HFCAClient;
|
||||
|
||||
public class EnrollAdmin {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// Create a CA client for interacting with the CA.
|
||||
Properties props = new Properties();
|
||||
props.put("pemFile",
|
||||
"../../test-network/organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem");
|
||||
props.put("allowAllHostNames", "true");
|
||||
HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props);
|
||||
CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
|
||||
caClient.setCryptoSuite(cryptoSuite);
|
||||
|
||||
// Create a wallet for managing identities
|
||||
Wallet wallet = Wallets.newFileSystemWallet(Paths.get("wallet"));
|
||||
|
||||
// Check to see if we've already enrolled the admin user.
|
||||
if (wallet.get("admin") != null) {
|
||||
System.out.println("An identity for the admin user \"admin\" already exists in the wallet");
|
||||
return;
|
||||
}
|
||||
|
||||
// Enroll the admin user, and import the new identity into the wallet.
|
||||
final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest();
|
||||
enrollmentRequestTLS.addHost("localhost");
|
||||
enrollmentRequestTLS.setProfile("tls");
|
||||
Enrollment enrollment = caClient.enroll("admin", "adminpw", enrollmentRequestTLS);
|
||||
Identity user = Identities.newX509Identity("Org1MSP", enrollment);
|
||||
wallet.put("admin", user);
|
||||
System.out.println("Successfully enrolled user \"admin\" and imported it into the wallet");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package application.java;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hyperledger.fabric.gateway.Wallet;
|
||||
import org.hyperledger.fabric.gateway.Wallets;
|
||||
import org.hyperledger.fabric.gateway.Identities;
|
||||
import org.hyperledger.fabric.gateway.Identity;
|
||||
import org.hyperledger.fabric.gateway.X509Identity;
|
||||
import org.hyperledger.fabric.sdk.Enrollment;
|
||||
import org.hyperledger.fabric.sdk.User;
|
||||
import org.hyperledger.fabric.sdk.security.CryptoSuite;
|
||||
import org.hyperledger.fabric.sdk.security.CryptoSuiteFactory;
|
||||
import org.hyperledger.fabric_ca.sdk.HFCAClient;
|
||||
import org.hyperledger.fabric_ca.sdk.RegistrationRequest;
|
||||
|
||||
public class RegisterUser {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// Create a CA client for interacting with the CA.
|
||||
Properties props = new Properties();
|
||||
props.put("pemFile",
|
||||
"../../test-network/organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem");
|
||||
props.put("allowAllHostNames", "true");
|
||||
HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props);
|
||||
CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
|
||||
caClient.setCryptoSuite(cryptoSuite);
|
||||
|
||||
// Create a wallet for managing identities
|
||||
Wallet wallet = Wallets.newFileSystemWallet(Paths.get("wallet"));
|
||||
|
||||
// Check to see if we've already enrolled the user.
|
||||
if (wallet.get("appUser") != null) {
|
||||
System.out.println("An identity for the user \"appUser\" already exists in the wallet");
|
||||
return;
|
||||
}
|
||||
|
||||
X509Identity adminIdentity = (X509Identity)wallet.get("admin");
|
||||
if (adminIdentity == null) {
|
||||
System.out.println("\"admin\" needs to be enrolled and added to the wallet first");
|
||||
return;
|
||||
}
|
||||
User admin = new User() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "admin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccount() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAffiliation() {
|
||||
return "org1.department1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enrollment getEnrollment() {
|
||||
return new Enrollment() {
|
||||
|
||||
@Override
|
||||
public PrivateKey getKey() {
|
||||
return adminIdentity.getPrivateKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCert() {
|
||||
return Identities.toPemString(adminIdentity.getCertificate());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMspId() {
|
||||
return "Org1MSP";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Register the user, enroll the user, and import the new identity into the wallet.
|
||||
RegistrationRequest registrationRequest = new RegistrationRequest("appUser");
|
||||
registrationRequest.setAffiliation("org1.department1");
|
||||
registrationRequest.setEnrollmentID("appUser");
|
||||
String enrollmentSecret = caClient.register(registrationRequest, admin);
|
||||
Enrollment enrollment = caClient.enroll("appUser", enrollmentSecret);
|
||||
Identity user = Identities.newX509Identity("Org1MSP", enrollment);
|
||||
wallet.put("appUser", user);
|
||||
System.out.println("Successfully enrolled user \"appUser\" and imported it into the wallet");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# initialize root logger with level ERROR for stdout and fout
|
||||
log4j.rootLogger=ERROR,stdout,fout
|
||||
# set the log level for these components
|
||||
log4j.logger.com.endeca=INFO
|
||||
log4j.logger.com.endeca.itl.web.metrics=INFO
|
||||
|
||||
# add a ConsoleAppender to the logger stdout to write to the console
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
# use a simple message format
|
||||
log4j.appender.stdout.layout.ConversionPattern=%m%n
|
||||
|
||||
# add a FileAppender to the logger fout
|
||||
log4j.appender.fout=org.apache.log4j.FileAppender
|
||||
# create a log file
|
||||
log4j.appender.fout.File=crawl.log
|
||||
log4j.appender.fout.layout=org.apache.log4j.PatternLayout
|
||||
# use a more detailed message pattern
|
||||
log4j.appender.fout.layout.ConversionPattern=%p\t%d{ISO8601}\t%r\t%c\t[%t]\t%m%n
|
||||
36
asset-transfer-basic/application-javascript/.eslintrc.js
Normal file
36
asset-transfer-basic/application-javascript/.eslintrc.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
node: true,
|
||||
mocha: true
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 8,
|
||||
sourceType: 'script'
|
||||
},
|
||||
extends: "eslint:recommended",
|
||||
rules: {
|
||||
indent: ['error', 'tab'],
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
quotes: ['error', 'single'],
|
||||
semi: ['error', 'always'],
|
||||
'no-unused-vars': ['error', { args: 'none' }],
|
||||
'no-console': 'off',
|
||||
curly: 'error',
|
||||
eqeqeq: 'error',
|
||||
'no-throw-literal': 'error',
|
||||
strict: 'error',
|
||||
'no-var': 'error',
|
||||
'dot-notation': 'error',
|
||||
'no-trailing-spaces': 'error',
|
||||
'no-use-before-define': 'error',
|
||||
'no-useless-call': 'error',
|
||||
'no-with': 'error',
|
||||
'operator-linebreak': 'error',
|
||||
yoda: 'error',
|
||||
'quote-props': ['error', 'as-needed']
|
||||
}
|
||||
};
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
|
|
@ -11,6 +10,5 @@ node_modules/
|
|||
jspm_packages/
|
||||
package-lock.json
|
||||
|
||||
# Compiled TypeScript files
|
||||
dist
|
||||
|
||||
wallet
|
||||
!wallet/.gitkeep
|
||||
180
asset-transfer-basic/application-javascript/app.js
Normal file
180
asset-transfer-basic/application-javascript/app.js
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Gateway, Wallets } = require('fabric-network');
|
||||
const FabricCAServices = require('fabric-ca-client');
|
||||
const path = require('path');
|
||||
const { buildCAClient, registerAndEnrollUser, enrollAdmin } = require('../../test-application/javascript/CAUtil.js');
|
||||
const { buildCCPOrg1, buildWallet } = require('../../test-application/javascript/AppUtil.js');
|
||||
|
||||
const channelName = 'mychannel';
|
||||
const chaincodeName = 'basic';
|
||||
const mspOrg1 = 'Org1MSP';
|
||||
const walletPath = path.join(__dirname, 'wallet');
|
||||
const org1UserId = 'appUser';
|
||||
|
||||
function prettyJSONString(inputString) {
|
||||
return JSON.stringify(JSON.parse(inputString), null, 2);
|
||||
}
|
||||
|
||||
// pre-requisites:
|
||||
// - fabric-sample two organization test-network setup with two peers, ordering service,
|
||||
// and 2 certificate authorities
|
||||
// ===> from directory /fabric-samples/test-network
|
||||
// ./network.sh up createChannel -ca
|
||||
// - Use any of the asset-transfer-basic chaincodes deployed on the channel "mychannel"
|
||||
// with the chaincode name of "basic". The following deploy command will package,
|
||||
// install, approve, and commit the javascript chaincode, all the actions it takes
|
||||
// to deploy a chaincode to a channel.
|
||||
// ===> from directory /fabric-samples/test-network
|
||||
// ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
|
||||
// - Be sure that node.js is installed
|
||||
// ===> from directory /fabric-samples/asset-transfer-basic/application-javascript
|
||||
// node -v
|
||||
// - npm installed code dependencies
|
||||
// ===> from directory /fabric-samples/asset-transfer-basic/application-javascript
|
||||
// npm install
|
||||
// - to run this test application
|
||||
// ===> from directory /fabric-samples/asset-transfer-basic/application-javascript
|
||||
// node app.js
|
||||
|
||||
// NOTE: If you see kind an error like these:
|
||||
/*
|
||||
2020-08-07T20:23:17.590Z - error: [DiscoveryService]: send[mychannel] - Channel:mychannel received discovery error:access denied
|
||||
******** FAILED to run the application: Error: DiscoveryService: mychannel error: access denied
|
||||
|
||||
OR
|
||||
|
||||
Failed to register user : Error: fabric-ca request register failed with errors [[ { code: 20, message: 'Authentication failure' } ]]
|
||||
******** FAILED to run the application: Error: Identity not found in wallet: appUser
|
||||
*/
|
||||
// Delete the /fabric-samples/asset-transfer-basic/application-javascript/wallet directory
|
||||
// and retry this application.
|
||||
//
|
||||
// The certificate authority must have been restarted and the saved certificates for the
|
||||
// admin and application user are not valid. Deleting the wallet store will force these to be reset
|
||||
// with the new certificate authority.
|
||||
//
|
||||
|
||||
/**
|
||||
* A test application to show basic queries operations with any of the asset-transfer-basic chaincodes
|
||||
* -- How to submit a transaction
|
||||
* -- How to query and check the results
|
||||
*
|
||||
* To see the SDK workings, try setting the logging to show on the console before running
|
||||
* export HFC_LOGGING='{"debug":"console"}'
|
||||
*/
|
||||
async function main() {
|
||||
try {
|
||||
// build an in memory object with the network configuration (also known as a connection profile)
|
||||
const ccp = buildCCPOrg1();
|
||||
|
||||
// build an instance of the fabric ca services client based on
|
||||
// the information in the network configuration
|
||||
const caClient = buildCAClient(FabricCAServices, ccp, 'ca.org1.example.com');
|
||||
|
||||
// setup the wallet to hold the credentials of the application user
|
||||
const wallet = await buildWallet(Wallets, walletPath);
|
||||
|
||||
// in a real application this would be done on an administrative flow, and only once
|
||||
await enrollAdmin(caClient, wallet, mspOrg1);
|
||||
|
||||
// in a real application this would be done only when a new user was required to be added
|
||||
// and would be part of an administrative flow
|
||||
await registerAndEnrollUser(caClient, wallet, mspOrg1, org1UserId, 'org1.department1');
|
||||
|
||||
// Create a new gateway instance for interacting with the fabric network.
|
||||
// In a real application this would be done as the backend server session is setup for
|
||||
// a user that has been verified.
|
||||
const gateway = new Gateway();
|
||||
|
||||
try {
|
||||
// setup the gateway instance
|
||||
// The user will now be able to create connections to the fabric network and be able to
|
||||
// submit transactions and query. All transactions submitted by this gateway will be
|
||||
// signed by this user using the credentials stored in the wallet.
|
||||
await gateway.connect(ccp, {
|
||||
wallet,
|
||||
identity: org1UserId,
|
||||
discovery: { enabled: true, asLocalhost: true } // using asLocalhost as this gateway is using a fabric network deployed locally
|
||||
});
|
||||
|
||||
// Build a network instance based on the channel where the smart contract is deployed
|
||||
const network = await gateway.getNetwork(channelName);
|
||||
|
||||
// Get the contract from the network.
|
||||
const contract = network.getContract(chaincodeName);
|
||||
|
||||
// Initialize a set of asset data on the channel using the chaincode 'InitLedger' function.
|
||||
// This type of transaction would only be run once by an application the first time it was started after it
|
||||
// deployed the first time. Any updates to the chaincode deployed later would likely not need to run
|
||||
// an "init" type function.
|
||||
console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger');
|
||||
await contract.submitTransaction('InitLedger');
|
||||
console.log('*** Result: committed');
|
||||
|
||||
// Let's try a query type operation (function).
|
||||
// This will be sent to just one peer and the results will be shown.
|
||||
console.log('\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger');
|
||||
let result = await contract.evaluateTransaction('GetAllAssets');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
// Now let's try to submit a transaction.
|
||||
// This will be sent to both peers and if both peers endorse the transaction, the endorsed proposal will be sent
|
||||
// to the orderer to be committed by each of the peer's to the channel ledger.
|
||||
console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments');
|
||||
result = await contract.submitTransaction('CreateAsset', 'asset13', 'yellow', '5', 'Tom', '1300');
|
||||
console.log('*** Result: committed');
|
||||
if (`${result}` !== '') {
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
}
|
||||
|
||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns an asset with a given assetID');
|
||||
result = await contract.evaluateTransaction('ReadAsset', 'asset13');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
console.log('\n--> Evaluate Transaction: AssetExists, function returns "true" if an asset with given assetID exist');
|
||||
result = await contract.evaluateTransaction('AssetExists', 'asset1');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
console.log('\n--> Submit Transaction: UpdateAsset asset1, change the appraisedValue to 350');
|
||||
await contract.submitTransaction('UpdateAsset', 'asset1', 'blue', '5', 'Tomoko', '350');
|
||||
console.log('*** Result: committed');
|
||||
|
||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes');
|
||||
result = await contract.evaluateTransaction('ReadAsset', 'asset1');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
try {
|
||||
// How about we try a transactions where the executing chaincode throws an error
|
||||
// Notice how the submitTransaction will throw an error containing the error thrown by the chaincode
|
||||
console.log('\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error');
|
||||
await contract.submitTransaction('UpdateAsset', 'asset70', 'blue', '5', 'Tomoko', '300');
|
||||
console.log('******** FAILED to return an error');
|
||||
} catch (error) {
|
||||
console.log(`*** Successfully caught the error: \n ${error}`);
|
||||
}
|
||||
|
||||
console.log('\n--> Submit Transaction: TransferAsset asset1, transfer to new owner of Tom');
|
||||
await contract.submitTransaction('TransferAsset', 'asset1', 'Tom');
|
||||
console.log('*** Result: committed');
|
||||
|
||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes');
|
||||
result = await contract.evaluateTransaction('ReadAsset', 'asset1');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
} finally {
|
||||
// Disconnect from the gateway when the application is closing
|
||||
// This will close all connections to the network
|
||||
gateway.disconnect();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`******** FAILED to run the application: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
16
asset-transfer-basic/application-javascript/package.json
Normal file
16
asset-transfer-basic/application-javascript/package.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "asset-transfer-basic",
|
||||
"version": "1.0.0",
|
||||
"description": "Asset-transfer-basic application implemented in JavaScript",
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"author": "Hyperledger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-ca-client": "^2.2.4",
|
||||
"fabric-network": "^2.2.4"
|
||||
}
|
||||
}
|
||||
|
|
@ -12,3 +12,4 @@ jspm_packages/
|
|||
|
||||
# Compiled TypeScript files
|
||||
dist
|
||||
|
||||
263
asset-transfer-basic/application-typescript-hsm/README.md
Normal file
263
asset-transfer-basic/application-typescript-hsm/README.md
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
# Asset Transfer Basic typescript HSM sample
|
||||
|
||||
This sample takes the Asset Transfer basic example and re-works it to focus on how
|
||||
you would use a Hardware Security Modules within your node client application.
|
||||
|
||||
## About the Sample
|
||||
|
||||
This typescript sample application is able to use any of the asset transfer basic
|
||||
chaincode samples. It will show how to register users with a Fabric CA and enroll users which will store keys in an HSM (In this case the sample uses SoftHSM which is an HSM implementation that should be used for development and testing purposes only). It also demonstrates setting up a wallet that will store identities that can then be used to transact on the fabric network which are HSM managed.
|
||||
|
||||
## C Compilers
|
||||
|
||||
In order for the client application to run successfully you must ensure you have C compilers and Python 3 (Note that Python 2 may still work however Python 2 is out of support and could stop working in the future) installed otherwise the node dependency `pkcs11js` will not be built and the application will fail. The failure will look like
|
||||
|
||||
```
|
||||
Loaded the network configuration located at /home/dave/temp/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/connection-org1.json
|
||||
******** FAILED to run the application: Error: Cannot find module 'pkcs11js'
|
||||
Require stack:
|
||||
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-common/lib/impl/bccsp_pkcs11.js
|
||||
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-common/lib/Utils.js
|
||||
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-common/index.js
|
||||
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-ca-client/lib/FabricCAServices.js
|
||||
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-ca-client/index.js
|
||||
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/dist/app.js
|
||||
```
|
||||
|
||||
how to install the required C Compilers and Python will depend on your operating system and version.
|
||||
|
||||
## Configuring and running a Hardware Security Module
|
||||
|
||||
This sample sets the hsmOptions for the wallet as follows
|
||||
|
||||
```javascript
|
||||
const softHSMOptions: HsmOptions = {
|
||||
lib: await findSoftHSMPKCS11Lib(),
|
||||
pin: process.env.PKCS11_PIN || '98765432',
|
||||
label: process.env.PKCS11_LABEL || 'ForFabric',
|
||||
};
|
||||
```
|
||||
|
||||
which is specific to using SoftHSM which has been initialised with a token labelled `ForFabric`
|
||||
and a user pin of `98765432`, however you can override these values to use your own HSM by either
|
||||
editting the application or use these environment variables to pass in the values:
|
||||
|
||||
* PKCS11_LIB - path to the your specific HSM Library
|
||||
* PKCS11_PIN - your HSM pin
|
||||
* PKCS11_LABEL - your HSM label
|
||||
|
||||
Alternatively you could install SoftHSM to try out the application as described in the next sections
|
||||
|
||||
### Install SoftHSM
|
||||
|
||||
In order to run the application in the absence of a real HSM, a software
|
||||
emulator of the PKCS#11 interface is required.
|
||||
For more information please refer to [SoftHSM](https://www.opendnssec.org/softhsm/).
|
||||
|
||||
SoftHSM can either be installed using the package manager for your host system:
|
||||
|
||||
* Ubuntu: `sudo apt install softhsm2`
|
||||
* macOS: `brew install softhsm`
|
||||
* Windows: **unsupported**
|
||||
|
||||
Or compiled and installed from source:
|
||||
|
||||
1. install openssl 1.0.0+ or botan 1.10.0+
|
||||
2. download the source code from <https://dist.opendnssec.org/source/softhsm-2.5.0.tar.gz>
|
||||
3. `tar -xvf softhsm-2.5.0.tar.gz`
|
||||
4. `cd softhsm-2.5.0`
|
||||
5. `./configure --disable-gost` (would require additional libraries, turn it off unless you need 'gost' algorithm support for the Russian market)
|
||||
6. `make`
|
||||
7. `sudo make install`
|
||||
|
||||
### Specify the SoftHSM configuration file
|
||||
|
||||
A configuration file for SoftHSM is provided in this sample directory. This file
|
||||
uses /tmp as the location for SoftHSM to store it's data which means (depending on
|
||||
your operating system configuration) the data could be deleted at some point, for example
|
||||
when you reboot your system. If this data is lost then you will have to delete the wallet
|
||||
created. An alternative is to change this file to store SoftHSM data in a permanent location
|
||||
on your file system.
|
||||
To use this configuration file you need to export an environment variable to point to it
|
||||
for example, if you are in the application directory then you can use the following command
|
||||
|
||||
```bash
|
||||
export SOFTHSM2_CONF=$PWD/softhsm2.conf
|
||||
```
|
||||
|
||||
Ensure you have this set when initializing the token as well as running the application
|
||||
|
||||
### Initialize a token to store keys in SoftHSM
|
||||
|
||||
If you have not initialized a token previously (or it has been deleted) then you will need to perform this one time operation
|
||||
|
||||
```bash
|
||||
softhsm2-util --init-token --slot 0 --label "ForFabric" --pin 98765432 --so-pin 1234
|
||||
```
|
||||
|
||||
The Security Officer PIN, specified with the `--so-pin` flag, can be used to re-initialize the token,
|
||||
and the user PIN (see below), specified with the `--pin` flag, is used by applications to access the token for
|
||||
generating and retrieving keys.
|
||||
|
||||
## Running the sample
|
||||
|
||||
Use the Fabric test network utility (`network.sh`) to start a Fabric network and deploy one
|
||||
one of the sample chaincodes.
|
||||
|
||||
Follow these step in order.
|
||||
- Start the test network with a Certificate Authority and create a channel, so assuming you are in the ensuring you are in the `application-typescript-hsm` directory
|
||||
|
||||
```
|
||||
cd ../../test-network
|
||||
./network.sh down
|
||||
./network.sh up createChannel -c mychannel -ca
|
||||
```
|
||||
|
||||
- Deploy the chaincode (smart contract)
|
||||
|
||||
```
|
||||
# to deploy the javascript version
|
||||
./network.sh deployCC -ccs 1 -ccv 1 -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -ccl javascript -ccp ./../asset-transfer-basic/chaincode-javascript/ -ccn basic
|
||||
```
|
||||
|
||||
- Run the application
|
||||
|
||||
```
|
||||
cd ../asset-transfer-basic/application-typescript-hsm
|
||||
npm install
|
||||
npm run build
|
||||
node dist/app.js
|
||||
```
|
||||
|
||||
### Expected successful execution
|
||||
|
||||
If the sample runs successfully then it will output several messages showing the various actions and finally display the message
|
||||
|
||||
```
|
||||
*** The sample ran successfully ***
|
||||
```
|
||||
|
||||
One the first run of the sample, a CA admin id from Org1 will be enrolled from the CA. The certificate for this admin will be stored in the application wallet but the private key will have been stored in the HSM, it will not be in the application wallet. A User in Org1 will be registered in the the Org1 CA and then enrolled. Again only it's certificate will be stored in the application wallet.
|
||||
All signing of transactions done by the application (driven by the node sdk) will actually be done by the HSM rather than within the node sdk as the private key will never be directly available outside of the HSM.
|
||||
|
||||
This sample can be run multiple times even while the same network remains up. As the certificates are already in the application wallet it will not have to enroll a CA admin or register and enroll a user.
|
||||
|
||||
### Possible issues you could encounter running the sample
|
||||
|
||||
If you see this error:
|
||||
|
||||
```
|
||||
******** FAILED to run the application: Pkcs11Error: CKR_GENERAL_ERROR
|
||||
```
|
||||
Make sure you have exported SOFTHSM2_CONF correctly and it points to a valid SoftHSM configuration file that references
|
||||
a directory containing a initialised SoftHSM token
|
||||
|
||||
|
||||
If you see this error:
|
||||
|
||||
```
|
||||
2020-08-07T20:23:17.590Z - error: [DiscoveryService]: send[mychannel] - Channel:mychannel received discovery error:access denied
|
||||
******** FAILED to run the application: Error: DiscoveryService: mychannel error: access denied
|
||||
```
|
||||
|
||||
Then the current certificates in your wallet are not valid for the network you are trying to interact with. This would happen if you had
|
||||
shutdown the fabric network using `network.sh down` and created a new network because this causes all the root certificates to be recreated
|
||||
To address this problem, you can delete the `wallet` directory in the `dist` folder (`fabric-samples/asset-transfer-basic/application-typescript-hsm/dist/wallet`) of this sample to create new certificates. Because new keypairs are generated these will be stored in SoftHSM and the existing old ones will not be referenced
|
||||
|
||||
If you see this error
|
||||
|
||||
```
|
||||
Failed to register user : Error: fabric-ca request register failed with errors [[ { code: 20, message: 'Authentication failure' } ]]
|
||||
******** FAILED to run the application: Error: Identity not found in wallet: appUser
|
||||
```
|
||||
|
||||
Then the most likely cause is you have deleted your wallet. You would need to either
|
||||
- stop and create a new fabric network using the `network.sh down` and then following the above instructions to start a new fabric network (but you should not re-initialize the softhsm token)
|
||||
- or change the application such that it registers a new user instead of `appUser`. This is because be default a registered user can only be enrolled once (using the userid and it's secret)
|
||||
|
||||
If you see this error
|
||||
|
||||
```
|
||||
******** FAILED to run the application: Error: _pkcs11OpenSession[336]: PKCS11 label ForFabric cannot be found in the slot list
|
||||
```
|
||||
|
||||
Then the SoftHSM token directory has been deleted (could be due to the /tmp file being cleaned up if you use the sample softhsm2.conf file provided).
|
||||
You will either need to
|
||||
- delete your existing wallet, bring down the network as described in `Clean up` section and recreate the network including re-initializing the softhsm token
|
||||
- or you could just re-initialise the softhsm token but you will need to change the application so that it registers a new user instead of `appUser`
|
||||
|
||||
If you see this error (note the number following `SKI` will not be the same)
|
||||
|
||||
```
|
||||
******** FAILED to run the application: Error: _pkcs11SkiToHandle[572]: no key with SKI 27f3557183cd5f26384ab69968ba74944c94c0e24f681c4fadd6502886891da0 found
|
||||
```
|
||||
|
||||
Then the certificates in your wallet do not have corresponding keys in SoftHSM. You can should bring down the network and delete your current wallet (as described in `Clean up` section) and create the network again
|
||||
|
||||
|
||||
If you see either of these errors when the application ends
|
||||
|
||||
```
|
||||
free(): double free detected in tcache 2
|
||||
Aborted
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
node[61480]: ../src/node_http2.cc:521:void node::http2::Http2Session::CheckAllocatedSize(size_t) const: Assertion `(current_nghttp2_memory_) >= (previous_size)' failed.
|
||||
1: 0xa1a640 node::Abort() [node]
|
||||
2: 0xa1a6be [node]
|
||||
3: 0xa55e2a node::mem::NgLibMemoryManager<node::http2::Http2Session, nghttp2_mem>::ReallocImpl(void*, unsigned long, void*) [node]
|
||||
4: 0xa55ed3 node::mem::NgLibMemoryManager<node::http2::Http2Session, nghttp2_mem>::FreeImpl(void*, void*) [node]
|
||||
5: 0x18b0388 nghttp2_session_close_stream [node]
|
||||
6: 0x18b76ea nghttp2_session_mem_recv [node]
|
||||
7: 0xa54937 node::http2::Http2Session::ConsumeHTTP2Data() [node]
|
||||
8: 0xa54d5e node::http2::Http2Session::OnStreamRead(long, uv_buf_t const&) [node]
|
||||
9: 0xb6a651 node::TLSWrap::ClearOut() [node]
|
||||
10: 0xb6bcdb node::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
|
||||
11: 0xaf54b1 [node]
|
||||
12: 0x137fed9 [node]
|
||||
13: 0x1380500 [node]
|
||||
14: 0x1386de5 [node]
|
||||
15: 0x137458f uv_run [node]
|
||||
16: 0xa5d7a6 node::NodeMainInstance::Run() [node]
|
||||
17: 0x9eab6c node::Start(int, char**) [node]
|
||||
18: 0x7fd7612180b3 __libc_start_main [/lib/x86_64-linux-gnu/libc.so.6]
|
||||
19: 0x981fe5 [node]
|
||||
Aborted (core dumped)
|
||||
```
|
||||
|
||||
then this is due to a bug in `node`. May sure you are using the latest supported version of node, however at the time of writing (node 14.17.1 & node 12.22.1) a fix had not been released by node.js
|
||||
|
||||
### Enabling Node SDK logging
|
||||
|
||||
To see the SDK workings, try setting the logging to show on the console before running
|
||||
```
|
||||
export HFC_LOGGING='{"debug":"console"}'
|
||||
```
|
||||
or log to a file
|
||||
```
|
||||
export HFC_LOGGING='{"debug":"./debug.log"}'
|
||||
```
|
||||
|
||||
## Clean up
|
||||
|
||||
When you are finished, you can bring down the test network.
|
||||
The command will remove all the nodes of the test network, and delete any
|
||||
ledger data that you created:
|
||||
|
||||
```bash
|
||||
cd ../../test-network
|
||||
./network.sh down
|
||||
```
|
||||
Be sure to delete the wallet directory create by the application.
|
||||
The stored identities will no longer be valid when restarting the network.
|
||||
For example if you are in the application-typescript-hsm directory
|
||||
|
||||
```bash
|
||||
rm -fr dist/wallet
|
||||
```
|
||||
|
||||
## Suggestions
|
||||
When typescript node applications log problems or terminate with a stack trace you normally would have to look at the compiled .js code to find the code that was executed in the stack trace. It would be easier if you could find the corresponding lines in the typescript source file. One solution to this problem can be found here https://github.com/evanw/node-source-map-support which will convert stack trace output to corresponding typescript file lines using the generated source maps.
|
||||
50
asset-transfer-basic/application-typescript-hsm/package.json
Normal file
50
asset-transfer-basic/application-typescript-hsm/package.json
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"name": "asset-transfer-basic",
|
||||
"version": "1.0.0",
|
||||
"description": "Asset Transfer Basic contract implemented in TypeScript",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "tslint -c tslint.json 'src/**/*.ts'",
|
||||
"pretest": "npm run lint",
|
||||
"start": "npm run build && node dist/app.js",
|
||||
"build": "tsc",
|
||||
"build:watch": "tsc -w",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"author": "Hyperledger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-ca-client": "^2.2.8",
|
||||
"fabric-network": "^2.2.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tslint": "^5.11.0",
|
||||
"typescript": "^3.1.6"
|
||||
},
|
||||
"nyc": {
|
||||
"extension": [
|
||||
".ts",
|
||||
".tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"coverage/**",
|
||||
"dist/**"
|
||||
],
|
||||
"reporter": [
|
||||
"text-summary",
|
||||
"html"
|
||||
],
|
||||
"all": true,
|
||||
"check-coverage": true,
|
||||
"statements": 100,
|
||||
"branches": 100,
|
||||
"functions": 100,
|
||||
"lines": 100
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
directories.tokendir = /tmp/
|
||||
objectstore.backend = file
|
||||
|
||||
# ERROR, WARNING, INFO, DEBUG
|
||||
log.level = INFO
|
||||
278
asset-transfer-basic/application-typescript-hsm/src/app.ts
Normal file
278
asset-transfer-basic/application-typescript-hsm/src/app.ts
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
import * as FabricCAServices from 'fabric-ca-client';
|
||||
import { Contract, Gateway, GatewayOptions, HsmOptions, HsmX509Provider, Wallets } from 'fabric-network';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { buildCCPOrg1, prettyJSONString } from './utils//AppUtil';
|
||||
import { enrollUserToWallet, registerUser, UserToEnroll, UserToRegister } from './utils/CAUtil';
|
||||
|
||||
const walletPath = path.join(__dirname, 'wallet');
|
||||
|
||||
// define information about the channel and chaincode id that will be driven by this application
|
||||
const channelName = 'mychannel';
|
||||
const chaincodeId = 'basic';
|
||||
|
||||
// define the CA Registrar
|
||||
const mspOrg1 = 'Org1MSP';
|
||||
const org1CAAdminUserId = 'admin';
|
||||
const org1CAAdminSecret = 'adminpw';
|
||||
|
||||
// define the user in org1 to use
|
||||
const org1UserId = 'appUser';
|
||||
const org1Secret = 'appUserSecret';
|
||||
const org1Affiliation = 'org1.department1';
|
||||
|
||||
type Request = 'submit' | 'evaluate';
|
||||
|
||||
interface TransactionToSendFormat {
|
||||
request: Request;
|
||||
txName: string;
|
||||
txArgs: string[];
|
||||
description?: string;
|
||||
}
|
||||
|
||||
// The set of transactions to be invoked
|
||||
const transactionsToSend: TransactionToSendFormat[] = [
|
||||
{
|
||||
request: 'submit',
|
||||
txName: 'InitLedger',
|
||||
txArgs: [],
|
||||
description: '\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger',
|
||||
},
|
||||
{
|
||||
request: 'evaluate',
|
||||
txName: 'GetAllAssets',
|
||||
txArgs: [],
|
||||
description: '\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger',
|
||||
},
|
||||
{
|
||||
request: 'submit',
|
||||
txName: 'CreateAsset',
|
||||
txArgs: ['asset13', 'yellow', '5', 'Tom', '1300'],
|
||||
description: '\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments',
|
||||
},
|
||||
{
|
||||
request: 'evaluate',
|
||||
txName: 'ReadAsset',
|
||||
txArgs: ['asset13'],
|
||||
description: '\n--> Evaluate Transaction: ReadAsset, function returns an asset with a given assetID',
|
||||
},
|
||||
{
|
||||
request: 'evaluate',
|
||||
txName: 'AssetExists',
|
||||
txArgs: ['asset1'],
|
||||
description: '\n--> Evaluate Transaction: AssetExists, function returns "true" if an asset with given assetID exist',
|
||||
},
|
||||
{
|
||||
request: 'submit',
|
||||
txName: 'UpdateAsset',
|
||||
txArgs: ['asset1', 'blue', '5', 'Tomoko', '350'],
|
||||
description: '\n--> Submit Transaction: UpdateAsset asset1, change the appraisedValue to 350',
|
||||
},
|
||||
{
|
||||
request: 'evaluate',
|
||||
txName: 'ReadAsset',
|
||||
txArgs: ['asset1'],
|
||||
description: '\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes',
|
||||
},
|
||||
{
|
||||
request: 'submit',
|
||||
txName: 'UpdateAsset',
|
||||
txArgs: ['asset70', 'blue', '5', 'Tomoko', '300'],
|
||||
description: '\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error',
|
||||
},
|
||||
{
|
||||
request: 'submit',
|
||||
txName: 'TransferAsset',
|
||||
txArgs: ['asset1', 'Tom'],
|
||||
description: '\n--> Submit Transaction: TransferAsset asset1, transfer to new owner of Tom',
|
||||
},
|
||||
{
|
||||
request: 'evaluate',
|
||||
txName: 'ReadAsset',
|
||||
txArgs: ['asset1'],
|
||||
description: '\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* A test application to show basic queries operations with any of the asset-transfer-basic chaincodes
|
||||
* -- How to submit a transaction
|
||||
* -- How to query and check the results
|
||||
*
|
||||
* To see the SDK workings, try setting the logging to show on the console before running
|
||||
* export HFC_LOGGING='{"debug":"console"}'
|
||||
*/
|
||||
async function main() {
|
||||
try {
|
||||
// build an in memory object with the network configuration (also known as a connection profile)
|
||||
const ccp = buildCCPOrg1();
|
||||
|
||||
// softhsm pkcs11 options to use
|
||||
const softHSMOptions: HsmOptions = {
|
||||
lib: await findSoftHSMPKCS11Lib(),
|
||||
pin: process.env.PKCS11_PIN || '98765432',
|
||||
label: process.env.PKCS11_LABEL || 'ForFabric',
|
||||
};
|
||||
|
||||
// setup the wallet to hold the credentials used by this application
|
||||
// Here we add the HSM provider to the provider registry of the wallet
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
const hsmProvider = new HsmX509Provider(softHSMOptions);
|
||||
wallet.getProviderRegistry().addProvider(hsmProvider);
|
||||
|
||||
// build an instance of the fabric ca services client based on
|
||||
// the information in the network configuration
|
||||
const caInfo = ccp.certificateAuthorities['ca.org1.example.com']; // lookup CA details from config
|
||||
const caTLSCACerts = caInfo.tlsCACerts.pem;
|
||||
|
||||
// Here we make sure we pass in an HSM enabled cryptosuite to this CA instance
|
||||
const hsmCAClient = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName, hsmProvider.getCryptoSuite());
|
||||
console.log(`Built a CA Client named ${caInfo.caName}`);
|
||||
|
||||
// enroll the CA admin into the wallet if it doesn't already exist in the wallet
|
||||
if (!await wallet.get(org1CAAdminUserId)) {
|
||||
await enrollUserToWallet({
|
||||
caClient: hsmCAClient,
|
||||
wallet,
|
||||
orgMspId: mspOrg1,
|
||||
userId: org1CAAdminUserId,
|
||||
userIdSecret: org1CAAdminSecret,
|
||||
} as UserToEnroll);
|
||||
}
|
||||
|
||||
// if we don't have the required user in the wallet then
|
||||
// register this user to the CA (if it's not already registered)
|
||||
// then enroll that user into the wallet
|
||||
if (!await wallet.get(org1UserId)) {
|
||||
await registerUser({
|
||||
caClient: hsmCAClient,
|
||||
adminId: org1CAAdminUserId,
|
||||
wallet,
|
||||
orgMspId: mspOrg1,
|
||||
userId: org1UserId,
|
||||
userIdSecret: org1Secret,
|
||||
affiliation: org1Affiliation,
|
||||
} as UserToRegister);
|
||||
|
||||
// By default you can only enroll a user once, after that you would have to re-enroll using the current
|
||||
// certificate rather than using the secret.
|
||||
await enrollUserToWallet({
|
||||
caClient: hsmCAClient,
|
||||
wallet,
|
||||
orgMspId: mspOrg1,
|
||||
userId: org1UserId,
|
||||
userIdSecret: org1Secret,
|
||||
} as UserToEnroll);
|
||||
}
|
||||
|
||||
// Create a new gateway instance for interacting with the fabric network bound to our user
|
||||
// This sample expects a locally deployed fabric network (ie running on the same machine in docker containers)
|
||||
// therefore we set asLocalhost to true
|
||||
const gateway = new Gateway();
|
||||
|
||||
const gatewayOpts: GatewayOptions = {
|
||||
wallet,
|
||||
identity: org1UserId,
|
||||
discovery: { enabled: true, asLocalhost: true }, // using asLocalhost as this gateway is using a fabric network deployed locally
|
||||
};
|
||||
|
||||
try {
|
||||
// setup the gateway instance
|
||||
// The user will now be able to create connections to the fabric network and be able to
|
||||
// submit transactions and query. All transactions submitted by this gateway will be
|
||||
// signed by this user using the credentials stored in the wallet.
|
||||
await gateway.connect(ccp, gatewayOpts);
|
||||
|
||||
// Build a network instance based on the channel where the smart contract is deployed
|
||||
const network = await gateway.getNetwork(channelName);
|
||||
|
||||
// Get the contract from the network.
|
||||
const contract = network.getContract(chaincodeId);
|
||||
|
||||
// loop around all transactions to send, each one will be sent sequentially
|
||||
// through the same gateway/network/contract as subsequent transations expect the
|
||||
// previous submits to have been committed
|
||||
// Note however that a gateway/network/contract can support concurrent submitted
|
||||
// transactions.
|
||||
for (const transactionToSend of transactionsToSend) {
|
||||
await interactWithFabric(contract, transactionToSend);
|
||||
}
|
||||
|
||||
console.log('*** The sample ran successfully ***');
|
||||
} finally {
|
||||
|
||||
// Disconnect from the gateway when the application is closing
|
||||
// This will close all connections to the network
|
||||
gateway.disconnect();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`******** FAILED to run the application: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the location of the SoftHSM PKCS11 Library
|
||||
* @returns the location of the SoftHSM PKCS11 Library or 'NOT FOUND' if not found
|
||||
*/
|
||||
async function findSoftHSMPKCS11Lib() {
|
||||
const commonSoftHSMPathNames = [
|
||||
'/usr/lib/softhsm/libsofthsm2.so',
|
||||
'/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so',
|
||||
'/usr/local/lib/softhsm/libsofthsm2.so',
|
||||
'/usr/lib/libacsp-pkcs11.so',
|
||||
];
|
||||
|
||||
let pkcsLibPath = 'NOT FOUND';
|
||||
if (typeof process.env.PKCS11_LIB === 'string' && process.env.PKCS11_LIB !== '') {
|
||||
pkcsLibPath = process.env.PKCS11_LIB;
|
||||
} else {
|
||||
//
|
||||
// Check common locations for PKCS library
|
||||
//
|
||||
for (const pathnameToTry of commonSoftHSMPathNames) {
|
||||
if (fs.existsSync(pathnameToTry)) {
|
||||
pkcsLibPath = pathnameToTry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pkcsLibPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the Fabric Network via the Contact with the required transaction to perform.
|
||||
* @param contract The contract to send the transaction to
|
||||
* @param transactionToPerform the transaction to perform
|
||||
*/
|
||||
async function interactWithFabric(contract: Contract, transactionToPerform: TransactionToSendFormat): Promise<void> {
|
||||
console.log(transactionToPerform.description);
|
||||
try {
|
||||
switch (transactionToPerform.request) {
|
||||
case 'submit': {
|
||||
await contract.submitTransaction(transactionToPerform.txName, ...transactionToPerform.txArgs);
|
||||
console.log('*** Result: committed');
|
||||
break;
|
||||
}
|
||||
|
||||
case 'evaluate': {
|
||||
const result = await contract.evaluateTransaction(transactionToPerform.txName, ...transactionToPerform.txArgs);
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`*** Successfully caught the error: \n ${error}`);
|
||||
// In reality applications should check the returned error to decide whether the transaction needs to be retried (ie go through
|
||||
// endorsement again) for example an MVCC_READ_CONFLICT error, resubmitted to the orderer for example a timeout because it was
|
||||
// never committed (for example due to networking issues the transaction never gets included in a block), or whether it should
|
||||
// be reported back, for example they tried to perform an invalid application action.
|
||||
}
|
||||
}
|
||||
|
||||
// execute the main function
|
||||
main();
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const buildCCPOrg1 = (): Record<string, any> => {
|
||||
// load the common connection configuration file
|
||||
const ccpPath = path.resolve(__dirname, '..', '..', '..', '..', 'test-network',
|
||||
'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
|
||||
const fileExists = fs.existsSync(ccpPath);
|
||||
if (!fileExists) {
|
||||
throw new Error(`no such file or directory: ${ccpPath}`);
|
||||
}
|
||||
const contents = fs.readFileSync(ccpPath, 'utf8');
|
||||
|
||||
// build a JSON object from the file contents
|
||||
const ccp = JSON.parse(contents);
|
||||
|
||||
console.log(`Loaded the network configuration located at ${ccpPath}`);
|
||||
return ccp;
|
||||
};
|
||||
|
||||
const buildCCPOrg2 = (): Record<string, any> => {
|
||||
// load the common connection configuration file
|
||||
const ccpPath = path.resolve(__dirname, '..', '..', '..', '..', 'test-network',
|
||||
'organizations', 'peerOrganizations', 'org2.example.com', 'connection-org2.json');
|
||||
const fileExists = fs.existsSync(ccpPath);
|
||||
if (!fileExists) {
|
||||
throw new Error(`no such file or directory: ${ccpPath}`);
|
||||
}
|
||||
const contents = fs.readFileSync(ccpPath, 'utf8');
|
||||
|
||||
// build a JSON object from the file contents
|
||||
const ccp = JSON.parse(contents);
|
||||
|
||||
console.log(`Loaded the network configuration located at ${ccpPath}`);
|
||||
return ccp;
|
||||
};
|
||||
|
||||
const prettyJSONString = (inputString: string): string => {
|
||||
if (inputString) {
|
||||
return JSON.stringify(JSON.parse(inputString), null, 2);
|
||||
} else {
|
||||
return inputString;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
buildCCPOrg1,
|
||||
buildCCPOrg2,
|
||||
prettyJSONString,
|
||||
};
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as FabricCAServices from 'fabric-ca-client';
|
||||
import { Wallet } from 'fabric-network';
|
||||
|
||||
export interface UserToEnroll {
|
||||
caClient: FabricCAServices;
|
||||
wallet: Wallet;
|
||||
orgMspId: string;
|
||||
userId: string;
|
||||
userIdSecret: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* enroll a registered CA user and store the credentials in the wallet
|
||||
* @param userToEnroll details about the user and the wallet to use
|
||||
*/
|
||||
export const enrollUserToWallet = async (userToEnroll: UserToEnroll): Promise<void> => {
|
||||
try {
|
||||
|
||||
// check that the identity isn't already in the wallet
|
||||
const identity = await userToEnroll.wallet.get(userToEnroll.userId);
|
||||
if (identity) {
|
||||
console.log(`Identity ${userToEnroll.userId} already exists in the wallet`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Enroll the user
|
||||
const enrollment = await userToEnroll.caClient.enroll({ enrollmentID: userToEnroll.userId, enrollmentSecret: userToEnroll.userIdSecret });
|
||||
|
||||
// store the user
|
||||
const hsmIdentity = {
|
||||
credentials: {
|
||||
certificate: enrollment.certificate,
|
||||
},
|
||||
mspId: userToEnroll.orgMspId,
|
||||
type: 'HSM-X.509',
|
||||
};
|
||||
await userToEnroll.wallet.put(userToEnroll.userId, hsmIdentity);
|
||||
console.log(`Successfully enrolled user ${userToEnroll.userId} and imported it into the wallet`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to enroll user ${userToEnroll.userId}: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
export interface UserToRegister {
|
||||
caClient: FabricCAServices;
|
||||
wallet: Wallet;
|
||||
orgMspId: string;
|
||||
adminId: string;
|
||||
userId: string;
|
||||
userIdSecret: string;
|
||||
affiliation: string;
|
||||
}
|
||||
|
||||
export const registerUser = async (userToRegister: UserToRegister): Promise<void> => {
|
||||
try {
|
||||
|
||||
// Must use a CA admin (registrar) to register a new user
|
||||
const adminIdentity = await userToRegister.wallet.get(userToRegister.adminId);
|
||||
if (!adminIdentity) {
|
||||
console.log('An identity for the admin user does not exist in the wallet');
|
||||
console.log('Enroll the admin user before retrying');
|
||||
return;
|
||||
}
|
||||
|
||||
// build a user object for authenticating with the CA
|
||||
const provider = userToRegister.wallet.getProviderRegistry().getProvider(adminIdentity.type);
|
||||
const adminUser = await provider.getUserContext(adminIdentity, userToRegister.adminId);
|
||||
|
||||
// Register the user
|
||||
// if affiliation is specified by client, the affiliation value must be configured in CA
|
||||
await userToRegister.caClient.register({
|
||||
affiliation: userToRegister.affiliation,
|
||||
enrollmentID: userToRegister.userId,
|
||||
enrollmentSecret: userToRegister.userIdSecret,
|
||||
role: 'client',
|
||||
}, adminUser);
|
||||
console.log(`Successfully registered ${userToRegister.userId}.`);
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
// check to see if it's an already registered error, if it is, then we can ignore it
|
||||
// otherwise we rethrow the error
|
||||
if (error.errors[0].code !== 74) {
|
||||
console.error(`Failed to register user : ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"target": "es2017",
|
||||
"moduleResolution": "node",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"./src/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
24
asset-transfer-basic/application-typescript-hsm/tslint.json
Normal file
24
asset-transfer-basic/application-typescript-hsm/tslint.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended"
|
||||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"indent": [true, "spaces", 4],
|
||||
"linebreak-style": [true, "LF"],
|
||||
"quotemark": [true, "single"],
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"curly": true,
|
||||
"triple-equals": true,
|
||||
"no-string-throw": true,
|
||||
"no-var-keyword": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"object-literal-key-quotes": [true, "as-needed"],
|
||||
"object-literal-sort-keys": false,
|
||||
"max-line-length": false,
|
||||
"interface-name":false
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
||||
|
|
@ -12,3 +12,4 @@ jspm_packages/
|
|||
|
||||
# Compiled TypeScript files
|
||||
dist
|
||||
|
||||
50
asset-transfer-basic/application-typescript/package.json
Normal file
50
asset-transfer-basic/application-typescript/package.json
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"name": "asset-transfer-basic",
|
||||
"version": "1.0.0",
|
||||
"description": "Asset Transfer Basic contract implemented in TypeScript",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "tslint -c tslint.json 'src/**/*.ts'",
|
||||
"pretest": "npm run lint",
|
||||
"start": "npm run build && node dist/app.js",
|
||||
"build": "tsc",
|
||||
"build:watch": "tsc -w",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"author": "Hyperledger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-ca-client": "^2.2.4",
|
||||
"fabric-network": "^2.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tslint": "^5.11.0",
|
||||
"typescript": "^3.1.6"
|
||||
},
|
||||
"nyc": {
|
||||
"extension": [
|
||||
".ts",
|
||||
".tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"coverage/**",
|
||||
"dist/**"
|
||||
],
|
||||
"reporter": [
|
||||
"text-summary",
|
||||
"html"
|
||||
],
|
||||
"all": true,
|
||||
"check-coverage": true,
|
||||
"statements": 100,
|
||||
"branches": 100,
|
||||
"functions": 100,
|
||||
"lines": 100
|
||||
}
|
||||
}
|
||||
171
asset-transfer-basic/application-typescript/src/app.ts
Normal file
171
asset-transfer-basic/application-typescript/src/app.ts
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
import { Gateway, GatewayOptions } from 'fabric-network';
|
||||
import * as path from 'path';
|
||||
import { buildCCPOrg1, buildWallet, prettyJSONString } from './utils//AppUtil';
|
||||
import { buildCAClient, enrollAdmin, registerAndEnrollUser } from './utils/CAUtil';
|
||||
|
||||
const channelName = 'mychannel';
|
||||
const chaincodeName = 'basic';
|
||||
const mspOrg1 = 'Org1MSP';
|
||||
const walletPath = path.join(__dirname, 'wallet');
|
||||
const org1UserId = 'appUser';
|
||||
|
||||
// pre-requisites:
|
||||
// - fabric-sample two organization test-network setup with two peers, ordering service,
|
||||
// and 2 certificate authorities
|
||||
// ===> from directory /fabric-samples/test-network
|
||||
// ./network.sh up createChannel -ca
|
||||
// - Use any of the asset-transfer-basic chaincodes deployed on the channel "mychannel"
|
||||
// with the chaincode name of "basic". The following deploy command will package,
|
||||
// install, approve, and commit the javascript chaincode, all the actions it takes
|
||||
// to deploy a chaincode to a channel.
|
||||
// ===> from directory /fabric-samples/test-network
|
||||
// ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl javascript
|
||||
// - Be sure that node.js is installed
|
||||
// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript
|
||||
// node -v
|
||||
// - npm installed code dependencies
|
||||
// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript
|
||||
// npm install
|
||||
// - to run this test application
|
||||
// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript
|
||||
// npm start
|
||||
|
||||
// NOTE: If you see kind an error like these:
|
||||
/*
|
||||
2020-08-07T20:23:17.590Z - error: [DiscoveryService]: send[mychannel] - Channel:mychannel received discovery error:access denied
|
||||
******** FAILED to run the application: Error: DiscoveryService: mychannel error: access denied
|
||||
|
||||
OR
|
||||
|
||||
Failed to register user : Error: fabric-ca request register failed with errors [[ { code: 20, message: 'Authentication failure' } ]]
|
||||
******** FAILED to run the application: Error: Identity not found in wallet: appUser
|
||||
*/
|
||||
// Delete the /fabric-samples/asset-transfer-basic/application-typescript/wallet directory
|
||||
// and retry this application.
|
||||
//
|
||||
// The certificate authority must have been restarted and the saved certificates for the
|
||||
// admin and application user are not valid. Deleting the wallet store will force these to be reset
|
||||
// with the new certificate authority.
|
||||
//
|
||||
|
||||
/**
|
||||
* A test application to show basic queries operations with any of the asset-transfer-basic chaincodes
|
||||
* -- How to submit a transaction
|
||||
* -- How to query and check the results
|
||||
*
|
||||
* To see the SDK workings, try setting the logging to show on the console before running
|
||||
* export HFC_LOGGING='{"debug":"console"}'
|
||||
*/
|
||||
async function main() {
|
||||
try {
|
||||
// build an in memory object with the network configuration (also known as a connection profile)
|
||||
const ccp = buildCCPOrg1();
|
||||
|
||||
// build an instance of the fabric ca services client based on
|
||||
// the information in the network configuration
|
||||
const caClient = buildCAClient(ccp, 'ca.org1.example.com');
|
||||
|
||||
// setup the wallet to hold the credentials of the application user
|
||||
const wallet = await buildWallet(walletPath);
|
||||
|
||||
// in a real application this would be done on an administrative flow, and only once
|
||||
await enrollAdmin(caClient, wallet, mspOrg1);
|
||||
|
||||
// in a real application this would be done only when a new user was required to be added
|
||||
// and would be part of an administrative flow
|
||||
await registerAndEnrollUser(caClient, wallet, mspOrg1, org1UserId, 'org1.department1');
|
||||
|
||||
// Create a new gateway instance for interacting with the fabric network.
|
||||
// In a real application this would be done as the backend server session is setup for
|
||||
// a user that has been verified.
|
||||
const gateway = new Gateway();
|
||||
|
||||
const gatewayOpts: GatewayOptions = {
|
||||
wallet,
|
||||
identity: org1UserId,
|
||||
discovery: { enabled: true, asLocalhost: true }, // using asLocalhost as this gateway is using a fabric network deployed locally
|
||||
};
|
||||
|
||||
try {
|
||||
// setup the gateway instance
|
||||
// The user will now be able to create connections to the fabric network and be able to
|
||||
// submit transactions and query. All transactions submitted by this gateway will be
|
||||
// signed by this user using the credentials stored in the wallet.
|
||||
await gateway.connect(ccp, gatewayOpts);
|
||||
|
||||
// Build a network instance based on the channel where the smart contract is deployed
|
||||
const network = await gateway.getNetwork(channelName);
|
||||
|
||||
// Get the contract from the network.
|
||||
const contract = network.getContract(chaincodeName);
|
||||
|
||||
// Initialize a set of asset data on the channel using the chaincode 'InitLedger' function.
|
||||
// This type of transaction would only be run once by an application the first time it was started after it
|
||||
// deployed the first time. Any updates to the chaincode deployed later would likely not need to run
|
||||
// an "init" type function.
|
||||
console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger');
|
||||
await contract.submitTransaction('InitLedger');
|
||||
console.log('*** Result: committed');
|
||||
|
||||
// Let's try a query type operation (function).
|
||||
// This will be sent to just one peer and the results will be shown.
|
||||
console.log('\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger');
|
||||
let result = await contract.evaluateTransaction('GetAllAssets');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
// Now let's try to submit a transaction.
|
||||
// This will be sent to both peers and if both peers endorse the transaction, the endorsed proposal will be sent
|
||||
// to the orderer to be committed by each of the peer's to the channel ledger.
|
||||
console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments');
|
||||
await contract.submitTransaction('CreateAsset', 'asset13', 'yellow', '5', 'Tom', '1300');
|
||||
console.log('*** Result: committed');
|
||||
|
||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns an asset with a given assetID');
|
||||
result = await contract.evaluateTransaction('ReadAsset', 'asset13');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
console.log('\n--> Evaluate Transaction: AssetExists, function returns "true" if an asset with given assetID exist');
|
||||
result = await contract.evaluateTransaction('AssetExists', 'asset1');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
console.log('\n--> Submit Transaction: UpdateAsset asset1, change the appraisedValue to 350');
|
||||
await contract.submitTransaction('UpdateAsset', 'asset1', 'blue', '5', 'Tomoko', '350');
|
||||
console.log('*** Result: committed');
|
||||
|
||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes');
|
||||
result = await contract.evaluateTransaction('ReadAsset', 'asset1');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
|
||||
try {
|
||||
// How about we try a transactions where the executing chaincode throws an error
|
||||
// Notice how the submitTransaction will throw an error containing the error thrown by the chaincode
|
||||
console.log('\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error');
|
||||
await contract.submitTransaction('UpdateAsset', 'asset70', 'blue', '5', 'Tomoko', '300');
|
||||
console.log('******** FAILED to return an error');
|
||||
} catch (error) {
|
||||
console.log(`*** Successfully caught the error: \n ${error}`);
|
||||
}
|
||||
|
||||
console.log('\n--> Submit Transaction: TransferAsset asset1, transfer to new owner of Tom');
|
||||
await contract.submitTransaction('TransferAsset', 'asset1', 'Tom');
|
||||
console.log('*** Result: committed');
|
||||
|
||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes');
|
||||
result = await contract.evaluateTransaction('ReadAsset', 'asset1');
|
||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||
} finally {
|
||||
// Disconnect from the gateway when the application is closing
|
||||
// This will close all connections to the network
|
||||
gateway.disconnect();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`******** FAILED to run the application: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Wallet, Wallets } from 'fabric-network';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const buildCCPOrg1 = (): Record<string, any> => {
|
||||
// load the common connection configuration file
|
||||
const ccpPath = path.resolve(__dirname, '..', '..', '..', '..', 'test-network',
|
||||
'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
|
||||
const fileExists = fs.existsSync(ccpPath);
|
||||
if (!fileExists) {
|
||||
throw new Error(`no such file or directory: ${ccpPath}`);
|
||||
}
|
||||
const contents = fs.readFileSync(ccpPath, 'utf8');
|
||||
|
||||
// build a JSON object from the file contents
|
||||
const ccp = JSON.parse(contents);
|
||||
|
||||
console.log(`Loaded the network configuration located at ${ccpPath}`);
|
||||
return ccp;
|
||||
};
|
||||
|
||||
const buildCCPOrg2 = (): Record<string, any> => {
|
||||
// load the common connection configuration file
|
||||
const ccpPath = path.resolve(__dirname, '..', '..', '..', '..', 'test-network',
|
||||
'organizations', 'peerOrganizations', 'org2.example.com', 'connection-org2.json');
|
||||
const fileExists = fs.existsSync(ccpPath);
|
||||
if (!fileExists) {
|
||||
throw new Error(`no such file or directory: ${ccpPath}`);
|
||||
}
|
||||
const contents = fs.readFileSync(ccpPath, 'utf8');
|
||||
|
||||
// build a JSON object from the file contents
|
||||
const ccp = JSON.parse(contents);
|
||||
|
||||
console.log(`Loaded the network configuration located at ${ccpPath}`);
|
||||
return ccp;
|
||||
};
|
||||
|
||||
const buildWallet = async (walletPath: string): Promise<Wallet> => {
|
||||
// Create a new wallet : Note that wallet is for managing identities.
|
||||
let wallet: Wallet;
|
||||
if (walletPath) {
|
||||
wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
console.log(`Built a file system wallet at ${walletPath}`);
|
||||
} else {
|
||||
wallet = await Wallets.newInMemoryWallet();
|
||||
console.log('Built an in memory wallet');
|
||||
}
|
||||
|
||||
return wallet;
|
||||
};
|
||||
|
||||
const prettyJSONString = (inputString: string): string => {
|
||||
if (inputString) {
|
||||
return JSON.stringify(JSON.parse(inputString), null, 2);
|
||||
} else {
|
||||
return inputString;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
buildCCPOrg1,
|
||||
buildCCPOrg2,
|
||||
buildWallet,
|
||||
prettyJSONString,
|
||||
};
|
||||
104
asset-transfer-basic/application-typescript/src/utils/CAUtil.ts
Normal file
104
asset-transfer-basic/application-typescript/src/utils/CAUtil.ts
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as FabricCAServices from 'fabric-ca-client';
|
||||
import { Wallet } from 'fabric-network';
|
||||
|
||||
const adminUserId = 'admin';
|
||||
const adminUserPasswd = 'adminpw';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} ccp
|
||||
*/
|
||||
const buildCAClient = (ccp: Record<string, any>, caHostName: string): FabricCAServices => {
|
||||
// Create a new CA client for interacting with the CA.
|
||||
const caInfo = ccp.certificateAuthorities[caHostName]; // lookup CA details from config
|
||||
const caTLSCACerts = caInfo.tlsCACerts.pem;
|
||||
const caClient = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName);
|
||||
|
||||
console.log(`Built a CA Client named ${caInfo.caName}`);
|
||||
return caClient;
|
||||
};
|
||||
|
||||
const enrollAdmin = async (caClient: FabricCAServices, wallet: Wallet, orgMspId: string): Promise<void> => {
|
||||
try {
|
||||
// Check to see if we've already enrolled the admin user.
|
||||
const identity = await wallet.get(adminUserId);
|
||||
if (identity) {
|
||||
console.log('An identity for the admin user already exists in the wallet');
|
||||
return;
|
||||
}
|
||||
|
||||
// Enroll the admin user, and import the new identity into the wallet.
|
||||
const enrollment = await caClient.enroll({ enrollmentID: adminUserId, enrollmentSecret: adminUserPasswd });
|
||||
const x509Identity = {
|
||||
credentials: {
|
||||
certificate: enrollment.certificate,
|
||||
privateKey: enrollment.key.toBytes(),
|
||||
},
|
||||
mspId: orgMspId,
|
||||
type: 'X.509',
|
||||
};
|
||||
await wallet.put(adminUserId, x509Identity);
|
||||
console.log('Successfully enrolled admin user and imported it into the wallet');
|
||||
} catch (error) {
|
||||
console.error(`Failed to enroll admin user : ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
const registerAndEnrollUser = async (caClient: FabricCAServices, wallet: Wallet, orgMspId: string, userId: string, affiliation: string): Promise<void> => {
|
||||
try {
|
||||
// Check to see if we've already enrolled the user
|
||||
const userIdentity = await wallet.get(userId);
|
||||
if (userIdentity) {
|
||||
console.log(`An identity for the user ${userId} already exists in the wallet`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Must use an admin to register a new user
|
||||
const adminIdentity = await wallet.get(adminUserId);
|
||||
if (!adminIdentity) {
|
||||
console.log('An identity for the admin user does not exist in the wallet');
|
||||
console.log('Enroll the admin user before retrying');
|
||||
return;
|
||||
}
|
||||
|
||||
// build a user object for authenticating with the CA
|
||||
const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type);
|
||||
const adminUser = await provider.getUserContext(adminIdentity, adminUserId);
|
||||
|
||||
// Register the user, enroll the user, and import the new identity into the wallet.
|
||||
// if affiliation is specified by client, the affiliation value must be configured in CA
|
||||
const secret = await caClient.register({
|
||||
affiliation,
|
||||
enrollmentID: userId,
|
||||
role: 'client',
|
||||
}, adminUser);
|
||||
const enrollment = await caClient.enroll({
|
||||
enrollmentID: userId,
|
||||
enrollmentSecret: secret,
|
||||
});
|
||||
const x509Identity = {
|
||||
credentials: {
|
||||
certificate: enrollment.certificate,
|
||||
privateKey: enrollment.key.toBytes(),
|
||||
},
|
||||
mspId: orgMspId,
|
||||
type: 'X.509',
|
||||
};
|
||||
await wallet.put(userId, x509Identity);
|
||||
console.log(`Successfully registered and enrolled user ${userId} and imported it into the wallet`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to register user : ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
buildCAClient,
|
||||
enrollAdmin,
|
||||
registerAndEnrollUser,
|
||||
};
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"extends":"@tsconfig/node18/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"outDir": "dist",
|
||||
"target": "es2017",
|
||||
"moduleResolution": "node",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true
|
||||
|
|
@ -12,6 +14,6 @@
|
|||
"./src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"./src/**/*.spec.ts"
|
||||
"./src/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
23
asset-transfer-basic/application-typescript/tslint.json
Normal file
23
asset-transfer-basic/application-typescript/tslint.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended"
|
||||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"indent": [true, "spaces", 4],
|
||||
"linebreak-style": [true, "LF"],
|
||||
"quotemark": [true, "single"],
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"curly": true,
|
||||
"triple-equals": true,
|
||||
"no-string-throw": true,
|
||||
"no-var-keyword": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"object-literal-key-quotes": [true, "as-needed"],
|
||||
"object-literal-sort-keys": false,
|
||||
"max-line-length": false
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
*.tar.gz
|
||||
*.tgz
|
||||
crypto/*.pem
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
FROM golang:alpine
|
||||
ARG GO_VER=1.14.4
|
||||
ARG ALPINE_VER=3.12
|
||||
|
||||
FROM golang:${GO_VER}-alpine${ALPINE_VER}
|
||||
|
||||
WORKDIR /go/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external
|
||||
COPY . .
|
||||
|
|
|
|||
|
|
@ -1,50 +1,46 @@
|
|||
# Asset-Transfer-Basic as an external service
|
||||
|
||||
This sample provides an introduction to how to use external builder and launcher scripts to run chaincode as an external service to your peer. For more information, see the [Chaincode as an external service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html) topic in the Fabric documentation.
|
||||
This sample provides an introduction to how to use external builder and launcher scripts to run chaincode as an external service to your peer. For more information, see the [Chaincode as an external service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_launcher.html) topic in the Fabric documentation.
|
||||
|
||||
**Note:** each organization in a real network would need to setup and host their own instance of the external service. In this tutorial, we use the same instance for both organizations for simplicity.
|
||||
**Note:** each organization in a real network would need to setup and host their own instance of the external service. For simplification purpose, in this sample we use the same instance for both organizations.
|
||||
|
||||
## Setting up the external builder and launcher
|
||||
|
||||
External Builders and Launchers is an advanced feature that typically requires custom packaging of the peer image so that it contains all the tools your builder and launcher require. This sample uses very simple (and crude) shell scripts that can be run directly within the default Fabric peer images.
|
||||
External Builders and Launchers is an advanced feature that typically requires custom packaging of the peer image so that it contains all the tools your builder and launcher require. For this sample we use very simple (and crude) shell scripts that can be run directly within the default Fabric peer images.
|
||||
|
||||
Open the `config/core.yaml` file at the top of the `fabric-samples` directory. If you do not have this file, follow the instructions to [Install the Samples, Binaries and Docker Images](https://hyperledger-fabric.readthedocs.io/en/latest/install.html) to download the Fabric binaries and configuration files alongside the Fabric samples.
|
||||
|
||||
Modify the `externalBuilders` field in the `core.yaml` file to resemble the configuration below:
|
||||
Open the `config/core.yaml` file at the top of the `fabric-samples` hierarchy. Note that this file comes along with the Fabric binaries, so if you don't have it, follow the [Install the Samples, Binaries and Docker Images](https://hyperledger-fabric.readthedocs.io/en/latest/install.html) instructions in the Hyperledger Fabric documentation to download the binaries and config files.
|
||||
|
||||
Modify the field `externalBuilders` as the following:
|
||||
```
|
||||
externalBuilders:
|
||||
- path: /opt/gopath/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external/sampleBuilder
|
||||
name: external-sample-builder
|
||||
```
|
||||
This configuration sets the name of the external builder as `external-sample-builder`, and the path of the builder to the scripts provided in this sample. Note that this is the path within the peer container, not your local machine.
|
||||
|
||||
This update sets the name of the external builder as `external-sample-builder`, and the path of the builder to the scripts provided in this sample. Note that this is the path within the peer container, not your local machine.
|
||||
|
||||
To set the path within the peer container, you will need to modify the docker compose file to mount a couple of additional volumes. Open the file `test-network/compose/docker/docker-compose-test-net.yaml`, and add to the `volumes` section of both `peer0.org1.example.com` and `peer0.org2.example.com` the following two lines:
|
||||
To set the path within the peer container, you will need to modify the container compose file to mount a couple of additional volumes.
|
||||
Open the file `test-network/docker/docker-compose-test-net.yaml`, and add to the `volumes` section of both `peer0.org1.example.com` and `peer0.org2.example.com` the following two lines:
|
||||
|
||||
```
|
||||
- ../..:/opt/gopath/src/github.com/hyperledger/fabric-samples
|
||||
- ../../config/core.yaml:/etc/hyperledger/peercfg/core.yaml
|
||||
- ../../config/core.yaml:/etc/hyperledger/fabric/core.yaml
|
||||
```
|
||||
|
||||
This update will mount the `core.yaml` that you modified into the peer container and override the configuration file within the peer image. The update also mounts the fabric-sample builder so that it can be found at the location that you specified in `core.yaml`. You also have the option of commenting out the line `- /var/run/docker.sock:/host/var/run/docker.sock`, since we no longer need to access the docker daemon from inside the peer container to launch the chaincode.
|
||||
This will mount the fabric-sample builder into the peer container so that it can be found at the location specified in the config file,
|
||||
and override the peer's core.yaml config file within the fabric-peer image so that the config file modified above is used.
|
||||
|
||||
## Packaging and installing Chaincode
|
||||
|
||||
The Asset-Transfer-Basic external chaincode requires two environment variables to run, `CHAINCODE_SERVER_ADDRESS` and `CHAINCODE_ID`, which are described and set in the `chaincode.env` file.
|
||||
|
||||
You need to provide a `connection.json` configuration file to your peer in order to connect to the external Asset-Transfer-Basic service. The address specified in the `connection.json` must correspond to the `CHAINCODE_SERVER_ADDRESS` value in `chaincode.env`, which is `asset-transfer-basic.org1.example.com:9999` in our example.
|
||||
The peer needs a corresponding `connection.json` configuration file so that it can connect to the external Asset-Transfer-Basic service.
|
||||
|
||||
The address specified in the `connection.json` must correspond to the `CHAINCODE_SERVER_ADDRESS` value in `chaincode.env`, which is `asset-transfer-basic.org1.example.com:9999` in our example.
|
||||
|
||||
Because we will run our chaincode as an external service, the chaincode itself does not need to be included in the chaincode
|
||||
package that gets installed to each peer. Only the configuration and metadata information needs to be included
|
||||
in the package. Since the packaging is trivial, we can manually create the chaincode package.
|
||||
|
||||
Open a new terminal and navigate to the `fabric-samples/asset-transfer-basic/chaincode-external` directory.
|
||||
|
||||
```
|
||||
cd fabric-samples/asset-transfer-basic/chaincode-external
|
||||
```
|
||||
|
||||
First, create a `code.tar.gz` archive containing the `connection.json` file:
|
||||
|
||||
```
|
||||
|
|
@ -57,196 +53,109 @@ Then, create the chaincode package, including the `code.tar.gz` file and the sup
|
|||
tar cfz asset-transfer-basic-external.tgz metadata.json code.tar.gz
|
||||
```
|
||||
|
||||
You are now ready to deploy the external chaincode sample.
|
||||
You are now ready to use the external chaincode. We will use the `test-network` sample to get a network setup and make use of it.
|
||||
|
||||
## Starting the test network
|
||||
|
||||
We will use the Fabric test network to run the external chaincode. Open a new terminal and navigate to the `fabric-samples/test-network` directory.
|
||||
|
||||
```
|
||||
cd fabric-samples/test-network
|
||||
```
|
||||
|
||||
Run the following command to deploy the test network and create a new channel:
|
||||
In a different terminal, from the `test-network` sample directory starts the network using the following command:
|
||||
|
||||
```
|
||||
./network.sh up createChannel -c mychannel -ca
|
||||
```
|
||||
|
||||
We are now ready to deploy the external chaincode.
|
||||
This starts the test network and creates the channel. We will now proceed to installing our external chaincode package.
|
||||
|
||||
## Installing the external chaincode
|
||||
|
||||
We can't use the test network script to install an external chaincode so we will have to do a bit more work. However, we can still leverage part of the test-network scripts to make this easier.
|
||||
We can't use the `test-network/network.sh` script to install our external chaincode so we will have to do a bit more work by hand but we can still leverage part of the test-network scripts to make this easier.
|
||||
|
||||
From the `test-network` directory, set the following environment variables to use the Fabric binaries:
|
||||
|
||||
```
|
||||
export PATH=${PWD}/../bin:$PATH
|
||||
export FABRIC_CFG_PATH=$PWD/../config/
|
||||
```
|
||||
|
||||
Run the following command to import functions from the `envVar.sh` script into your terminal. These functions allow you to act as either test network organization.
|
||||
First, get the functions to setup your environment as needed by running the following command (this assumes you are still in the `test-network` directory):
|
||||
|
||||
```
|
||||
. ./scripts/envVar.sh
|
||||
```
|
||||
|
||||
Run the following commands to install the `asset-transfer-basic-external.tar.gz` chaincode on org1. The `setGlobals` function simply sets the environment variables that allow you to act as org1 or org2.
|
||||
Install the `asset-transfer-basic-external.tar.gz` chaincode on org1:
|
||||
|
||||
```
|
||||
setGlobals 1
|
||||
peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz
|
||||
../bin/peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz
|
||||
```
|
||||
|
||||
Install the chaincode package on the org2 peer:
|
||||
setGlobals simply defines a bunch of environment variables suitable to act as one organization or another, org1 or org2.
|
||||
|
||||
Install it on org2:
|
||||
|
||||
```
|
||||
setGlobals 2
|
||||
peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz
|
||||
../bin/peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz
|
||||
```
|
||||
|
||||
Run the following command to query the package ID of the chaincode that you just installed:
|
||||
This will output the chaincode pakage identifier such as `basic_1.0:0262396ccaffaa2174bc09f750f742319c4f14d60b16334d2c8921b6842c090c` that you will need to use in the following commands.
|
||||
|
||||
For convenience it is best to store your package id value in an environment variable so that it can be referenced in later commands:
|
||||
|
||||
```
|
||||
export PKGID=basic_1.0:0262396ccaffaa2174bc09f750f742319c4f14d60b16334d2c8921b6842c090
|
||||
```
|
||||
|
||||
If needed, you can query the installed chaincode to get its package-id:
|
||||
|
||||
```
|
||||
setGlobals 1
|
||||
peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
|
||||
../bin/peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
|
||||
```
|
||||
|
||||
The command will return output similar to the following:
|
||||
Edit the `chaincode.env` file in the `fabric-samples/asset-transfer-basic/chaincode-external` directory as necessary to set the `CHAINCODE_ID` variable to the chaincode package-id obtained above.
|
||||
|
||||
```
|
||||
Installed chaincodes on peer:
|
||||
Package ID: basic_1.0:ecfc83f251b7c2d9ef376bc3fc20fc6b9744c0fc0a8923092af6542af94790c3, Label: basic_1.0
|
||||
```
|
||||
|
||||
Save the package ID that was returned by the command as an environment variable. The ID will not be the same for all users, so you need to set the variable using the ID from your command window:
|
||||
|
||||
```
|
||||
export CHAINCODE_ID=basic_1.0:ecfc83f251b7c2d9ef376bc3fc20fc6b9744c0fc0a8923092af6542af94790c3
|
||||
```
|
||||
|
||||
## Running the Asset-Transfer-Basic external service
|
||||
|
||||
We are going to run the smart contract as an external service by first building and then starting a docker container. Open a new terminal and navigate back to the `chaincode-external` directory:
|
||||
|
||||
```
|
||||
cd fabric-samples/asset-transfer-basic/chaincode-external
|
||||
```
|
||||
|
||||
In this directory, open the `chaincode.env` file to set the `CHAINCODE_ID` variable to the same package ID that was returned by the `peer lifecycle chaincode queryinstalled` command. The value should be the same as the environment variable that you set in the previous terminal.
|
||||
|
||||
After you edit the `chaincode.env` file, you can use the `Dockerfile` to build an image of the external Asset-Transfer-Basic chaincode:
|
||||
To run the service in a container, from a different terminal, build an Asset-Transfer-Basic docker image, using the supplied `Dockerfile`, using the following command in the `fabric-samples/asset-transfer-basic/chaincode-external` directory:
|
||||
|
||||
```
|
||||
docker build -t hyperledger/asset-transfer-basic .
|
||||
```
|
||||
|
||||
You can then run the image to start the Asset-Transfer-Basic service:
|
||||
Then, start the Asset-Transfer-Basic service:
|
||||
|
||||
```
|
||||
docker run -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode.env --network=fabric_test hyperledger/asset-transfer-basic
|
||||
docker run -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode.env --network=net_test hyperledger/asset-transfer-basic
|
||||
```
|
||||
|
||||
This will start and run the external chaincode service within the container.
|
||||
This will start the container and start the external chaincode service within it.
|
||||
|
||||
## Deploy the Asset-Transfer-Basic external chaincode definition to the channel
|
||||
## Finish deploying the Asset-Transfer-Basic external chaincode
|
||||
|
||||
Navigate back to the `test-network` directory to finish deploying the chaincode definition of the external smart contract to the channel. Make sure that your environment variables are still set.
|
||||
Finishing the deployment of the chaincode on the test network can be done from the terminal you started the network from with the following commands (make sure the package-id is set to the value you received above):
|
||||
|
||||
```
|
||||
setGlobals 2
|
||||
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name basic --version 1.0 --package-id $CHAINCODE_ID --sequence 1
|
||||
../bin/peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1
|
||||
|
||||
setGlobals 1
|
||||
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name basic --version 1.0 --package-id $CHAINCODE_ID --sequence 1
|
||||
../bin/peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1
|
||||
|
||||
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles "$PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1.0 --sequence 1
|
||||
../bin/peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles $PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1.0 --sequence 1
|
||||
```
|
||||
|
||||
The commands above approve the chaincode definition for the external chaincode and commits the definition to the channel. The resulting output should be similar to the following:
|
||||
This approves the chaincode definition for both orgs and commits it using org1. This should result in an output similar to:
|
||||
|
||||
```
|
||||
2020-08-05 15:41:44.982 PDT [chaincodeCmd] ClientWait -> INFO 001 txid [6bdbe040b99a45cc90a23ec21f02ea5da7be8b70590eb04ff3323ef77fdedfc7] committed with status (VALID) at localhost:7051
|
||||
2020-08-05 15:41:44.983 PDT [chaincodeCmd] ClientWait -> INFO 002 txid [6bdbe040b99a45cc90a23ec21f02ea5da7be8b70590eb04ff3323ef77fdedfc7] committed with status (VALID) at localhost:9051
|
||||
```
|
||||
|
||||
Now that we have started the chaincode service and deployed it to the channel, we can submit transactions as we would with a normal chaincode.
|
||||
Now that the chaincode is deployed to the channel, and started as an external service, it can be used as normal.
|
||||
|
||||
## Using the Asset-Transfer-Basic external chaincode
|
||||
|
||||
Open yet another terminal and navigate to the `fabric-samples/asset-transfer-basic/application-gateway-go` directory:
|
||||
From yet another terminal, go to `fabric-samples/asset-transfer-basic/application-javascript` and use the node application to test the chaincode you just installed with the following commands:
|
||||
|
||||
```
|
||||
cd fabric-samples/asset-transfer-basic/application-gateway-go
|
||||
rm -rf wallet # in case you ran this before
|
||||
npm install
|
||||
node app.js
|
||||
```
|
||||
|
||||
Run the following commands to use the node application in this directory to test the external smart contract:
|
||||
|
||||
```
|
||||
go run .
|
||||
```
|
||||
|
||||
If all goes well, the program should run exactly the same as described in the "Writing Your First Application" tutorial.
|
||||
|
||||
## Enabling TLS for chaincode and peer communication
|
||||
|
||||
**Note:** This section uses an example of self-signed certificate. You may use your organization hosted CA to issue the certificate and generate a key for production deployment.
|
||||
|
||||
In the sample so far, you connected both peers in `test-network` to the single instance of chaincode server. However, if you would like to enable TLS between the peer nodes and the chaincode server, each peer node needs to have its own CA certificate. Enabling TLS is made possible at runtime in the chaincode.
|
||||
|
||||
- As a first step generate a keypair that can be used. Run these commands from the `fabric-samples/asset-transfer-basic/chaincode-external` directory.
|
||||
|
||||
_Find instructions to install `openssl` in [openssl.org](https://www.openssl.org/)_
|
||||
|
||||
For `org1.example.com`
|
||||
|
||||
```
|
||||
openssl req -nodes -x509 -newkey rsa:4096 -keyout crypto/key1.pem -out crypto/cert1.pem -subj "/C=IN/ST=KA/L=Bangalore/O=example Inc/OU=Developer/CN=asset-transfer-basic.org1.example.com/emailAddress=dev@asset-transfer-basic.org1.example.com"
|
||||
```
|
||||
|
||||
For `org2.example.com`
|
||||
|
||||
```
|
||||
openssl req -nodes -x509 -newkey rsa:4096 -keyout crypto/key2.pem -out crypto/cert2.pem -subj "/C=IN/ST=KA/L=Bangalore/O=example Inc/OU=Developer/CN=asset-transfer-basic.org2.example.com/emailAddress=dev@asset-transfer-basic.org2.example.com"
|
||||
```
|
||||
|
||||
- Copy the CA file contents for both `org1.example.com` & `org2.example.com`
|
||||
|
||||
```
|
||||
cp ../../test-network/organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem crypto/rootcert1.pem
|
||||
cp ../../test-network/organizations/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem crypto/rootcert2.pem
|
||||
```
|
||||
|
||||
- Generate a client key and cert for auth purpose. You need a key and cert generated from the CA of each organization. Peer nodes act as clients to chaincode server.
|
||||
|
||||
- Change the `connection.json` with the below contents. The `root_cert` parameter is the root CA certificate which the chaincode server is run with. You may run the below commands to get the certificate file contents as strings and copy them when needed.
|
||||
|
||||
```
|
||||
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crypto/cert1.pem
|
||||
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crypto/cert2.pem
|
||||
```
|
||||
|
||||
Similarly, replace the `client_key` and the `client_cert` contents with the values from the previous step.
|
||||
|
||||
```
|
||||
{
|
||||
"address": "asset-transfer-basic.org1.example.com:9999",
|
||||
"dial_timeout": "10s",
|
||||
"tls_required": true,
|
||||
"client_auth_required": true,
|
||||
"client_key": "-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----",
|
||||
"client_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----",
|
||||
"root_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----"
|
||||
}
|
||||
```
|
||||
|
||||
- Follow the instructions in [Package](#packaging-and-installing-chaincode) and [Install](#installing-the-external-chaincode) steps for each organization. Remember that the chaincode server's address for the second organization is `asset-transfer-basic.org2.example.com:9999`.
|
||||
|
||||
- Copy the appropriate `CHAINCODE_ID` to both [chaincode1.env](./chaincode1.env) and [chaincode2.env](./chaincode2.env) files. Bring up the chaincode containers using the docker-compose command below
|
||||
|
||||
```
|
||||
docker-compose up -f docker-compose-chaincode.yaml up --build -d
|
||||
```
|
||||
|
||||
- Follow the instructions in [Finish Deployment](#finish-deploying-the-asset-transfer-basic-external-chaincode-) for each organization seperately.
|
||||
If all goes well, it should run exactly the same as described in the "Writing Your First Application" tutorial.
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/hyperledger/fabric-chaincode-go/v2/shim"
|
||||
"github.com/hyperledger/fabric-contract-api-go/v2/contractapi"
|
||||
"github.com/hyperledger/fabric-chaincode-go/shim"
|
||||
"github.com/hyperledger/fabric-contract-api-go/contractapi"
|
||||
)
|
||||
|
||||
type serverConfig struct {
|
||||
|
|
@ -120,7 +119,7 @@ func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface,
|
|||
return fmt.Errorf("the asset %s does not exist", id)
|
||||
}
|
||||
|
||||
// overwriting original asset with new asset
|
||||
// overwritting original asset with new asset
|
||||
asset := Asset{
|
||||
ID: id,
|
||||
Color: color,
|
||||
|
|
@ -137,7 +136,7 @@ func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface,
|
|||
return ctx.GetStub().PutState(id, assetJSON)
|
||||
}
|
||||
|
||||
// DeleteAsset deletes a given asset from the world state.
|
||||
// DeleteAsset deletes an given asset from the world state.
|
||||
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
|
||||
exists, err := s.AssetExists(ctx, id)
|
||||
if err != nil {
|
||||
|
|
@ -160,27 +159,20 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface,
|
|||
return assetJSON != nil, nil
|
||||
}
|
||||
|
||||
// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner.
|
||||
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) {
|
||||
// TransferAsset updates the owner field of asset with given id in world state.
|
||||
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error {
|
||||
asset, err := s.ReadAsset(ctx, id)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
|
||||
oldOwner := asset.Owner
|
||||
asset.Owner = newOwner
|
||||
|
||||
assetJSON, err := json.Marshal(asset)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
|
||||
err = ctx.GetStub().PutState(id, assetJSON)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return oldOwner, nil
|
||||
return ctx.GetStub().PutState(id, assetJSON)
|
||||
}
|
||||
|
||||
// GetAllAssets returns all assets found in world state
|
||||
|
|
@ -229,69 +221,15 @@ func main() {
|
|||
}
|
||||
|
||||
server := &shim.ChaincodeServer{
|
||||
CCID: config.CCID,
|
||||
Address: config.Address,
|
||||
CC: chaincode,
|
||||
TLSProps: getTLSProperties(),
|
||||
CCID: config.CCID,
|
||||
Address: config.Address,
|
||||
CC: chaincode,
|
||||
TLSProps: shim.TLSProperties{
|
||||
Disabled: true,
|
||||
},
|
||||
}
|
||||
|
||||
if err := server.Start(); err != nil {
|
||||
log.Panicf("error starting asset-transfer-basic chaincode: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func getTLSProperties() shim.TLSProperties {
|
||||
// Check if chaincode is TLS enabled
|
||||
tlsDisabledStr := getEnvOrDefault("CHAINCODE_TLS_DISABLED", "true")
|
||||
key := getEnvOrDefault("CHAINCODE_TLS_KEY", "")
|
||||
cert := getEnvOrDefault("CHAINCODE_TLS_CERT", "")
|
||||
clientCACert := getEnvOrDefault("CHAINCODE_CLIENT_CA_CERT", "")
|
||||
|
||||
// convert tlsDisabledStr to boolean
|
||||
tlsDisabled := getBoolOrDefault(tlsDisabledStr, false)
|
||||
var keyBytes, certBytes, clientCACertBytes []byte
|
||||
var err error
|
||||
|
||||
if !tlsDisabled {
|
||||
keyBytes, err = os.ReadFile(key)
|
||||
if err != nil {
|
||||
log.Panicf("error while reading the crypto file: %s", err)
|
||||
}
|
||||
certBytes, err = os.ReadFile(cert)
|
||||
if err != nil {
|
||||
log.Panicf("error while reading the crypto file: %s", err)
|
||||
}
|
||||
}
|
||||
// Did not request for the peer cert verification
|
||||
if clientCACert != "" {
|
||||
clientCACertBytes, err = os.ReadFile(clientCACert)
|
||||
if err != nil {
|
||||
log.Panicf("error while reading the crypto file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return shim.TLSProperties{
|
||||
Disabled: tlsDisabled,
|
||||
Key: keyBytes,
|
||||
Cert: certBytes,
|
||||
ClientCACerts: clientCACertBytes,
|
||||
}
|
||||
}
|
||||
|
||||
func getEnvOrDefault(env, defaultVal string) string {
|
||||
value, ok := os.LookupEnv(env)
|
||||
if !ok {
|
||||
value = defaultVal
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Note that the method returns default value if the string
|
||||
// cannot be parsed!
|
||||
func getBoolOrDefault(value string, defaultVal bool) bool {
|
||||
parsed, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,19 +6,3 @@ CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org1.example.com:9999
|
|||
# on install. The `peer lifecycle chaincode queryinstalled` command can be
|
||||
# used to get the ID after install if required
|
||||
CHAINCODE_ID=basic_1.0:0262396ccaffaa2174bc09f750f742319c4f14d60b16334d2c8921b6842c090c
|
||||
|
||||
# Optional parameters that will be used for TLS connection between peer node
|
||||
# and the chaincode.
|
||||
# TLS is disabled by default, uncomment the following line to enable TLS connection
|
||||
# CHAINCODE_TLS_DISABLED=false
|
||||
|
||||
# Following variables will be ignored if TLS is not enabled.
|
||||
# They need to be in PEM format
|
||||
# CHAINCODE_TLS_KEY=/path/to/private/key/file
|
||||
# CHAINCODE_TLS_CERT=/path/to/public/cert/file
|
||||
|
||||
# The following variable will be used by the chaincode server to verify the
|
||||
# connection from the peer node.
|
||||
# Note that when this is set a single chaincode server cannot be shared
|
||||
# across organizations unless their root CA is same.
|
||||
# CHAINCODE_CLIENT_CA_CERT=/path/to/peer/organization/root/ca/cert/file
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
# CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can
|
||||
# connect to the chaincode server
|
||||
CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org1.example.com:9999
|
||||
|
||||
# CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode
|
||||
# on install. The `peer lifecycle chaincode queryinstalled` command can be
|
||||
# used to get the ID after install if required
|
||||
CHAINCODE_ID=basic_1.0:6726c6b6d8ff66fcf5710b72c6ce512d24f118c51c3de510b3d43e51fa592a7d
|
||||
|
||||
# Optional parameters that will be used for TLS connection between peer node
|
||||
# and the chaincode.
|
||||
# TLS is disabled by default, uncomment the following line to enable TLS connection
|
||||
CHAINCODE_TLS_DISABLED=false
|
||||
|
||||
# Following variables will be ignored if TLS is not enabled.
|
||||
# They need to be in PEM format
|
||||
CHAINCODE_TLS_KEY=/crypto/key1.pem
|
||||
CHAINCODE_TLS_CERT=/crypto/cert1.pem
|
||||
|
||||
# The following variable will be used by the chaincode server to verify the
|
||||
# connection from the peer node.
|
||||
# Note that when this is set a single chaincode server cannot be shared
|
||||
# across organizations unless their root CA is same.
|
||||
CHAINCODE_CLIENT_CA_CERT=/crypto/rootcert1.pem
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can
|
||||
# connect to the chaincode server
|
||||
CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org2.example.com:9999
|
||||
|
||||
# CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode
|
||||
# on install. The `peer lifecycle chaincode queryinstalled` command can be
|
||||
# used to get the ID after install if required
|
||||
CHAINCODE_ID=basic_1.0:e8f9052385e3763ecf5635591155da05d8efbb6905ccbfc1c7229eb6bd28df1b
|
||||
|
||||
# Optional parameters that will be used for TLS connection between peer node
|
||||
# and the chaincode.
|
||||
# TLS is disabled by default, uncomment the following line to enable TLS connection
|
||||
CHAINCODE_TLS_DISABLED=false
|
||||
|
||||
# Following variables will be ignored if TLS is not enabled.
|
||||
# They need to be in PEM format
|
||||
CHAINCODE_TLS_KEY=/crypto/key2.pem
|
||||
CHAINCODE_TLS_CERT=/crypto/cert2.pem
|
||||
|
||||
# The following variable will be used by the chaincode server to verify the
|
||||
# connection from the peer node.
|
||||
# Note that when this is set a single chaincode server cannot be shared
|
||||
# across organizations unless their root CA is same.
|
||||
CHAINCODE_CLIENT_CA_CERT=/crypto/rootcert2.pem
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
networks:
|
||||
docker_test:
|
||||
external: true
|
||||
|
||||
services:
|
||||
asset-transfer-basic.org1.example.com:
|
||||
build: .
|
||||
container_name: asset-transfer-basic.org1.example.com
|
||||
hostname: asset-transfer-basic.org1.example.com
|
||||
volumes:
|
||||
- ./crypto:/crypto
|
||||
env_file:
|
||||
- chaincode1.env
|
||||
networks:
|
||||
docker_test:
|
||||
expose:
|
||||
- 9999
|
||||
|
||||
asset-transfer-basic.org2.example.com:
|
||||
build: .
|
||||
container_name: asset-transfer-basic.org2.example.com
|
||||
hostname: asset-transfer-basic.org2.example.com
|
||||
volumes:
|
||||
- ./crypto:/crypto
|
||||
env_file:
|
||||
- chaincode2.env
|
||||
networks:
|
||||
docker_test:
|
||||
expose:
|
||||
- 9999
|
||||
|
|
@ -1,28 +1,8 @@
|
|||
module github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external
|
||||
|
||||
go 1.23.0
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0
|
||||
github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
google.golang.org/protobuf v1.36.4 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212
|
||||
github.com/hyperledger/fabric-contract-api-go v1.1.0
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,81 +1,146 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DATA-DOG/go-txdb v0.1.3/go.mod h1:DhAhxMXZpUJVGnT+p9IbzJoRKvlArO2pkHjnGX7o0n0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c=
|
||||
github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk=
|
||||
github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4=
|
||||
github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs=
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc=
|
||||
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
|
||||
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
|
||||
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
|
||||
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
|
||||
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
|
||||
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212 h1:1i4lnpV8BDgKOLi1hgElfBqdHXjXieSuj8629mwBZ8o=
|
||||
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc=
|
||||
github.com/hyperledger/fabric-contract-api-go v1.1.0 h1:K9uucl/6eX3NF0/b+CGIiO1IPm1VYQxBkpnVGJur2S4=
|
||||
github.com/hyperledger/fabric-contract-api-go v1.1.0/go.mod h1:nHWt0B45fK53owcFpLtAe8DH0Q5P068mnzkNXMPSL7E=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e h1:9PS5iezHk/j7XriSlNuSQILyCOfcZ9wZ3/PiucmSE8E=
|
||||
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ=
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package main
|
|||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hyperledger/fabric-contract-api-go/v2/contractapi"
|
||||
"github.com/hyperledger/fabric-contract-api-go/contractapi"
|
||||
"github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ package mocks
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hyperledger/fabric-chaincode-go/v2/shim"
|
||||
"github.com/hyperledger/fabric-protos-go-apiv2/peer"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/hyperledger/fabric-chaincode-go/shim"
|
||||
"github.com/hyperledger/fabric-protos-go/peer"
|
||||
)
|
||||
|
||||
type ChaincodeStub struct {
|
||||
|
|
@ -388,19 +388,19 @@ type ChaincodeStub struct {
|
|||
getTxIDReturnsOnCall map[int]struct {
|
||||
result1 string
|
||||
}
|
||||
GetTxTimestampStub func() (*timestamppb.Timestamp, error)
|
||||
GetTxTimestampStub func() (*timestamp.Timestamp, error)
|
||||
getTxTimestampMutex sync.RWMutex
|
||||
getTxTimestampArgsForCall []struct {
|
||||
}
|
||||
getTxTimestampReturns struct {
|
||||
result1 *timestamppb.Timestamp
|
||||
result1 *timestamp.Timestamp
|
||||
result2 error
|
||||
}
|
||||
getTxTimestampReturnsOnCall map[int]struct {
|
||||
result1 *timestamppb.Timestamp
|
||||
result1 *timestamp.Timestamp
|
||||
result2 error
|
||||
}
|
||||
InvokeChaincodeStub func(string, [][]byte, string) *peer.Response
|
||||
InvokeChaincodeStub func(string, [][]byte, string) peer.Response
|
||||
invokeChaincodeMutex sync.RWMutex
|
||||
invokeChaincodeArgsForCall []struct {
|
||||
arg1 string
|
||||
|
|
@ -408,22 +408,10 @@ type ChaincodeStub struct {
|
|||
arg3 string
|
||||
}
|
||||
invokeChaincodeReturns struct {
|
||||
result1 *peer.Response
|
||||
result1 peer.Response
|
||||
}
|
||||
invokeChaincodeReturnsOnCall map[int]struct {
|
||||
result1 *peer.Response
|
||||
}
|
||||
PurgePrivateDataStub func(string, string) error
|
||||
purgePrivateDataMutex sync.RWMutex
|
||||
purgePrivateDataArgsForCall []struct {
|
||||
arg1 string
|
||||
arg2 string
|
||||
}
|
||||
purgePrivateDataReturns struct {
|
||||
result1 error
|
||||
}
|
||||
purgePrivateDataReturnsOnCall map[int]struct {
|
||||
result1 error
|
||||
result1 peer.Response
|
||||
}
|
||||
PutPrivateDataStub func(string, string, []byte) error
|
||||
putPrivateDataMutex sync.RWMutex
|
||||
|
|
@ -518,16 +506,15 @@ func (fake *ChaincodeStub) CreateCompositeKey(arg1 string, arg2 []string) (strin
|
|||
arg1 string
|
||||
arg2 []string
|
||||
}{arg1, arg2Copy})
|
||||
stub := fake.CreateCompositeKeyStub
|
||||
fakeReturns := fake.createCompositeKeyReturns
|
||||
fake.recordInvocation("CreateCompositeKey", []interface{}{arg1, arg2Copy})
|
||||
fake.createCompositeKeyMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.CreateCompositeKeyStub != nil {
|
||||
return fake.CreateCompositeKeyStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.createCompositeKeyReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -583,16 +570,15 @@ func (fake *ChaincodeStub) DelPrivateData(arg1 string, arg2 string) error {
|
|||
arg1 string
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.DelPrivateDataStub
|
||||
fakeReturns := fake.delPrivateDataReturns
|
||||
fake.recordInvocation("DelPrivateData", []interface{}{arg1, arg2})
|
||||
fake.delPrivateDataMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.DelPrivateDataStub != nil {
|
||||
return fake.DelPrivateDataStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.delPrivateDataReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -644,16 +630,15 @@ func (fake *ChaincodeStub) DelState(arg1 string) error {
|
|||
fake.delStateArgsForCall = append(fake.delStateArgsForCall, struct {
|
||||
arg1 string
|
||||
}{arg1})
|
||||
stub := fake.DelStateStub
|
||||
fakeReturns := fake.delStateReturns
|
||||
fake.recordInvocation("DelState", []interface{}{arg1})
|
||||
fake.delStateMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
if fake.DelStateStub != nil {
|
||||
return fake.DelStateStub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.delStateReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -704,16 +689,15 @@ func (fake *ChaincodeStub) GetArgs() [][]byte {
|
|||
ret, specificReturn := fake.getArgsReturnsOnCall[len(fake.getArgsArgsForCall)]
|
||||
fake.getArgsArgsForCall = append(fake.getArgsArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetArgsStub
|
||||
fakeReturns := fake.getArgsReturns
|
||||
fake.recordInvocation("GetArgs", []interface{}{})
|
||||
fake.getArgsMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetArgsStub != nil {
|
||||
return fake.GetArgsStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.getArgsReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -757,16 +741,15 @@ func (fake *ChaincodeStub) GetArgsSlice() ([]byte, error) {
|
|||
ret, specificReturn := fake.getArgsSliceReturnsOnCall[len(fake.getArgsSliceArgsForCall)]
|
||||
fake.getArgsSliceArgsForCall = append(fake.getArgsSliceArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetArgsSliceStub
|
||||
fakeReturns := fake.getArgsSliceReturns
|
||||
fake.recordInvocation("GetArgsSlice", []interface{}{})
|
||||
fake.getArgsSliceMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetArgsSliceStub != nil {
|
||||
return fake.GetArgsSliceStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getArgsSliceReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -813,16 +796,15 @@ func (fake *ChaincodeStub) GetBinding() ([]byte, error) {
|
|||
ret, specificReturn := fake.getBindingReturnsOnCall[len(fake.getBindingArgsForCall)]
|
||||
fake.getBindingArgsForCall = append(fake.getBindingArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetBindingStub
|
||||
fakeReturns := fake.getBindingReturns
|
||||
fake.recordInvocation("GetBinding", []interface{}{})
|
||||
fake.getBindingMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetBindingStub != nil {
|
||||
return fake.GetBindingStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getBindingReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -869,16 +851,15 @@ func (fake *ChaincodeStub) GetChannelID() string {
|
|||
ret, specificReturn := fake.getChannelIDReturnsOnCall[len(fake.getChannelIDArgsForCall)]
|
||||
fake.getChannelIDArgsForCall = append(fake.getChannelIDArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetChannelIDStub
|
||||
fakeReturns := fake.getChannelIDReturns
|
||||
fake.recordInvocation("GetChannelID", []interface{}{})
|
||||
fake.getChannelIDMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetChannelIDStub != nil {
|
||||
return fake.GetChannelIDStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.getChannelIDReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -922,16 +903,15 @@ func (fake *ChaincodeStub) GetCreator() ([]byte, error) {
|
|||
ret, specificReturn := fake.getCreatorReturnsOnCall[len(fake.getCreatorArgsForCall)]
|
||||
fake.getCreatorArgsForCall = append(fake.getCreatorArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetCreatorStub
|
||||
fakeReturns := fake.getCreatorReturns
|
||||
fake.recordInvocation("GetCreator", []interface{}{})
|
||||
fake.getCreatorMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetCreatorStub != nil {
|
||||
return fake.GetCreatorStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getCreatorReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -978,16 +958,15 @@ func (fake *ChaincodeStub) GetDecorations() map[string][]byte {
|
|||
ret, specificReturn := fake.getDecorationsReturnsOnCall[len(fake.getDecorationsArgsForCall)]
|
||||
fake.getDecorationsArgsForCall = append(fake.getDecorationsArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetDecorationsStub
|
||||
fakeReturns := fake.getDecorationsReturns
|
||||
fake.recordInvocation("GetDecorations", []interface{}{})
|
||||
fake.getDecorationsMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetDecorationsStub != nil {
|
||||
return fake.GetDecorationsStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.getDecorationsReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -1031,16 +1010,15 @@ func (fake *ChaincodeStub) GetFunctionAndParameters() (string, []string) {
|
|||
ret, specificReturn := fake.getFunctionAndParametersReturnsOnCall[len(fake.getFunctionAndParametersArgsForCall)]
|
||||
fake.getFunctionAndParametersArgsForCall = append(fake.getFunctionAndParametersArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetFunctionAndParametersStub
|
||||
fakeReturns := fake.getFunctionAndParametersReturns
|
||||
fake.recordInvocation("GetFunctionAndParameters", []interface{}{})
|
||||
fake.getFunctionAndParametersMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetFunctionAndParametersStub != nil {
|
||||
return fake.GetFunctionAndParametersStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getFunctionAndParametersReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1088,16 +1066,15 @@ func (fake *ChaincodeStub) GetHistoryForKey(arg1 string) (shim.HistoryQueryItera
|
|||
fake.getHistoryForKeyArgsForCall = append(fake.getHistoryForKeyArgsForCall, struct {
|
||||
arg1 string
|
||||
}{arg1})
|
||||
stub := fake.GetHistoryForKeyStub
|
||||
fakeReturns := fake.getHistoryForKeyReturns
|
||||
fake.recordInvocation("GetHistoryForKey", []interface{}{arg1})
|
||||
fake.getHistoryForKeyMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
if fake.GetHistoryForKeyStub != nil {
|
||||
return fake.GetHistoryForKeyStub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getHistoryForKeyReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1153,16 +1130,15 @@ func (fake *ChaincodeStub) GetPrivateData(arg1 string, arg2 string) ([]byte, err
|
|||
arg1 string
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.GetPrivateDataStub
|
||||
fakeReturns := fake.getPrivateDataReturns
|
||||
fake.recordInvocation("GetPrivateData", []interface{}{arg1, arg2})
|
||||
fake.getPrivateDataMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.GetPrivateDataStub != nil {
|
||||
return fake.GetPrivateDataStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getPrivateDataReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1224,16 +1200,15 @@ func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKey(arg1 string, arg2
|
|||
arg2 string
|
||||
arg3 []string
|
||||
}{arg1, arg2, arg3Copy})
|
||||
stub := fake.GetPrivateDataByPartialCompositeKeyStub
|
||||
fakeReturns := fake.getPrivateDataByPartialCompositeKeyReturns
|
||||
fake.recordInvocation("GetPrivateDataByPartialCompositeKey", []interface{}{arg1, arg2, arg3Copy})
|
||||
fake.getPrivateDataByPartialCompositeKeyMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3)
|
||||
if fake.GetPrivateDataByPartialCompositeKeyStub != nil {
|
||||
return fake.GetPrivateDataByPartialCompositeKeyStub(arg1, arg2, arg3)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getPrivateDataByPartialCompositeKeyReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1290,16 +1265,15 @@ func (fake *ChaincodeStub) GetPrivateDataByRange(arg1 string, arg2 string, arg3
|
|||
arg2 string
|
||||
arg3 string
|
||||
}{arg1, arg2, arg3})
|
||||
stub := fake.GetPrivateDataByRangeStub
|
||||
fakeReturns := fake.getPrivateDataByRangeReturns
|
||||
fake.recordInvocation("GetPrivateDataByRange", []interface{}{arg1, arg2, arg3})
|
||||
fake.getPrivateDataByRangeMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3)
|
||||
if fake.GetPrivateDataByRangeStub != nil {
|
||||
return fake.GetPrivateDataByRangeStub(arg1, arg2, arg3)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getPrivateDataByRangeReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1355,16 +1329,15 @@ func (fake *ChaincodeStub) GetPrivateDataHash(arg1 string, arg2 string) ([]byte,
|
|||
arg1 string
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.GetPrivateDataHashStub
|
||||
fakeReturns := fake.getPrivateDataHashReturns
|
||||
fake.recordInvocation("GetPrivateDataHash", []interface{}{arg1, arg2})
|
||||
fake.getPrivateDataHashMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.GetPrivateDataHashStub != nil {
|
||||
return fake.GetPrivateDataHashStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getPrivateDataHashReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1420,16 +1393,15 @@ func (fake *ChaincodeStub) GetPrivateDataQueryResult(arg1 string, arg2 string) (
|
|||
arg1 string
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.GetPrivateDataQueryResultStub
|
||||
fakeReturns := fake.getPrivateDataQueryResultReturns
|
||||
fake.recordInvocation("GetPrivateDataQueryResult", []interface{}{arg1, arg2})
|
||||
fake.getPrivateDataQueryResultMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.GetPrivateDataQueryResultStub != nil {
|
||||
return fake.GetPrivateDataQueryResultStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getPrivateDataQueryResultReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1485,16 +1457,15 @@ func (fake *ChaincodeStub) GetPrivateDataValidationParameter(arg1 string, arg2 s
|
|||
arg1 string
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.GetPrivateDataValidationParameterStub
|
||||
fakeReturns := fake.getPrivateDataValidationParameterReturns
|
||||
fake.recordInvocation("GetPrivateDataValidationParameter", []interface{}{arg1, arg2})
|
||||
fake.getPrivateDataValidationParameterMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.GetPrivateDataValidationParameterStub != nil {
|
||||
return fake.GetPrivateDataValidationParameterStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getPrivateDataValidationParameterReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1549,16 +1520,15 @@ func (fake *ChaincodeStub) GetQueryResult(arg1 string) (shim.StateQueryIteratorI
|
|||
fake.getQueryResultArgsForCall = append(fake.getQueryResultArgsForCall, struct {
|
||||
arg1 string
|
||||
}{arg1})
|
||||
stub := fake.GetQueryResultStub
|
||||
fakeReturns := fake.getQueryResultReturns
|
||||
fake.recordInvocation("GetQueryResult", []interface{}{arg1})
|
||||
fake.getQueryResultMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
if fake.GetQueryResultStub != nil {
|
||||
return fake.GetQueryResultStub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getQueryResultReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1615,16 +1585,15 @@ func (fake *ChaincodeStub) GetQueryResultWithPagination(arg1 string, arg2 int32,
|
|||
arg2 int32
|
||||
arg3 string
|
||||
}{arg1, arg2, arg3})
|
||||
stub := fake.GetQueryResultWithPaginationStub
|
||||
fakeReturns := fake.getQueryResultWithPaginationReturns
|
||||
fake.recordInvocation("GetQueryResultWithPagination", []interface{}{arg1, arg2, arg3})
|
||||
fake.getQueryResultWithPaginationMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3)
|
||||
if fake.GetQueryResultWithPaginationStub != nil {
|
||||
return fake.GetQueryResultWithPaginationStub(arg1, arg2, arg3)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2, ret.result3
|
||||
}
|
||||
fakeReturns := fake.getQueryResultWithPaginationReturns
|
||||
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
|
||||
}
|
||||
|
||||
|
|
@ -1681,16 +1650,15 @@ func (fake *ChaincodeStub) GetSignedProposal() (*peer.SignedProposal, error) {
|
|||
ret, specificReturn := fake.getSignedProposalReturnsOnCall[len(fake.getSignedProposalArgsForCall)]
|
||||
fake.getSignedProposalArgsForCall = append(fake.getSignedProposalArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetSignedProposalStub
|
||||
fakeReturns := fake.getSignedProposalReturns
|
||||
fake.recordInvocation("GetSignedProposal", []interface{}{})
|
||||
fake.getSignedProposalMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetSignedProposalStub != nil {
|
||||
return fake.GetSignedProposalStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getSignedProposalReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1738,16 +1706,15 @@ func (fake *ChaincodeStub) GetState(arg1 string) ([]byte, error) {
|
|||
fake.getStateArgsForCall = append(fake.getStateArgsForCall, struct {
|
||||
arg1 string
|
||||
}{arg1})
|
||||
stub := fake.GetStateStub
|
||||
fakeReturns := fake.getStateReturns
|
||||
fake.recordInvocation("GetState", []interface{}{arg1})
|
||||
fake.getStateMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
if fake.GetStateStub != nil {
|
||||
return fake.GetStateStub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getStateReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1808,16 +1775,15 @@ func (fake *ChaincodeStub) GetStateByPartialCompositeKey(arg1 string, arg2 []str
|
|||
arg1 string
|
||||
arg2 []string
|
||||
}{arg1, arg2Copy})
|
||||
stub := fake.GetStateByPartialCompositeKeyStub
|
||||
fakeReturns := fake.getStateByPartialCompositeKeyReturns
|
||||
fake.recordInvocation("GetStateByPartialCompositeKey", []interface{}{arg1, arg2Copy})
|
||||
fake.getStateByPartialCompositeKeyMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.GetStateByPartialCompositeKeyStub != nil {
|
||||
return fake.GetStateByPartialCompositeKeyStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getStateByPartialCompositeKeyReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -1880,16 +1846,15 @@ func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPagination(arg1 stri
|
|||
arg3 int32
|
||||
arg4 string
|
||||
}{arg1, arg2Copy, arg3, arg4})
|
||||
stub := fake.GetStateByPartialCompositeKeyWithPaginationStub
|
||||
fakeReturns := fake.getStateByPartialCompositeKeyWithPaginationReturns
|
||||
fake.recordInvocation("GetStateByPartialCompositeKeyWithPagination", []interface{}{arg1, arg2Copy, arg3, arg4})
|
||||
fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3, arg4)
|
||||
if fake.GetStateByPartialCompositeKeyWithPaginationStub != nil {
|
||||
return fake.GetStateByPartialCompositeKeyWithPaginationStub(arg1, arg2, arg3, arg4)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2, ret.result3
|
||||
}
|
||||
fakeReturns := fake.getStateByPartialCompositeKeyWithPaginationReturns
|
||||
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
|
||||
}
|
||||
|
||||
|
|
@ -1948,16 +1913,15 @@ func (fake *ChaincodeStub) GetStateByRange(arg1 string, arg2 string) (shim.State
|
|||
arg1 string
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.GetStateByRangeStub
|
||||
fakeReturns := fake.getStateByRangeReturns
|
||||
fake.recordInvocation("GetStateByRange", []interface{}{arg1, arg2})
|
||||
fake.getStateByRangeMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.GetStateByRangeStub != nil {
|
||||
return fake.GetStateByRangeStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getStateByRangeReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -2015,16 +1979,15 @@ func (fake *ChaincodeStub) GetStateByRangeWithPagination(arg1 string, arg2 strin
|
|||
arg3 int32
|
||||
arg4 string
|
||||
}{arg1, arg2, arg3, arg4})
|
||||
stub := fake.GetStateByRangeWithPaginationStub
|
||||
fakeReturns := fake.getStateByRangeWithPaginationReturns
|
||||
fake.recordInvocation("GetStateByRangeWithPagination", []interface{}{arg1, arg2, arg3, arg4})
|
||||
fake.getStateByRangeWithPaginationMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3, arg4)
|
||||
if fake.GetStateByRangeWithPaginationStub != nil {
|
||||
return fake.GetStateByRangeWithPaginationStub(arg1, arg2, arg3, arg4)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2, ret.result3
|
||||
}
|
||||
fakeReturns := fake.getStateByRangeWithPaginationReturns
|
||||
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
|
||||
}
|
||||
|
||||
|
|
@ -2082,16 +2045,15 @@ func (fake *ChaincodeStub) GetStateValidationParameter(arg1 string) ([]byte, err
|
|||
fake.getStateValidationParameterArgsForCall = append(fake.getStateValidationParameterArgsForCall, struct {
|
||||
arg1 string
|
||||
}{arg1})
|
||||
stub := fake.GetStateValidationParameterStub
|
||||
fakeReturns := fake.getStateValidationParameterReturns
|
||||
fake.recordInvocation("GetStateValidationParameter", []interface{}{arg1})
|
||||
fake.getStateValidationParameterMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
if fake.GetStateValidationParameterStub != nil {
|
||||
return fake.GetStateValidationParameterStub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getStateValidationParameterReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -2145,16 +2107,15 @@ func (fake *ChaincodeStub) GetStringArgs() []string {
|
|||
ret, specificReturn := fake.getStringArgsReturnsOnCall[len(fake.getStringArgsArgsForCall)]
|
||||
fake.getStringArgsArgsForCall = append(fake.getStringArgsArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetStringArgsStub
|
||||
fakeReturns := fake.getStringArgsReturns
|
||||
fake.recordInvocation("GetStringArgs", []interface{}{})
|
||||
fake.getStringArgsMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetStringArgsStub != nil {
|
||||
return fake.GetStringArgsStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.getStringArgsReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2198,16 +2159,15 @@ func (fake *ChaincodeStub) GetTransient() (map[string][]byte, error) {
|
|||
ret, specificReturn := fake.getTransientReturnsOnCall[len(fake.getTransientArgsForCall)]
|
||||
fake.getTransientArgsForCall = append(fake.getTransientArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetTransientStub
|
||||
fakeReturns := fake.getTransientReturns
|
||||
fake.recordInvocation("GetTransient", []interface{}{})
|
||||
fake.getTransientMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetTransientStub != nil {
|
||||
return fake.GetTransientStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getTransientReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -2254,16 +2214,15 @@ func (fake *ChaincodeStub) GetTxID() string {
|
|||
ret, specificReturn := fake.getTxIDReturnsOnCall[len(fake.getTxIDArgsForCall)]
|
||||
fake.getTxIDArgsForCall = append(fake.getTxIDArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetTxIDStub
|
||||
fakeReturns := fake.getTxIDReturns
|
||||
fake.recordInvocation("GetTxID", []interface{}{})
|
||||
fake.getTxIDMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetTxIDStub != nil {
|
||||
return fake.GetTxIDStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.getTxIDReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2302,21 +2261,20 @@ func (fake *ChaincodeStub) GetTxIDReturnsOnCall(i int, result1 string) {
|
|||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) GetTxTimestamp() (*timestamppb.Timestamp, error) {
|
||||
func (fake *ChaincodeStub) GetTxTimestamp() (*timestamp.Timestamp, error) {
|
||||
fake.getTxTimestampMutex.Lock()
|
||||
ret, specificReturn := fake.getTxTimestampReturnsOnCall[len(fake.getTxTimestampArgsForCall)]
|
||||
fake.getTxTimestampArgsForCall = append(fake.getTxTimestampArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.GetTxTimestampStub
|
||||
fakeReturns := fake.getTxTimestampReturns
|
||||
fake.recordInvocation("GetTxTimestamp", []interface{}{})
|
||||
fake.getTxTimestampMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.GetTxTimestampStub != nil {
|
||||
return fake.GetTxTimestampStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.getTxTimestampReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
@ -2326,39 +2284,39 @@ func (fake *ChaincodeStub) GetTxTimestampCallCount() int {
|
|||
return len(fake.getTxTimestampArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) GetTxTimestampCalls(stub func() (*timestamppb.Timestamp, error)) {
|
||||
func (fake *ChaincodeStub) GetTxTimestampCalls(stub func() (*timestamp.Timestamp, error)) {
|
||||
fake.getTxTimestampMutex.Lock()
|
||||
defer fake.getTxTimestampMutex.Unlock()
|
||||
fake.GetTxTimestampStub = stub
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) GetTxTimestampReturns(result1 *timestamppb.Timestamp, result2 error) {
|
||||
func (fake *ChaincodeStub) GetTxTimestampReturns(result1 *timestamp.Timestamp, result2 error) {
|
||||
fake.getTxTimestampMutex.Lock()
|
||||
defer fake.getTxTimestampMutex.Unlock()
|
||||
fake.GetTxTimestampStub = nil
|
||||
fake.getTxTimestampReturns = struct {
|
||||
result1 *timestamppb.Timestamp
|
||||
result1 *timestamp.Timestamp
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) GetTxTimestampReturnsOnCall(i int, result1 *timestamppb.Timestamp, result2 error) {
|
||||
func (fake *ChaincodeStub) GetTxTimestampReturnsOnCall(i int, result1 *timestamp.Timestamp, result2 error) {
|
||||
fake.getTxTimestampMutex.Lock()
|
||||
defer fake.getTxTimestampMutex.Unlock()
|
||||
fake.GetTxTimestampStub = nil
|
||||
if fake.getTxTimestampReturnsOnCall == nil {
|
||||
fake.getTxTimestampReturnsOnCall = make(map[int]struct {
|
||||
result1 *timestamppb.Timestamp
|
||||
result1 *timestamp.Timestamp
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.getTxTimestampReturnsOnCall[i] = struct {
|
||||
result1 *timestamppb.Timestamp
|
||||
result1 *timestamp.Timestamp
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) InvokeChaincode(arg1 string, arg2 [][]byte, arg3 string) *peer.Response {
|
||||
func (fake *ChaincodeStub) InvokeChaincode(arg1 string, arg2 [][]byte, arg3 string) peer.Response {
|
||||
var arg2Copy [][]byte
|
||||
if arg2 != nil {
|
||||
arg2Copy = make([][]byte, len(arg2))
|
||||
|
|
@ -2371,16 +2329,15 @@ func (fake *ChaincodeStub) InvokeChaincode(arg1 string, arg2 [][]byte, arg3 stri
|
|||
arg2 [][]byte
|
||||
arg3 string
|
||||
}{arg1, arg2Copy, arg3})
|
||||
stub := fake.InvokeChaincodeStub
|
||||
fakeReturns := fake.invokeChaincodeReturns
|
||||
fake.recordInvocation("InvokeChaincode", []interface{}{arg1, arg2Copy, arg3})
|
||||
fake.invokeChaincodeMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3)
|
||||
if fake.InvokeChaincodeStub != nil {
|
||||
return fake.InvokeChaincodeStub(arg1, arg2, arg3)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.invokeChaincodeReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2390,7 +2347,7 @@ func (fake *ChaincodeStub) InvokeChaincodeCallCount() int {
|
|||
return len(fake.invokeChaincodeArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) InvokeChaincodeCalls(stub func(string, [][]byte, string) *peer.Response) {
|
||||
func (fake *ChaincodeStub) InvokeChaincodeCalls(stub func(string, [][]byte, string) peer.Response) {
|
||||
fake.invokeChaincodeMutex.Lock()
|
||||
defer fake.invokeChaincodeMutex.Unlock()
|
||||
fake.InvokeChaincodeStub = stub
|
||||
|
|
@ -2403,88 +2360,26 @@ func (fake *ChaincodeStub) InvokeChaincodeArgsForCall(i int) (string, [][]byte,
|
|||
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) InvokeChaincodeReturns(result1 *peer.Response) {
|
||||
func (fake *ChaincodeStub) InvokeChaincodeReturns(result1 peer.Response) {
|
||||
fake.invokeChaincodeMutex.Lock()
|
||||
defer fake.invokeChaincodeMutex.Unlock()
|
||||
fake.InvokeChaincodeStub = nil
|
||||
fake.invokeChaincodeReturns = struct {
|
||||
result1 *peer.Response
|
||||
result1 peer.Response
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) InvokeChaincodeReturnsOnCall(i int, result1 *peer.Response) {
|
||||
func (fake *ChaincodeStub) InvokeChaincodeReturnsOnCall(i int, result1 peer.Response) {
|
||||
fake.invokeChaincodeMutex.Lock()
|
||||
defer fake.invokeChaincodeMutex.Unlock()
|
||||
fake.InvokeChaincodeStub = nil
|
||||
if fake.invokeChaincodeReturnsOnCall == nil {
|
||||
fake.invokeChaincodeReturnsOnCall = make(map[int]struct {
|
||||
result1 *peer.Response
|
||||
result1 peer.Response
|
||||
})
|
||||
}
|
||||
fake.invokeChaincodeReturnsOnCall[i] = struct {
|
||||
result1 *peer.Response
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) PurgePrivateData(arg1 string, arg2 string) error {
|
||||
fake.purgePrivateDataMutex.Lock()
|
||||
ret, specificReturn := fake.purgePrivateDataReturnsOnCall[len(fake.purgePrivateDataArgsForCall)]
|
||||
fake.purgePrivateDataArgsForCall = append(fake.purgePrivateDataArgsForCall, struct {
|
||||
arg1 string
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.PurgePrivateDataStub
|
||||
fakeReturns := fake.purgePrivateDataReturns
|
||||
fake.recordInvocation("PurgePrivateData", []interface{}{arg1, arg2})
|
||||
fake.purgePrivateDataMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) PurgePrivateDataCallCount() int {
|
||||
fake.purgePrivateDataMutex.RLock()
|
||||
defer fake.purgePrivateDataMutex.RUnlock()
|
||||
return len(fake.purgePrivateDataArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) PurgePrivateDataCalls(stub func(string, string) error) {
|
||||
fake.purgePrivateDataMutex.Lock()
|
||||
defer fake.purgePrivateDataMutex.Unlock()
|
||||
fake.PurgePrivateDataStub = stub
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) PurgePrivateDataArgsForCall(i int) (string, string) {
|
||||
fake.purgePrivateDataMutex.RLock()
|
||||
defer fake.purgePrivateDataMutex.RUnlock()
|
||||
argsForCall := fake.purgePrivateDataArgsForCall[i]
|
||||
return argsForCall.arg1, argsForCall.arg2
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) PurgePrivateDataReturns(result1 error) {
|
||||
fake.purgePrivateDataMutex.Lock()
|
||||
defer fake.purgePrivateDataMutex.Unlock()
|
||||
fake.PurgePrivateDataStub = nil
|
||||
fake.purgePrivateDataReturns = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *ChaincodeStub) PurgePrivateDataReturnsOnCall(i int, result1 error) {
|
||||
fake.purgePrivateDataMutex.Lock()
|
||||
defer fake.purgePrivateDataMutex.Unlock()
|
||||
fake.PurgePrivateDataStub = nil
|
||||
if fake.purgePrivateDataReturnsOnCall == nil {
|
||||
fake.purgePrivateDataReturnsOnCall = make(map[int]struct {
|
||||
result1 error
|
||||
})
|
||||
}
|
||||
fake.purgePrivateDataReturnsOnCall[i] = struct {
|
||||
result1 error
|
||||
result1 peer.Response
|
||||
}{result1}
|
||||
}
|
||||
|
||||
|
|
@ -2501,16 +2396,15 @@ func (fake *ChaincodeStub) PutPrivateData(arg1 string, arg2 string, arg3 []byte)
|
|||
arg2 string
|
||||
arg3 []byte
|
||||
}{arg1, arg2, arg3Copy})
|
||||
stub := fake.PutPrivateDataStub
|
||||
fakeReturns := fake.putPrivateDataReturns
|
||||
fake.recordInvocation("PutPrivateData", []interface{}{arg1, arg2, arg3Copy})
|
||||
fake.putPrivateDataMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3)
|
||||
if fake.PutPrivateDataStub != nil {
|
||||
return fake.PutPrivateDataStub(arg1, arg2, arg3)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.putPrivateDataReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2568,16 +2462,15 @@ func (fake *ChaincodeStub) PutState(arg1 string, arg2 []byte) error {
|
|||
arg1 string
|
||||
arg2 []byte
|
||||
}{arg1, arg2Copy})
|
||||
stub := fake.PutStateStub
|
||||
fakeReturns := fake.putStateReturns
|
||||
fake.recordInvocation("PutState", []interface{}{arg1, arg2Copy})
|
||||
fake.putStateMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.PutStateStub != nil {
|
||||
return fake.PutStateStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.putStateReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2635,16 +2528,15 @@ func (fake *ChaincodeStub) SetEvent(arg1 string, arg2 []byte) error {
|
|||
arg1 string
|
||||
arg2 []byte
|
||||
}{arg1, arg2Copy})
|
||||
stub := fake.SetEventStub
|
||||
fakeReturns := fake.setEventReturns
|
||||
fake.recordInvocation("SetEvent", []interface{}{arg1, arg2Copy})
|
||||
fake.setEventMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.SetEventStub != nil {
|
||||
return fake.SetEventStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.setEventReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2703,16 +2595,15 @@ func (fake *ChaincodeStub) SetPrivateDataValidationParameter(arg1 string, arg2 s
|
|||
arg2 string
|
||||
arg3 []byte
|
||||
}{arg1, arg2, arg3Copy})
|
||||
stub := fake.SetPrivateDataValidationParameterStub
|
||||
fakeReturns := fake.setPrivateDataValidationParameterReturns
|
||||
fake.recordInvocation("SetPrivateDataValidationParameter", []interface{}{arg1, arg2, arg3Copy})
|
||||
fake.setPrivateDataValidationParameterMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3)
|
||||
if fake.SetPrivateDataValidationParameterStub != nil {
|
||||
return fake.SetPrivateDataValidationParameterStub(arg1, arg2, arg3)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.setPrivateDataValidationParameterReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2770,16 +2661,15 @@ func (fake *ChaincodeStub) SetStateValidationParameter(arg1 string, arg2 []byte)
|
|||
arg1 string
|
||||
arg2 []byte
|
||||
}{arg1, arg2Copy})
|
||||
stub := fake.SetStateValidationParameterStub
|
||||
fakeReturns := fake.setStateValidationParameterReturns
|
||||
fake.recordInvocation("SetStateValidationParameter", []interface{}{arg1, arg2Copy})
|
||||
fake.setStateValidationParameterMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
if fake.SetStateValidationParameterStub != nil {
|
||||
return fake.SetStateValidationParameterStub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.setStateValidationParameterReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -2831,16 +2721,15 @@ func (fake *ChaincodeStub) SplitCompositeKey(arg1 string) (string, []string, err
|
|||
fake.splitCompositeKeyArgsForCall = append(fake.splitCompositeKeyArgsForCall, struct {
|
||||
arg1 string
|
||||
}{arg1})
|
||||
stub := fake.SplitCompositeKeyStub
|
||||
fakeReturns := fake.splitCompositeKeyReturns
|
||||
fake.recordInvocation("SplitCompositeKey", []interface{}{arg1})
|
||||
fake.splitCompositeKeyMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
if fake.SplitCompositeKeyStub != nil {
|
||||
return fake.SplitCompositeKeyStub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2, ret.result3
|
||||
}
|
||||
fakeReturns := fake.splitCompositeKeyReturns
|
||||
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
|
||||
}
|
||||
|
||||
|
|
@ -2957,8 +2846,6 @@ func (fake *ChaincodeStub) Invocations() map[string][][]interface{} {
|
|||
defer fake.getTxTimestampMutex.RUnlock()
|
||||
fake.invokeChaincodeMutex.RLock()
|
||||
defer fake.invokeChaincodeMutex.RUnlock()
|
||||
fake.purgePrivateDataMutex.RLock()
|
||||
defer fake.purgePrivateDataMutex.RUnlock()
|
||||
fake.putPrivateDataMutex.RLock()
|
||||
defer fake.putPrivateDataMutex.RUnlock()
|
||||
fake.putStateMutex.RLock()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package mocks
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hyperledger/fabric-protos-go-apiv2/ledger/queryresult"
|
||||
"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
|
||||
)
|
||||
|
||||
type StateQueryIterator struct {
|
||||
|
|
@ -49,16 +49,15 @@ func (fake *StateQueryIterator) Close() error {
|
|||
ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)]
|
||||
fake.closeArgsForCall = append(fake.closeArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.CloseStub
|
||||
fakeReturns := fake.closeReturns
|
||||
fake.recordInvocation("Close", []interface{}{})
|
||||
fake.closeMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.CloseStub != nil {
|
||||
return fake.CloseStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.closeReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -102,16 +101,15 @@ func (fake *StateQueryIterator) HasNext() bool {
|
|||
ret, specificReturn := fake.hasNextReturnsOnCall[len(fake.hasNextArgsForCall)]
|
||||
fake.hasNextArgsForCall = append(fake.hasNextArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.HasNextStub
|
||||
fakeReturns := fake.hasNextReturns
|
||||
fake.recordInvocation("HasNext", []interface{}{})
|
||||
fake.hasNextMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.HasNextStub != nil {
|
||||
return fake.HasNextStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
fakeReturns := fake.hasNextReturns
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
|
|
@ -155,16 +153,15 @@ func (fake *StateQueryIterator) Next() (*queryresult.KV, error) {
|
|||
ret, specificReturn := fake.nextReturnsOnCall[len(fake.nextArgsForCall)]
|
||||
fake.nextArgsForCall = append(fake.nextArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.NextStub
|
||||
fakeReturns := fake.nextReturns
|
||||
fake.recordInvocation("Next", []interface{}{})
|
||||
fake.nextMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub()
|
||||
if fake.NextStub != nil {
|
||||
return fake.NextStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
fakeReturns := fake.nextReturns
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue