Address some PR review feedback points - README reorg

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>
This commit is contained in:
Josh Kneubuhl 2022-04-26 09:32:09 -04:00
parent 81748831e7
commit f7a2eb38f8
6 changed files with 179 additions and 224 deletions

View file

@ -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"
pattern.
## Setup
In this sample we will employ the [Kubernetes Test Network](../../test-network-k8s) to illustrate a scenario of
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
```
This sample implements the basic asset transfer scenario, illustrating the use of the Java Contract SDKs to provide a
smart contract as a service.
To run this chaincode contract locally on a development network, see:
- [Debugging chaincode as a service](../../test-network-k8s/docs/CHAINCODE_AS_A_SERVICE.md) (Kube test network)
- [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)

View file

@ -31,7 +31,7 @@ repositories {
}
application {
mainClass = 'org.hyperledger.fabric.contract.ContractRouter'
mainClass = 'org.hyperledger.fabric.samples.assettransfer.ContractMain'
}
checkstyle {

View file

@ -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
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
running locally!
container within Kubernetes, the chaincode process can be launched locally as a native binary in a debugger, an IDE,
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
code, **verify** docker images generated by a CI/CD pipeline, and run integration tests on a local Kubernetes.
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.
For additional details, see the [debugging chaincode](CHAINCODE_AS_A_SERVICE.md) guide for running the basic asset
transfer chaincode in an interactive development workflow.
## Next Steps:

View 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
```

View file

@ -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)
- [Working with Channels](CHANNELS.md)
- [Working with Chaincode](CHAINCODE.md)
- [Debugging Chaincode](CHAINCODE_AS_A_SERVICE.md)
- [Working with Applications](APPLICATIONS.md)
- [High Availability](HIGH_AVAILABILITY.md)

View file

@ -40,7 +40,10 @@ function set_chaincode_image() {
}
# 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() {
local cc_name=$1
local cc_package=$2