mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-25 02:55:09 +00:00
Address some PR review feedback points - README reorg
Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>
This commit is contained in:
parent
81748831e7
commit
f7a2eb38f8
6 changed files with 179 additions and 224 deletions
|
|
@ -1,160 +1,12 @@
|
||||||
|
|
||||||
## Basic asset transfer
|
## Basic Asset Transfer
|
||||||
|
|
||||||
This project demonstrates the use of the Java SDK, running a basic asset transfer contract using the "chaincode as a service"
|
This sample implements the basic asset transfer scenario, illustrating the use of the Java Contract SDKs to provide a
|
||||||
pattern.
|
smart contract as a service.
|
||||||
|
|
||||||
|
To run this chaincode contract locally on a development network, see:
|
||||||
## Setup
|
|
||||||
|
- [Debugging chaincode as a service](../../test-network-k8s/docs/CHAINCODE_AS_A_SERVICE.md) (Kube test network)
|
||||||
In this sample we will employ the [Kubernetes Test Network](../../test-network-k8s) to illustrate a scenario of
|
- [End-to-end with the test-network](../../test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md#end-to-end-with-the-the-test-network) (Docker compose)
|
||||||
building, running, and debugging chaincode on a development workstation.
|
|
||||||
|
|
||||||
This project is also compatible with the legacy chaincode builder pipeline and the compose based test-network.
|
|
||||||
For additional details, see the [End-to-end with the test-network](../../test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md#end-to-end-with-the-the-test-network)
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
## [Quickstart](../../test-network-k8s#quickstart)
|
|
||||||
|
|
||||||
```
|
|
||||||
export PATH=${PWD}/../../test-network-k8s:$PATH
|
|
||||||
|
|
||||||
network kind
|
|
||||||
```
|
|
||||||
```
|
|
||||||
network up
|
|
||||||
network channel create
|
|
||||||
```
|
|
||||||
```
|
|
||||||
network chaincode deploy asset-transfer-basic basic_1.0 ${PWD}
|
|
||||||
```
|
|
||||||
```
|
|
||||||
network chaincode metadata asset-transfer-basic
|
|
||||||
network chaincode invoke asset-transfer-basic '{"Args":["InitLedger"]}'
|
|
||||||
network chaincode query asset-transfer-basic '{"Args":["ReadAsset","asset1"]}' | jq
|
|
||||||
```
|
|
||||||
|
|
||||||
## Detailed Guide
|
|
||||||
|
|
||||||
```shell
|
|
||||||
network down
|
|
||||||
network up
|
|
||||||
network channel create
|
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Build the chaincode docker image
|
|
||||||
docker build -t fabric-samples/asset-transfer-basic/chaincode-java .
|
|
||||||
|
|
||||||
# Load the docker image directly to the KIND control plane.
|
|
||||||
# (Alternately, build/tag/push the image to a remote container registry, e.g. localhost:5000)
|
|
||||||
kind load docker-image fabric-samples/asset-transfer-basic/chaincode-java
|
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Assemble the chaincode package archive
|
|
||||||
network chaincode package basic_1.0 asset-transfer-basic $PWD/build/asset-transfer.tgz
|
|
||||||
|
|
||||||
# Determine the ID for the chaincode package
|
|
||||||
CORE_CHAINCODE_ID_NAME=$(network chaincode id $PWD/build/asset-transfer.tgz)
|
|
||||||
|
|
||||||
# Launch the chaincode in k8s as Deployment + Service
|
|
||||||
network chaincode launch asset-transfer-basic $CORE_CHAINCODE_ID_NAME fabric-samples/asset-transfer-basic/chaincode-java
|
|
||||||
|
|
||||||
# Complete the chaincode lifecycle
|
|
||||||
network chaincode install $PWD/build/asset-transfer.tgz
|
|
||||||
network chaincode approve asset-transfer-basic $CORE_CHAINCODE_ID_NAME
|
|
||||||
network chaincode commit asset-transfer-basic
|
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# execute the smart contract by name
|
|
||||||
network chaincode metadata asset-transfer-basic
|
|
||||||
network chaincode invoke asset-transfer-basic '{"Args":["InitLedger"]}'
|
|
||||||
network chaincode query asset-transfer-basic '{"Args":["ReadAsset","asset1"]}'
|
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n test-network logs -f deployment/org1peer1-ccaas-asset-transfer-basic
|
|
||||||
```
|
|
||||||
|
|
||||||
## Debugging
|
|
||||||
|
|
||||||
### Build
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./gradlew shadowJar
|
|
||||||
```
|
|
||||||
or
|
|
||||||
```shell
|
|
||||||
docker build -t fabric-samples/asset-transfer-basic/chaincode-java .
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Package
|
|
||||||
|
|
||||||
By instructing the peer to connect to chaincode at the Docker host alias `host.docker.internal`, pods running in
|
|
||||||
Kubernetes will access the local process via a special loopback interface established by KIND.
|
|
||||||
|
|
||||||
Set the "address" attribute in the package connection.json descriptor and assemble the chaincode package:
|
|
||||||
```shell
|
|
||||||
export TEST_NETWORK_CHAINCODE_ADDRESS=host.docker.internal:9999
|
|
||||||
|
|
||||||
network cc package basic_1.0 asset-transfer-debug $PWD/build/asset-transfer-debug.tgz
|
|
||||||
```
|
|
||||||
|
|
||||||
### Launch
|
|
||||||
|
|
||||||
When chaincode is launched locally, it must declare the package ID in the environment as if the process had been managed
|
|
||||||
by the peer's chaincode lifecycle manager. Calculate the package ID and start the chaincode, binding to port 9999
|
|
||||||
on the local system:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
export CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999
|
|
||||||
export CORE_CHAINCODE_ID_NAME=$(network chaincode id $PWD/build/asset-transfer-debug.tgz)
|
|
||||||
|
|
||||||
java -jar build/libs/chaincode.jar
|
|
||||||
```
|
|
||||||
|
|
||||||
Or using the editor/debugger/IDE of your choice, create a launch target for `ContractMain.main()`, specifying the
|
|
||||||
environment as above.
|
|
||||||
|
|
||||||
Or launch the chaincode in a Docker container, binding to port 9999 on the host system:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run \
|
|
||||||
--rm \
|
|
||||||
--name basic_1.0 \
|
|
||||||
-p 9999:9999 \
|
|
||||||
-e CHAINCODE_SERVER_ADDRESS \
|
|
||||||
-e CORE_CHAINCODE_ID_NAME \
|
|
||||||
fabric-samples/asset-transfer-basic/chaincode-java
|
|
||||||
```
|
|
||||||
|
|
||||||
### Approve, Invoke, and Query
|
|
||||||
|
|
||||||
After the contract main has launched, install, approve, commit, and invoke the chaincode:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Complete the chaincode lifecycle
|
|
||||||
network cc activate asset-transfer-debug $PWD/build/asset-transfer-debug.tgz
|
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# execute the smart contract by name
|
|
||||||
network cc metadata asset-transfer-debug
|
|
||||||
network cc invoke asset-transfer-debug '{"Args":["InitLedger"]}'
|
|
||||||
network cc query asset-transfer-debug '{"Args":["ReadAsset","asset1"]}'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tear Down
|
|
||||||
|
|
||||||
```shell
|
|
||||||
network down
|
|
||||||
```
|
|
||||||
or
|
|
||||||
```shell
|
|
||||||
network unkind
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass = 'org.hyperledger.fabric.contract.ContractRouter'
|
mainClass = 'org.hyperledger.fabric.samples.assettransfer.ContractMain'
|
||||||
}
|
}
|
||||||
|
|
||||||
checkstyle {
|
checkstyle {
|
||||||
|
|
|
||||||
|
|
@ -200,73 +200,11 @@ docker push $TEST_NETWORK_CHAINCODE_IMAGE
|
||||||
|
|
||||||
One of the most compelling features of Fabric's _Chaincode-as-a-Service_ pattern is that when the peer connects to a
|
One of the most compelling features of Fabric's _Chaincode-as-a-Service_ pattern is that when the peer connects to a
|
||||||
chaincode URL, it can connect back to a port on the local host. Instead of connecting to a pod running in a
|
chaincode URL, it can connect back to a port on the local host. Instead of connecting to a pod running in a
|
||||||
container within Kubernetes, we can simply connect to a native binary running in a debugger, an IDE, or docker image
|
container within Kubernetes, the chaincode process can be launched locally as a native binary in a debugger, an IDE,
|
||||||
running locally!
|
or a docker image bound to the host network.
|
||||||
|
|
||||||
Using a singular framework, we can employ this method to enable _rapid_ **edit/test/debug cycles** when authoring
|
For additional details, see the [debugging chaincode](CHAINCODE_AS_A_SERVICE.md) guide for running the basic asset
|
||||||
code, **verify** docker images generated by a CI/CD pipeline, and run integration tests on a local Kubernetes.
|
transfer chaincode in an interactive development workflow.
|
||||||
|
|
||||||
For example, we can deploy the basic asset transfer smart contract with a [connection.json](../chaincode/asset-transfer-basic-debug/connection.json)
|
|
||||||
referencing a service bound to the Docker network's IP address for the local host:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"address": "host.docker.internal:9999",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
When the test network opens a TCP socket to the chaincode process, the connection will be made from containers
|
|
||||||
running within Kubernetes to the port opened on the local system. Let's employ this to technique by running a
|
|
||||||
chaincode endpoint in a local Docker container, native binary, or IDE debugger:
|
|
||||||
|
|
||||||
|
|
||||||
0. Edit assetTransfer.go and [Build the Chaincode Image](#build-a-chaincode-docker-image)
|
|
||||||
|
|
||||||
|
|
||||||
1. Bring up the test network with:
|
|
||||||
```shell
|
|
||||||
$ ./network up
|
|
||||||
$ ./network channel create
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Install the debug chaincode archive, using a connection to localhost:9999 :
|
|
||||||
```shell
|
|
||||||
$ export TEST_NETWORK_CHAINCODE_NAME=asset-transfer-basic-debug
|
|
||||||
$ export TEST_NETWORK_CHAINCODE_IMAGE=localhost:5000/asset-transfer-basic
|
|
||||||
|
|
||||||
$ ./network chaincode install
|
|
||||||
Installing chaincode "asset-transfer-basic-debug":
|
|
||||||
✅ - Packaging chaincode folder chaincode/asset-transfer-basic-debug ...
|
|
||||||
✅ - Transferring chaincode archive to org1 ...
|
|
||||||
✅ - Installing chaincode for org org1 ...
|
|
||||||
🏁 - Chaincode is installed with CHAINCODE_ID=basic_1.0:159ed2f227586f40c5804e157919903fda2b861488f35eefb365eb9d85a73da3
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Set the `CHAINCODE_ID` and launch the chaincode binding to localhost:9999:
|
|
||||||
```shell
|
|
||||||
$ export CHAINCODE_ID=basic_1.0:159ed2f227586f40c5804e157919903fda2b861488f35eefb365eb9d85a73da3
|
|
||||||
|
|
||||||
$ docker run \
|
|
||||||
--rm \
|
|
||||||
--name asset-transfer-basic-debug \
|
|
||||||
-e CHAINCODE_ID \
|
|
||||||
-e CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999 \
|
|
||||||
-p 9999:9999 \
|
|
||||||
localhost:5000/asset-transfer-basic
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Activate the chaincode (commit and approve on the peer):
|
|
||||||
```shell
|
|
||||||
$ ./network chaincode activate
|
|
||||||
```
|
|
||||||
|
|
||||||
When the peer communicates with chaincode in this fashion, the network will reach out to the grpc server
|
|
||||||
bound to the localhost:9999, rather than connecting to services locked up behind the wall of Kubernetes
|
|
||||||
networking.
|
|
||||||
|
|
||||||
As an exercise, try using this approach to:
|
|
||||||
|
|
||||||
- introduce some `fmt.Printf` logging output to the chaincode, attaching to a process running locally in an IDE / debugger.
|
|
||||||
- build your local modifications into a docker container, publishing locally to localhost:5000/asset-transfer-basic
|
|
||||||
- test your local modifications by running a chaincode referencing the image hosted in the local container registry.
|
|
||||||
|
|
||||||
|
|
||||||
## Next Steps:
|
## Next Steps:
|
||||||
|
|
|
||||||
161
test-network-k8s/docs/CHAINCODE_AS_A_SERVICE.md
Normal file
161
test-network-k8s/docs/CHAINCODE_AS_A_SERVICE.md
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
# Debugging Chaincode
|
||||||
|
|
||||||
|
In this sample we will employ the [Kubernetes Test Network](../README.md) to illustrate a scenario of
|
||||||
|
building, running, and debugging chaincode on a development workstation.
|
||||||
|
|
||||||
|
While this guide targets the Java [asset-transfer-basic](../../asset-transfer-basic/chaincode-java) sample, the approach
|
||||||
|
may be applied to any sample and chaincode implementation language.
|
||||||
|
|
||||||
|
When debugging chaincode as a service, the chaincode process is launched on the local system, binding to a port
|
||||||
|
on the host's network interface. In this mode the developer has complete flexibility in determining how and where the
|
||||||
|
process runs - it can be launched as a native binary from a CLI, attached to an active debugging session from an IDE,
|
||||||
|
as a Docker container, or even behind a reverse network proxy for diagnosing issues in a remote / cloud-based Fabric
|
||||||
|
network.
|
||||||
|
|
||||||
|
|
||||||
|
## TL/DR
|
||||||
|
|
||||||
|
```
|
||||||
|
export PATH=${PWD}/test-network-k8s:$PATH
|
||||||
|
|
||||||
|
cd asset-transfer-basic/chaincode-java
|
||||||
|
|
||||||
|
network kind
|
||||||
|
```
|
||||||
|
```
|
||||||
|
network up
|
||||||
|
network channel create
|
||||||
|
```
|
||||||
|
```
|
||||||
|
network chaincode deploy asset-transfer-basic basic_1.0 ${PWD}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
network chaincode metadata asset-transfer-basic
|
||||||
|
network chaincode invoke asset-transfer-basic '{"Args":["InitLedger"]}'
|
||||||
|
network chaincode query asset-transfer-basic '{"Args":["ReadAsset","asset1"]}' | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Detailed Guide
|
||||||
|
|
||||||
|
```shell
|
||||||
|
network down
|
||||||
|
network up
|
||||||
|
network channel create
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Build the chaincode docker image
|
||||||
|
docker build -t fabric-samples/asset-transfer-basic/chaincode-java .
|
||||||
|
|
||||||
|
# Load the docker image directly to the KIND control plane.
|
||||||
|
# (Alternately, build/tag/push the image to a remote container registry, e.g. localhost:5000 or ghcr.io)
|
||||||
|
kind load docker-image fabric-samples/asset-transfer-basic/chaincode-java
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Assemble the chaincode package archive
|
||||||
|
network chaincode package basic_1.0 asset-transfer-basic $PWD/build/asset-transfer.tgz
|
||||||
|
|
||||||
|
# Determine the ID for the chaincode package
|
||||||
|
CORE_CHAINCODE_ID_NAME=$(network chaincode id $PWD/build/asset-transfer.tgz)
|
||||||
|
|
||||||
|
# Launch the chaincode in k8s as Deployment + Service
|
||||||
|
network chaincode launch asset-transfer-basic $CORE_CHAINCODE_ID_NAME fabric-samples/asset-transfer-basic/chaincode-java
|
||||||
|
|
||||||
|
# Complete the chaincode lifecycle
|
||||||
|
network chaincode install $PWD/build/asset-transfer.tgz
|
||||||
|
network chaincode approve asset-transfer-basic $CORE_CHAINCODE_ID_NAME
|
||||||
|
network chaincode commit asset-transfer-basic
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# execute the smart contract by name
|
||||||
|
network chaincode metadata asset-transfer-basic
|
||||||
|
network chaincode invoke asset-transfer-basic '{"Args":["InitLedger"]}'
|
||||||
|
network chaincode query asset-transfer-basic '{"Args":["ReadAsset","asset1"]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl -n test-network logs -f deployment/org1peer1-ccaas-asset-transfer-basic
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./gradlew shadowJar
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```shell
|
||||||
|
docker build -t fabric-samples/asset-transfer-basic/chaincode-java .
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Package
|
||||||
|
|
||||||
|
By instructing the peer to connect to chaincode at the Docker host alias `host.docker.internal`, pods running in
|
||||||
|
Kubernetes will access the local process via a special loopback interface established by KIND.
|
||||||
|
|
||||||
|
Set the "address" attribute in the package connection.json descriptor and assemble the chaincode package:
|
||||||
|
```shell
|
||||||
|
export TEST_NETWORK_CHAINCODE_ADDRESS=host.docker.internal:9999
|
||||||
|
|
||||||
|
network cc package basic_1.0 asset-transfer-debug $PWD/build/asset-transfer-debug.tgz
|
||||||
|
```
|
||||||
|
|
||||||
|
### Launch
|
||||||
|
|
||||||
|
When chaincode is launched locally, it must declare the package ID in the environment as if the process had been managed
|
||||||
|
by the peer's chaincode lifecycle manager. Calculate the package ID and start the chaincode, binding to port 9999
|
||||||
|
on the local system:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
export CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999
|
||||||
|
export CORE_CHAINCODE_ID_NAME=$(network chaincode id $PWD/build/asset-transfer-debug.tgz)
|
||||||
|
|
||||||
|
java -jar build/libs/chaincode.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
Or using the editor/debugger/IDE of your choice, create a launch target for `ContractMain.main()`, specifying the
|
||||||
|
environment as above.
|
||||||
|
|
||||||
|
Or launch the chaincode in a Docker container, binding to port 9999 on the host system:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run \
|
||||||
|
--rm \
|
||||||
|
--name basic_1.0 \
|
||||||
|
-p 9999:9999 \
|
||||||
|
-e CHAINCODE_SERVER_ADDRESS \
|
||||||
|
-e CORE_CHAINCODE_ID_NAME \
|
||||||
|
fabric-samples/asset-transfer-basic/chaincode-java
|
||||||
|
```
|
||||||
|
|
||||||
|
### Approve, Invoke, and Query
|
||||||
|
|
||||||
|
After the contract main has launched, install, approve, commit, and invoke the chaincode:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Complete the chaincode lifecycle
|
||||||
|
network cc activate asset-transfer-debug $PWD/build/asset-transfer-debug.tgz
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# execute the smart contract by name
|
||||||
|
network cc metadata asset-transfer-debug
|
||||||
|
network cc invoke asset-transfer-debug '{"Args":["InitLedger"]}'
|
||||||
|
network cc query asset-transfer-debug '{"Args":["ReadAsset","asset1"]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tear Down
|
||||||
|
|
||||||
|
```shell
|
||||||
|
network down
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```shell
|
||||||
|
network unkind
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,5 +41,6 @@ _Chaincode-as-a-Service_ running in a shared Kubernetes namespace.
|
||||||
- [Deploy Orderers and Peers](TEST_NETWORK.md#starting-peers-and-orderers)
|
- [Deploy Orderers and Peers](TEST_NETWORK.md#starting-peers-and-orderers)
|
||||||
- [Working with Channels](CHANNELS.md)
|
- [Working with Channels](CHANNELS.md)
|
||||||
- [Working with Chaincode](CHAINCODE.md)
|
- [Working with Chaincode](CHAINCODE.md)
|
||||||
|
- [Debugging Chaincode](CHAINCODE_AS_A_SERVICE.md)
|
||||||
- [Working with Applications](APPLICATIONS.md)
|
- [Working with Applications](APPLICATIONS.md)
|
||||||
- [High Availability](HIGH_AVAILABILITY.md)
|
- [High Availability](HIGH_AVAILABILITY.md)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ function set_chaincode_image() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Convenience routine to "do everything other than package and launch" a sample CC.
|
# Convenience routine to "do everything other than package and launch" a sample CC.
|
||||||
# This is useful in local debugging scenarios, where
|
# When debugging a chaincode server, the process must be launched prior to completing
|
||||||
|
# the chaincode lifecycle at the peer. This routine provides a route for packaging
|
||||||
|
# and installing the chaincode out of band, and a single target to complete the peer
|
||||||
|
# chaincode lifecycle.
|
||||||
function activate_chaincode() {
|
function activate_chaincode() {
|
||||||
local cc_name=$1
|
local cc_name=$1
|
||||||
local cc_package=$2
|
local cc_package=$2
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue